bldcall.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 910 行 · 第 1/3 页
C
910 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Build a subroutine call.
*
****************************************************************************/
#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "procdef.h"
#include "model.h"
#include "sysmacro.h"
#include "addrname.h"
#include "cgdefs.h"
#include "cgaux.h"
#include "zoiks.h"
#include "offset.h"
#include "feprotos.h"
#include "namelist.h"
#include "bldins.h"
#include "makeaddr.h"
#include "optask.h"
#include "bgcall.h"
extern label_handle AskForSymLabel(pointer,cg_class);
extern instruction *NewIns(int);
extern type_def *QParmType(sym_handle,sym_handle,type_def*);
extern instruction *MakeMove(name*,name*,type_class_def);
extern instruction *MakeUnary(opcode_defs,name*,name*,type_class_def);
extern instruction *MakeConvert(name*,name*,type_class_def,type_class_def);
extern instruction *MakeNop(void);
extern hw_reg_set ParmReg(type_class_def,type_length,type_length,call_state*);
extern hw_reg_set CallZap(call_state*);
extern type_length ParmMem(type_length,type_length,call_state*);
extern hw_reg_set ActualParmReg(hw_reg_set);
extern type_class_def CallState(aux_handle,type_def*,call_state*);
extern hw_reg_set ParmInLineReg(parm_state*);
extern void AddIns(instruction*);
extern bool CvtOk(type_class_def,type_class_def);
extern void CGFree(pointer);
extern type_length PushSize(type_length);
extern type_class_def ReturnClass(type_def*,call_attributes);
extern type_class_def InitCallState(type_def*);
extern type_class_def TypeClass(type_def*);
extern void DbgParmLoc(name_def*, sym_handle);
extern void DbgRetLoc(void);
extern void GenBlock(int,int);
extern void Generate(bool);
extern void PGBlip(char*);
extern void EnLink(label_handle,bool);
extern void UpdateReturn(call_state*,type_def*,type_class_def,aux_handle);
extern void FPPushParms(pn,call_state*);
extern void NewProc(int);
extern name *StReturn(an,type_def*,instruction**);
extern hw_reg_set StackReg(void);
extern name *SAllocIndex(name*,name*,type_length,type_class_def,type_length);
extern name *ScaleIndex(name*,name*,type_length,type_class_def,type_length,int,i_flags);
extern instruction *PushOneParm(instruction*,name*,type_class_def,type_length,call_state*);
extern bool IsVolatile(name*);
extern void TNZapParms(void);
extern name *AllocS32Const(signed_32);
extern void FPNotStack(name*);
extern void FreeIns(instruction*);
extern void PushInSameBlock(instruction*);
#if _TARGET & ( _TARG_80386 | _TARG_IAPX86 )
extern void TellObjVirtFuncRef(void *);
#endif
extern void TRAddParm(instruction*,instruction*);
extern void TRDeclareParm(instruction*);
extern an InsName(instruction*,type_def*);
extern type_def *ClassType(type_class_def);
extern bool SegIsCS( name * );
extern pointer FindAuxInfo( name *, aux_class );
extern type_length ParmAlignment( type_def * );
extern void SuffixIns( instruction *, instruction * );
extern type_def *TypeInteger;
extern type_def *TypeProcParm;
extern type_def *TypeNone;
extern proc_def *CurrProc;
extern block *CurrBlock;
extern an AddrList;
extern type_length MaxStack;
extern name *DummyIndex;
extern bool BlipsOn;
extern type_class_def AddCallBlock( sym_handle sym, type_def *tipe ) {
/***********************************************************************
create the initial basic block for routine "sym", and call some
other initialization routines.
*/
type_class_def class;
if( BlipsOn ) {
PGBlip( FEName( sym ) );
}
NewProc( FELexLevel( sym ) );
EnLink( AskForSymLabel( sym, CG_FE ), FALSE );
CurrProc->label = CurrBlock->label;
CurrBlock->class |= BIG_LABEL;
class = InitCallState( tipe );
AddIns( MakeNop() );
return( class );
}
extern void FreeCallNode( cn call )
/**************************************
free up a call node
*/
{
BGDone( call->name );
CGFree( call->state->parm.table );
_Free( call->state, sizeof( call_state ) );
_Free( call, sizeof( call_node ) );
}
extern cn BGInitCall(an node,type_def *tipe,aux_handle aux) {
/******************************************************************
initialize a call node for a call to routine "node", with type
"tipe" and aux handle "aux". This also allocates the instruction
to hold the call and parially initializes it.
*/
cn new;
type_class_def class;
name *mem;
#if _TARGET & ( _TARG_80386 | _TARG_IAPX86 )
void *cookie;
#endif
if( tipe->refno == T_DEFAULT ) {
tipe = TypeInteger;
}
_Alloc( new, sizeof( call_node ) );
_Alloc( new->state, sizeof( call_state ) );
new->name = node;
new->tipe = tipe;
new->parms = NULL;
new->ins = NewIns( 3 );
if( node->format == NF_ADDR && node->class == CL_ADDR_GLOBAL ) {
new->ins->head.opcode = OP_CALL;
class = CallState( aux, tipe, new->state );
mem = node->u.name;
mem = (name *) SAllocMemory( mem->v.symbol, mem->v.offset, mem->m.memory_type,
mem->n.name_class, mem->n.size );
node->u.name = mem;
} else {
new->ins->head.opcode = OP_CALL_INDIRECT;
class = CallState( aux, tipe, new->state );
#if _TARGET & ( _TARG_80386 | _TARG_IAPX86 )
cookie = FEAuxInfo( aux, VIRT_FUNC_REFERENCE );
if( cookie != NULL ) TellObjVirtFuncRef( cookie );
#elif _TARGET & _TARG_PPC
CurrProc->targ.toc_clobbered = TRUE;
#endif
}
new->ins->type_class = class;
return( new );
}
extern void BGAddParm( cn call, an parm ) {
/**********************************************
link a parm into the list of parms for a call node
*/
pn new;
_Alloc( new, sizeof( parm_node ) );
new->name = AddrToIns( parm );
new->name->flags |= ADDR_OK_ACROSS_BLOCKS; /* always taken care of by BGCall*/
new->next = call->parms;
call->parms = new;
}
extern void BGAutoDecl( sym_handle sym, type_def *tipe ) {
/*************************************************************
declare an automatic variable with name "sym" and type "tipe". This
just creates the appropriate back end symbol table entry. (eg: N_TEMP)
*/
BGDone( MakeAddrName( CG_FE, sym, tipe ) );
}
static void LinkParmIns( instruction *parm_def, instruction *ins ) {
/**********************************************************************/
ins->operands[ 2 ] = (name *)parm_def; /* link them together*/
parm_def->operands[ 2 ] = (name *)ins;
ins->ins_flags |= INS_PARAMETER;
parm_def->ins_flags |= INS_PARAMETER;
}
static instruction *DoParmDef( name *result, type_class_def class ) {
/********************************************************************/
instruction *parm_def;
parm_def = NewIns( 0 );
parm_def->head.opcode = OP_PARM_DEF;
parm_def->type_class = class;
parm_def->result = result;
AddIns( parm_def );
return( parm_def );
}
#if _TARGET & _TARG_RISC
#if _TARGET & _TARG_AXP
#define BASE_TYPE U8
#define BASE_SIZE 8
#define BASE_ALIGNMENT 8
#else
#define BASE_TYPE U4
#define BASE_SIZE 4
#define BASE_ALIGNMENT 4
#endif
static name *DoAlphaParmDecl( hw_reg_set reg, sym_handle sym, type_def *tipe, name *t2 ) {
/*********************************************************************************************
N.B.: This was too weird to be incorporated in routine below.
If we have a structure being passed by value on the Alpha, we start
stuffing 8-byte chunks of data into any available parm registers, and
put the remainder on the stack once those run out. In order to make
this mess into an actual temp of the correct type, we create something
which looks like:
PARMDEF => Ra
MOV` Ra => t2
PARMDEF => Rb
MOV Rb => t2+8
...
PARMDEF => t1
MOV XX t1 => t2+n
which give us a real temp in t2, when all is said and done.
*/
name *t1;
name *reg_name;
type_length offset;
instruction *ins;
instruction *parm_def;
type_length len;
sym = sym;
offset = 0;
len = _RoundUp( tipe->length, BASE_SIZE );
t2->n.size = len;
while( 1 ) {
if( HW_CEqual( reg, HW_EMPTY ) ) {
// put the rest of the structure on the stack
t1 = AllocTemp( XX );
t1->v.usage |= USE_IN_ANOTHER_BLOCK|NEEDS_MEMORY|HAS_MEMORY|USE_MEMORY;
t1->n.size = len - offset;
t1->t.temp_flags |= STACK_PARM;
t1->t.location = ParmMem( t1->n.size, BASE_ALIGNMENT, &CurrProc->state );
parm_def = DoParmDef( t1, XX );
ins = MakeMove( t1, STempOffset( t2, offset, XX, t1->n.size ), XX );
LinkParmIns( parm_def, ins );
AddIns( ins );
offset += t1->n.size;
} else {
reg_name = AllocRegName( reg );
parm_def = DoParmDef( reg_name, BASE_TYPE );
ins = MakeMove( reg_name, STempOffset( t2, offset, BASE_TYPE, BASE_SIZE ), BASE_TYPE );
LinkParmIns( parm_def, ins );
AddIns( ins );
offset += BASE_SIZE;
}
if( offset >= len ) break;
reg = ParmReg( BASE_TYPE, BASE_SIZE, BASE_ALIGNMENT, &CurrProc->state );
}
return( t2 );
}
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?