hw_reg_set CallZap( call_state *state ) /******************************************/ { hw_reg_set zap; hw_reg_set tmp; zap = state->modify; if( (state->attr & ROUTINE_MODIFY_EXACT) == 0 ) { HW_TurnOn( zap, state->parm.used ); HW_TurnOn( zap, state->return_reg ); zap = FullReg( zap ); tmp = ReturnReg( WD, _NPX( state->attr ) ); HW_TurnOn( zap, tmp ); } return( zap ); }
hw_reg_set PragRegList( void ) /****************************/ { hw_reg_set res, reg; TOKEN close; char buf[ 80 ]; HW_CAsgn( res, HW_EMPTY ); HW_CAsgn( reg, HW_EMPTY ); close = PragRegSet(); if( close != T_NULL ) { PPCTL_ENABLE_MACROS(); NextToken(); *buf = '\0'; for( ; CurToken != close; ) { strcat( buf, Buffer ); if( CurToken != T_BAD_CHAR ) { reg = PragRegName( buf ); HW_TurnOn( res, reg ); *buf = '\0'; } NextToken(); } PPCTL_DISABLE_MACROS(); MustRecog( close ); } return( res ); }
extern void BGProcDecl( cg_sym_handle sym, type_def *tipe ) /******************************************************/ { type_class_def class; name *temp; hw_reg_set reg; class = AddCallBlock( sym, tipe ); SaveTargetModel = TargetModel; if( tipe != TypeNone ) { if( class == XX ) { // Handle structure returns - we need to "eat up" the first // register used for argument passing here, so that it isn't // used for passing actual arguments. NB: Must also bump // parm.offset here so that arguments end up in the right // locations. reg = HW_D4; temp = AllocTemp( WD ); temp->v.usage |= USE_IN_ANOTHER_BLOCK; AddIns( MakeMove( AllocRegName( reg ), temp, WD ) ); HW_TurnOn( CurrProc->state.parm.used, reg ); // TODO: need to do anything here? // HW_CTurnOn( CurrProc->state.parm.used, HW_F16 ); CurrProc->targ.return_points = temp; CurrProc->state.parm.offset += REG_SIZE; } } }
hw_reg_set PragRegList( // GET PRAGMA REGISTER SET void ) { hw_reg_set res; // - resultant set hw_reg_set reg; // - current set TOKEN close_token; // - ending delimiter HW_CAsgn( res, HW_EMPTY ); if( CurToken == T_LEFT_BRACKET ) { close_token = T_RIGHT_BRACKET; } else if( CurToken == T_LEFT_BRACE ) { close_token = T_RIGHT_BRACE; } else { return( res ); } PPCTL_ENABLE_MACROS(); NextToken(); for( ; CurToken != close_token; ) { reg = PragRegName( Buffer, strlen( Buffer ) ); HW_TurnOn( res, reg ); NextToken(); } PPCTL_DISABLE_MACROS(); MustRecog( close_token ); return( res ); }
hw_reg_set MustSaveRegs( void ) /**********************************/ { hw_reg_set save; hw_reg_set tmp; HW_CAsgn( save, HW_FULL ); HW_TurnOff( save, CurrProc->state.modify ); HW_CTurnOff( save, HW_UNUSED ); if( CurrProc->state.attr & ROUTINE_MODIFY_EXACT ) { HW_TurnOff( save, CurrProc->state.return_reg ); } else { tmp = CurrProc->state.parm.used; HW_TurnOn( tmp, CurrProc->state.return_reg ); tmp = FullReg( tmp ); HW_TurnOff( save, tmp ); } tmp = StackReg(); HW_TurnOff( save, tmp ); if( HW_CEqual( CurrProc->state.return_reg, HW_EMPTY ) ) { tmp = ReturnReg( WD, _NPX( CurrProc->state.attr ) ); HW_TurnOff( save, tmp ); } tmp = CurrProc->state.unalterable; HW_TurnOff( tmp, DisplayReg() ); HW_TurnOff( tmp, StackReg() ); HW_TurnOff( save, tmp ); return( save ); }
local void GetSaveInfo( void ) /****************************/ { struct { unsigned f_exact : 1; unsigned f_nomemory : 1; unsigned f_list : 1; } have; have.f_exact = 0; have.f_nomemory = 0; have.f_list = 0; for( ;; ) { if( !have.f_exact && PragRecog( "exact" ) ) { AuxInfo.cclass |= MODIFY_EXACT; have.f_exact = 1; } else if( !have.f_nomemory && PragRecog( "nomemory" ) ) { AuxInfo.cclass |= NO_MEMORY_CHANGED; have.f_nomemory = 1; } else if( !have.f_list && PragRegSet() != T_NULL ) { HW_TurnOn( AuxInfo.save, PragRegList() ); have.f_list = 1; } else { break; } } }
extern hw_reg_set ParmInLineReg( parm_state *state ) { /**********************************************************/ hw_reg_set regs; regs = *state->curr_entry; if( !HW_CEqual( regs, HW_EMPTY ) ) { state->curr_entry++; } regs = InLineParm( regs, state->used ); HW_TurnOn( state->used, regs ); return( regs ); }
static void CopyAuxInfo( void ) /*****************************/ { hw_reg_set default_flt_n_seg; hw_reg_set flt_n_seg; if( CurrEntry == NULL ) { // Redefining a built-in calling convention } else { CurrInfo = (struct aux_info *)CMemAlloc( sizeof( struct aux_info ) ); *CurrInfo = *CurrAlias; } if( AuxInfo.code != NULL ) { CurrInfo->code = AuxInfo.code; } if( AuxInfoFlg.f_near ) { CurrInfo->cclass &= ~FAR; } if( AuxInfoFlg.f_routine_pops ) { CurrInfo->cclass &= ~CALLER_POPS; } if( AuxInfoFlg.f_caller_return ) { CurrInfo->cclass &= ~ROUTINE_RETURN; } if( AuxInfoFlg.f_8087_returns ) { CurrInfo->cclass &= ~NO_8087_RETURNS; } CurrInfo->cclass |= AuxInfo.cclass; CurrInfo->flags |= AuxInfo.flags; if( AuxInfo.objname != NULL ) CurrInfo->objname = AuxInfo.objname; if( AuxInfo.cclass & SPECIAL_RETURN ) CurrInfo->returns = AuxInfo.returns; if( AuxInfo.cclass & SPECIAL_STRUCT_RETURN ) CurrInfo->streturn = AuxInfo.streturn; if( AuxInfo.parms != NULL ) CurrInfo->parms = AuxInfo.parms; if( !HW_CEqual( AuxInfo.save, HW_EMPTY ) ) { HW_CTurnOn( CurrInfo->save, HW_FULL ); if( !( AuxInfo.cclass & MODIFY_EXACT ) && !CompFlags.save_restore_segregs ) { HW_Asgn( default_flt_n_seg, WatcallInfo.save ); HW_CAsgn( flt_n_seg, HW_FLTS ); HW_CTurnOn( flt_n_seg, HW_SEGS ); HW_TurnOff( CurrInfo->save, flt_n_seg ); HW_OnlyOn( default_flt_n_seg, flt_n_seg ); HW_TurnOn( CurrInfo->save, default_flt_n_seg ); } HW_TurnOff( CurrInfo->save, AuxInfo.save ); } }
static void GetSaveInfo( void ) { hw_reg_set modlist; hw_reg_set default_flt_n_seg; hw_reg_set flt_n_seg; struct { unsigned f_exact : 1; unsigned f_nomemory : 1; unsigned f_list : 1; } have; have.f_exact = 0; have.f_nomemory = 0; have.f_list = 0; for( ;; ) { if( !have.f_exact && PragRecog( "exact" ) ) { CurrInfo->cclass |= MODIFY_EXACT; have.f_exact = 1; } else if( !have.f_nomemory && PragRecog( "nomemory" ) ) { CurrInfo->cclass |= NO_MEMORY_CHANGED; have.f_nomemory = 1; } else if( !have.f_list && IS_REGSET( CurToken ) ) { modlist = PragRegList(); have.f_list = 1; } else { break; } } if( have.f_list ) { HW_Asgn( default_flt_n_seg, DefaultInfo.save ); HW_CTurnOn( CurrInfo->save, HW_FULL ); if( !have.f_exact && !CompFlags.save_restore_segregs ) { HW_CAsgn( flt_n_seg, HW_FLTS ); HW_CTurnOn( flt_n_seg, HW_SEGS ); HW_TurnOff( CurrInfo->save, flt_n_seg ); HW_OnlyOn( default_flt_n_seg, flt_n_seg ); HW_TurnOn( CurrInfo->save, default_flt_n_seg ); } HW_TurnOff( CurrInfo->save, modlist ); } }
void BGProcDecl( cg_sym_handle sym, type_def *tipe ) /*****************************************************/ { type_class_def class; name *temp; hw_reg_set reg; class = AddCallBlock( sym, tipe ); SaveTargetModel = TargetModel; if( tipe != TypeNone ) { if( class == XX ) { reg = HW_D3; temp = AllocTemp( WD ); temp->v.usage |= USE_IN_ANOTHER_BLOCK; AddIns( MakeMove( AllocRegName( reg ), temp, WD ) ); HW_TurnOn( CurrProc->state.parm.used, reg ); CurrProc->targ.return_points = temp; } } }
void BGProcDecl( cg_sym_handle sym, type_def *tipe ) /*****************************************************/ { hw_reg_set reg; name *temp; type_class_def type_class; segment_id old_segid; label_handle lbl; SaveTargetModel = TargetModel; type_class = AddCallBlock( sym, tipe ); if( tipe != TypeNone ) { if( type_class == XX ) { if( CurrProc->state.attr & ROUTINE_ALLOCS_RETURN ) { old_segid = SetOP( AskBackSeg() ); lbl = AskForNewLabel(); DataLabel( lbl ); DGUBytes( tipe->length ); CurrProc->targ.return_points = (name *)SAllocMemory( lbl, 0, CG_LBL, TypeClass( tipe ), tipe->length ); SetOP( old_segid ); } else { reg = CurrProc->state.return_reg; if( HW_CEqual( reg, HW_EMPTY ) ) { temp = DoParmDecl( NULL, TypeInteger, HW_EMPTY ); } else { temp = AllocTemp( WD ); temp->v.usage |= USE_IN_ANOTHER_BLOCK; AddIns( MakeMove( AllocRegName( reg ), temp, WD ) ); HW_TurnOn( CurrProc->state.parm.used, reg ); } CurrProc->targ.return_points = temp; } } } if( CurrProc->state.attr & ROUTINE_FARSS ) { TargetModel |= FLOATING_SS; } }
void PragmaAuxInfoInit( int flag_stdatnum ) /*****************************************/ { hw_reg_set full_no_segs; call_class call_type; HW_CAsgn( full_no_segs, HW_FULL ); HW_CTurnOff( full_no_segs, HW_SEGS ); call_type = WatcallInfo.cclass & FAR_CALL; /************************************************* * __fortran calling convention *************************************************/ FortranInfo.objname = AUX_STRALLOC( "^" ); /************************************************* * __cdecl calling convention *************************************************/ CdeclInfo.cclass = call_type | #if _CPU == 8086 LOAD_DS_ON_CALL | #endif //REVERSE_PARMS | CALLER_POPS | //GENERATE_STACK_FRAME | #if _CPU == 8086 NO_FLOAT_REG_RETURNS | #endif NO_STRUCT_REG_RETURNS | ROUTINE_RETURN | //NO_8087_RETURNS | //SPECIAL_RETURN | SPECIAL_STRUCT_RETURN; CdeclInfo.parms = StackParms; CdeclInfo.objname = AUX_STRALLOC( "_*" ); HW_CAsgn( CdeclInfo.returns, HW_EMPTY ); HW_CAsgn( CdeclInfo.streturn, HW_EMPTY ); HW_TurnOn( CdeclInfo.save, full_no_segs ); HW_CTurnOff( CdeclInfo.save, HW_FLTS ); #if _CPU == 386 HW_CAsgn( CdeclInfo.streturn, HW_EAX ); HW_CTurnOff( CdeclInfo.save, HW_EAX ); // HW_CTurnOff( CdeclInfo.save, HW_EBX ); HW_CTurnOff( CdeclInfo.save, HW_ECX ); HW_CTurnOff( CdeclInfo.save, HW_EDX ); #else HW_CAsgn( CdeclInfo.streturn, HW_AX ); HW_CTurnOff( CdeclInfo.save, HW_ABCD ); HW_CTurnOff( CdeclInfo.save, HW_ES ); #endif /************************************************* * __pascal calling convention *************************************************/ PascalInfo.cclass = call_type | REVERSE_PARMS | //CALLER_POPS | //GENERATE_STACK_FRAME | NO_FLOAT_REG_RETURNS | NO_STRUCT_REG_RETURNS | //ROUTINE_RETURN | //NO_8087_RETURNS | //SPECIAL_RETURN | SPECIAL_STRUCT_RETURN; PascalInfo.parms = StackParms; PascalInfo.objname = AUX_STRALLOC( "^" ); HW_CAsgn( PascalInfo.returns, HW_EMPTY ); HW_CAsgn( PascalInfo.streturn, HW_EMPTY ); HW_TurnOn( PascalInfo.save, full_no_segs ); HW_CTurnOff( PascalInfo.save, HW_FLTS ); #if _CPU == 386 HW_CTurnOff( PascalInfo.save, HW_EAX ); HW_CTurnOff( PascalInfo.save, HW_EBX ); HW_CTurnOff( PascalInfo.save, HW_ECX ); HW_CTurnOff( PascalInfo.save, HW_EDX ); #else HW_CTurnOff( PascalInfo.save, HW_ABCD ); HW_CTurnOff( PascalInfo.save, HW_ES ); #endif /************************************************* * __stdcall calling convention *************************************************/ StdcallInfo.cclass = call_type | //REVERSE_PARMS | //CALLER_POPS | //GENERATE_STACK_FRAME | //NO_FLOAT_REG_RETURNS | //NO_STRUCT_REG_RETURNS | //ROUTINE_RETURN | //NO_8087_RETURNS | //SPECIAL_RETURN | SPECIAL_STRUCT_RETURN; StdcallInfo.parms = StackParms; #if _CPU == 386 if( flag_stdatnum ) { StdcallInfo.objname = AUX_STRALLOC( "_*#" ); } else { StdcallInfo.objname = AUX_STRALLOC( "_*" ); } #else flag_stdatnum = flag_stdatnum; StdcallInfo.objname = AUX_STRALLOC( "_*" ); #endif HW_CAsgn( StdcallInfo.returns, HW_EMPTY ); HW_CAsgn( StdcallInfo.streturn, HW_EMPTY ); HW_TurnOn( StdcallInfo.save, full_no_segs ); HW_CTurnOff( StdcallInfo.save, HW_FLTS ); #if _CPU == 386 // HW_CAsgn( StdcallInfo.streturn, HW_EAX ); HW_CTurnOff( StdcallInfo.save, HW_EAX ); // HW_CTurnOff( StdcallInfo.save, HW_EBX ); HW_CTurnOff( StdcallInfo.save, HW_ECX ); HW_CTurnOff( StdcallInfo.save, HW_EDX ); #else HW_CAsgn( StdcallInfo.streturn, HW_AX ); HW_CTurnOff( StdcallInfo.save, HW_ABCD ); HW_CTurnOff( StdcallInfo.save, HW_ES ); #endif /************************************************* * __fastcall calling convention *************************************************/ #if _CPU == 386 FastcallInfo.cclass = call_type | //REVERSE_PARMS | //CALLER_POPS | //GENERATE_STACK_FRAME | //NO_FLOAT_REG_RETURNS | //NO_STRUCT_REG_RETURNS | //ROUTINE_RETURN | //NO_8087_RETURNS | //SPECIAL_RETURN | SPECIAL_STRUCT_RETURN; FastcallInfo.parms = FastcallParms; FastcallInfo.objname = AUX_STRALLOC( "@*#" ); HW_CAsgn( FastcallInfo.returns, HW_EMPTY ); HW_CAsgn( FastcallInfo.streturn, HW_EMPTY ); HW_TurnOn( FastcallInfo.save, full_no_segs ); HW_CTurnOff( FastcallInfo.save, HW_FLTS ); HW_CTurnOff( FastcallInfo.save, HW_EAX ); // HW_CTurnOff( FastcallInfo.save, HW_EBX ); HW_CTurnOff( FastcallInfo.save, HW_ECX ); HW_CTurnOff( FastcallInfo.save, HW_EDX ); #else FastcallInfo.cclass = call_type | PARMS_PREFER_REGS | //REVERSE_PARMS | //CALLER_POPS | //GENERATE_STACK_FRAME | //NO_FLOAT_REG_RETURNS | //NO_STRUCT_REG_RETURNS | //ROUTINE_RETURN | //NO_8087_RETURNS | //SPECIAL_RETURN | SPECIAL_STRUCT_RETURN; FastcallInfo.parms = FastcallParms; FastcallInfo.objname = AUX_STRALLOC( "@*" ); HW_CAsgn( FastcallInfo.returns, HW_EMPTY ); HW_CAsgn( FastcallInfo.streturn, HW_EMPTY ); HW_TurnOn( FastcallInfo.save, full_no_segs ); HW_CTurnOff( FastcallInfo.save, HW_FLTS ); HW_CTurnOff( FastcallInfo.save, HW_ABCD ); HW_CTurnOff( FastcallInfo.save, HW_ES ); #endif /************************************************* * _Optlink calling convention *************************************************/ OptlinkInfo.cclass = call_type | #ifdef PARMS_STACK_RESERVE PARMS_STACK_RESERVE | #endif //REVERSE_PARMS | CALLER_POPS | //GENERATE_STACK_FRAME | //NO_FLOAT_REG_RETURNS | NO_STRUCT_REG_RETURNS | //ROUTINE_RETURN | //NO_8087_RETURNS | //SPECIAL_RETURN | SPECIAL_STRUCT_RETURN; #if _CPU == 386 OptlinkInfo.parms = OptlinkParms; #else OptlinkInfo.parms = StackParms; #endif OptlinkInfo.objname = AUX_STRALLOC( "*" ); HW_CAsgn( OptlinkInfo.returns, HW_EMPTY ); // HW_CAsgn( OptlinkInfo.returns, HW_FLTS ); HW_CAsgn( OptlinkInfo.streturn, HW_EMPTY ); HW_TurnOn( OptlinkInfo.save, full_no_segs ); HW_CTurnOff( OptlinkInfo.save, HW_FLTS ); #if _CPU == 386 HW_CTurnOff( OptlinkInfo.save, HW_EAX ); // HW_CTurnOff( OptlinkInfo.save, HW_EBX ); HW_CTurnOff( OptlinkInfo.save, HW_ECX ); HW_CTurnOff( OptlinkInfo.save, HW_EDX ); #else HW_CTurnOff( OptlinkInfo.save, HW_ABCD ); HW_CTurnOff( OptlinkInfo.save, HW_ES ); #endif /************************************************* * __syscall calling convention *************************************************/ SyscallInfo.cclass = call_type | //REVERSE_PARMS | CALLER_POPS | //GENERATE_STACK_FRAME | //NO_FLOAT_REG_RETURNS | NO_STRUCT_REG_RETURNS | //ROUTINE_RETURN | //NO_8087_RETURNS | //SPECIAL_RETURN | SPECIAL_STRUCT_RETURN; SyscallInfo.parms = StackParms; SyscallInfo.objname = AUX_STRALLOC( "*" ); HW_CAsgn( SyscallInfo.returns, HW_EMPTY ); HW_CAsgn( SyscallInfo.streturn, HW_EMPTY ); HW_TurnOn( SyscallInfo.save, full_no_segs ); HW_CTurnOff( SyscallInfo.save, HW_FLTS ); #if _CPU == 386 HW_CTurnOff( SyscallInfo.save, HW_EAX ); // HW_CTurnOff( SyscallInfo.save, HW_EBX ); HW_CTurnOff( SyscallInfo.save, HW_ECX ); HW_CTurnOff( SyscallInfo.save, HW_EDX ); #else HW_CTurnOff( SyscallInfo.save, HW_ABCD ); HW_CTurnOff( SyscallInfo.save, HW_ES ); #endif #if _CPU == 386 /**************************************************** * OS/2 32-bit->16-bit calling convention ( _Far16 ) ****************************************************/ /* these are internal, and will never be pointed to by * an aux_entry, so we don't have to worry about them */ Far16CdeclInfo = CdeclInfo; Far16CdeclInfo.cclass |= FAR16_CALL; Far16CdeclInfo.parms = StackParms; Far16CdeclInfo.objname = AUX_STRALLOC( CdeclInfo.objname ); // __far16 __cdecl depends on EBX being trashed in __cdecl // but NT 386 __cdecl preserves EBX HW_CTurnOff( Far16CdeclInfo.save, HW_EBX ); Far16PascalInfo = PascalInfo; Far16PascalInfo.cclass |= FAR16_CALL; Far16PascalInfo.parms = StackParms; Far16PascalInfo.objname = AUX_STRALLOC( PascalInfo.objname ); #endif }
static void Far16Parms( cn call ) { /*************************************/ instruction *ins; type_length parm_size; pn parm, next; instruction *call_ins; name *eax; name *ecx; name *esi; label_handle lbl; type_length offset; name *parmlist; call_state *state; rt_class rtindex; call_ins = call->ins; parm_size = 0; state = call->state; for( parm = call->parms; parm != NULL; parm = parm->next ) { parm_size += _RoundUp( parm->name->tipe->length, 2 ); } parmlist = SAllocTemp( XX, parm_size ); parmlist->v.usage |= NEEDS_MEMORY | USE_IN_ANOTHER_BLOCK | USE_ADDRESS; offset = 0; for( parm = call->parms; parm != NULL; parm = parm->next ) { parm->name->u.i.ins->result = STempOffset( parmlist, offset, TypeClass( parm->name->tipe ), parm->name->tipe->length ); offset += _RoundUp( parm->name->tipe->length, 2 ); } for( parm = call->parms; parm != NULL; parm = next ) { next = parm->next; parm->name->format = NF_ADDR; /* so instruction doesn't get freed! */ BGDone( parm->name ); CGFree( parm ); } eax = AllocRegName( HW_EAX ); ecx = AllocRegName( HW_ECX ); esi = AllocRegName( HW_ESI ); HW_TurnOn( state->parm.used, eax->r.reg ); HW_TurnOn( state->parm.used, ecx->r.reg ); HW_TurnOn( state->parm.used, esi->r.reg ); ins = MakeMove( AllocS32Const( parm_size ), ecx, WD ); AddIns( ins ); ins = MakeUnary( OP_LA, parmlist, esi, WD ); AddIns( ins ); if( ins->head.opcode == OP_CALL ) { ins = MakeUnary( OP_LA, call->name->u.n.name, eax, WD ); } else { ins = MakeMove( GenIns( call->name ), eax, WD ); call_ins->head.opcode = OP_CALL; } call_ins->num_operands = 2; AddIns( ins ); if( call_ins->type_class == XX ) { if( state->attr & ROUTINE_ALLOCS_RETURN ) { rtindex = RT_Far16Cdecl; } else { rtindex = RT_Far16Pascal; } } else { rtindex = RT_Far16Func; } lbl = RTLabel( rtindex ); call->name->u.n.name = AllocMemory( lbl, 0, CG_LBL, WD ); call_ins->flags.call_flags |= CALL_FAR16 | CALL_POPS_PARMS; call_ins->operands[CALL_OP_USED] = AllocRegName( state->parm.used ); call_ins->operands[CALL_OP_POPS] = AllocS32Const( 0 ); call_ins->zap = &call_ins->operands[CALL_OP_USED]->r; }
an BGCall( cn call, bool use_return, bool in_line ) /******************************************************/ { instruction *call_ins; call_state *state; name *ret_ptr = NULL; name *result; name *temp; name *reg_name; instruction *ret_ins = NULL; hw_reg_set return_reg; hw_reg_set zap_reg; if( call->name->tipe == TypeProcParm ) { SaveDisplay( OP_PUSH ); } state = call->state; result = BGNewTemp( call->tipe ); call_ins = call->ins; /* If we have a return value that won't fit in a register*/ /* pass a pointer to result as the first parm*/ if( call_ins->type_class == XX ) { if( _RoutineIsFar16( state->attr ) ) { if( state->attr & ROUTINE_ALLOCS_RETURN ) { HW_CAsgn( state->return_reg, HW_EAX ); } else { HW_CAsgn( state->return_reg, HW_EBX ); } } if( ( state->attr & ROUTINE_ALLOCS_RETURN ) == 0 ) { if( HW_CEqual( state->return_reg, HW_EMPTY ) ) { ret_ptr = AllocTemp( WD ); } else { ret_ptr = AllocRegName( state->return_reg ); } ret_ins = MakeUnary( OP_LA, result, ret_ptr, WD ); HW_TurnOn( state->parm.used, state->return_reg ); call_ins->flags.call_flags |= CALL_RETURNS_STRUCT; } } if( _IsTargetModel(FLOATING_DS) && (state->attr&ROUTINE_NEEDS_DS_LOADED) ) { HW_CTurnOn( state->parm.used, HW_DS ); } if( _RoutineIsFar16( state->attr ) ) { #if _TARGET & _TARG_80386 Far16Parms( call ); #endif } else { if( AssgnParms( call, in_line ) ) { if( state->attr & ROUTINE_REMOVES_PARMS ) { call_ins->flags.call_flags |= CALL_POPS_PARMS; } } } if( state->attr & (ROUTINE_MODIFIES_NO_MEMORY | ROUTINE_NEVER_RETURNS) ) { /* a routine that never returns can not write any memory as far as this routine is concerned */ call_ins->flags.call_flags |= CALL_WRITES_NO_MEMORY; } if( state->attr & ROUTINE_READS_NO_MEMORY ) { call_ins->flags.call_flags |= CALL_READS_NO_MEMORY; } if( state->attr & ROUTINE_NEVER_RETURNS ) { call_ins->flags.call_flags |= CALL_ABORTS; } if( _RoutineIsInterrupt( state->attr ) ) { call_ins->flags.call_flags |= CALL_INTERRUPT | CALL_POPS_PARMS; } if( !use_return ) { call_ins->flags.call_flags |= CALL_IGNORES_RETURN; } if( call_ins->type_class == XX ) { reg_name = AllocRegName( state->return_reg ); if( state->attr & ROUTINE_ALLOCS_RETURN ) { call_ins->result = reg_name; AddCall( call_ins, call ); if( use_return ) { temp = AllocTemp( WD ); /* assume near pointer*/ AddIns( MakeMove( reg_name, temp, WD ) ); temp = SAllocIndex( temp, NULL, 0, result->n.type_class, call->tipe->length ); AddIns( MakeMove( temp, result, result->n.type_class ) ); } } else { call_ins->result = result; AddIns( ret_ins ); if( HW_CEqual( state->return_reg, HW_EMPTY ) ) { AddIns( MakeUnary( OP_PUSH, ret_ptr, NULL, WD ) ); state->parm.offset += TypeClassSize[WD]; call_ins->operands[CALL_OP_POPS] = AllocS32Const( call_ins->operands[CALL_OP_POPS]->c.lo.int_value + TypeClassSize[WD] ); if( state->attr & ROUTINE_REMOVES_PARMS ) { call_ins->flags.call_flags |= CALL_POPS_PARMS; } } AddCall( call_ins, call ); } } else { return_reg = state->return_reg; zap_reg = call_ins->zap->reg; HW_CTurnOn( zap_reg, HW_FLTS ); HW_OnlyOn( return_reg, zap_reg ); call_ins->result = AllocRegName( return_reg ); reg_name = AllocRegName( state->return_reg ); AddCall( call_ins, call ); if( use_return ) { ret_ins = MakeMove( reg_name, result, result->n.type_class ); if( HW_COvlap( reg_name->r.reg, HW_FLTS ) ) { ret_ins->stk_entry = 1; ret_ins->stk_exit = 0; } AddIns( ret_ins ); } } if( state->parm.offset != 0 && ( state->attr & ROUTINE_REMOVES_PARMS ) == 0 ) { reg_name = AllocRegName( HW_SP ); AddIns( MakeBinary( OP_ADD, reg_name, AllocS32Const( state->parm.offset ), reg_name, WD ) ); } return( MakeTempAddr( result ) ); }
type_class_def CallState( aux_handle aux, type_def *tipe, call_state *state ) /****************************************************************************/ { call_class cclass; type_class_def type_class; uint i; hw_reg_set parms[10]; hw_reg_set *parm_src; hw_reg_set *parm_dst; hw_reg_set *pregs; hw_reg_set tmp; state->unalterable = FixedRegs(); pregs = FEAuxInfo( aux, SAVE_REGS ); HW_CAsgn( state->modify, HW_FULL ); HW_TurnOff( state->modify, *pregs ); HW_CTurnOff( state->modify, HW_UNUSED ); state->used = state->modify; /* anything not saved is used*/ tmp = state->used; HW_TurnOff( tmp, StackReg() ); HW_CTurnOff( tmp, HW_BP ); // should be able to call routine which modifies BP if( HW_Ovlap( state->unalterable, tmp ) ) { FEMessage( MSG_BAD_SAVE, aux ); } state->attr = ROUTINE_REMOVES_PARMS; cclass = *(call_class *)FEAuxInfo( aux, CALL_CLASS ); if( cclass & INTERRUPT ) { state->attr |= ROUTINE_INTERRUPT; } else if( cclass & FAR_CALL ) { state->attr |= ROUTINE_LONG; } else if( cclass & FAR16_CALL ) { state->attr |= ROUTINE_FAR16; } if( cclass & CALLER_POPS ) { state->attr &= ~ROUTINE_REMOVES_PARMS; } if( cclass & SUICIDAL ) { state->attr |= ROUTINE_NEVER_RETURNS; } if( cclass & ROUTINE_RETURN ) { state->attr |= ROUTINE_ALLOCS_RETURN; } if( cclass & NO_STRUCT_REG_RETURNS ) { state->attr |= ROUTINE_NO_STRUCT_REG_RETURNS; } if( cclass & NO_FLOAT_REG_RETURNS ) { state->attr |= ROUTINE_NO_FLOAT_REG_RETURNS; state->attr |= ROUTINE_NO_8087_RETURNS; } if( cclass & NO_8087_RETURNS ) { state->attr |= ROUTINE_NO_8087_RETURNS; } if( cclass & MODIFY_EXACT ) { state->attr |= ROUTINE_MODIFY_EXACT; } if( cclass & NO_MEMORY_CHANGED ) { state->attr |= ROUTINE_MODIFIES_NO_MEMORY; } if( cclass & NO_MEMORY_READ ) { state->attr |= ROUTINE_READS_NO_MEMORY; } if( cclass & LOAD_DS_ON_ENTRY ) { state->attr |= ROUTINE_LOADS_DS; } if( cclass & LOAD_DS_ON_CALL ) { state->attr |= ROUTINE_NEEDS_DS_LOADED; } if( cclass & PARMS_STACK_RESERVE ) { state->attr |= ROUTINE_STACK_RESERVE; } if( cclass & PARMS_PREFER_REGS ) { state->attr |= ROUTINE_PREFER_REGS; } if( cclass & FARSS ) { state->attr |= ROUTINE_FARSS; } if( state == &CurrProc->state ) { if( cclass & ( GENERATE_STACK_FRAME | PROLOG_HOOKS | EPILOG_HOOKS ) ) { CurrProc->prolog_state |= GENERATE_FAT_PROLOG; state->attr |= ROUTINE_NEEDS_PROLOG; } if( cclass & PROLOG_HOOKS ) { CurrProc->prolog_state |= GENERATE_PROLOG_HOOKS; } if( cclass & EPILOG_HOOKS ) { CurrProc->prolog_state |= GENERATE_EPILOG_HOOKS; } if( cclass & FAT_WINDOWS_PROLOG ) { CurrProc->prolog_state |= GENERATE_FAT_PROLOG; } if( cclass & EMIT_FUNCTION_NAME ) { CurrProc->prolog_state |= GENERATE_FUNCTION_NAME; } if( cclass & THUNK_PROLOG ) { CurrProc->prolog_state |= GENERATE_THUNK_PROLOG; } if( cclass & GROW_STACK ) { CurrProc->prolog_state |= GENERATE_GROW_STACK; } if( cclass & TOUCH_STACK ) { CurrProc->prolog_state |= GENERATE_TOUCH_STACK; } if( cclass & LOAD_RDOSDEV_ON_ENTRY ) { CurrProc->prolog_state |= GENERATE_RDOSDEV_PROLOG; } } type_class = ReturnClass( tipe, state->attr ); i = 0; parm_dst = &parms[0]; for( parm_src = FEAuxInfo( aux, PARM_REGS ); !HW_CEqual( *parm_src, HW_EMPTY ); ++parm_src ) { *parm_dst = *parm_src; if( HW_Ovlap( *parm_dst, state->unalterable ) ) { FEMessage( MSG_BAD_SAVE, aux ); } HW_CTurnOff( *parm_dst, HW_UNUSED ); parm_dst++; i++; } *parm_dst = *parm_src; i++; state->parm.table = CGAlloc( i*sizeof( hw_reg_set ) ); Copy( parms, state->parm.table, i * sizeof( hw_reg_set ) ); HW_CAsgn( state->parm.used, HW_EMPTY ); state->parm.curr_entry = state->parm.table; state->parm.offset = 0; if( tipe == TypeNone ) { HW_CAsgn( state->return_reg, HW_EMPTY ); } else if( type_class == XX ) { if( cclass & SPECIAL_STRUCT_RETURN ) { pregs = FEAuxInfo( aux, STRETURN_REG ); state->return_reg = *pregs; state->attr |= ROUTINE_HAS_SPECIAL_RETURN; } else { state->return_reg = StructReg(); } if( (state->attr & ROUTINE_ALLOCS_RETURN) == 0 ) { tmp = ReturnReg( WD, false ); HW_TurnOn( state->modify, tmp ); } } else { if( cclass & SPECIAL_RETURN ) { pregs = FEAuxInfo( aux, RETURN_REG ); state->return_reg = *pregs; state->attr |= ROUTINE_HAS_SPECIAL_RETURN; } else { state->return_reg = ReturnReg( type_class, _NPX( state->attr ) ); } } UpdateReturn( state, tipe, type_class, aux ); return( type_class ); }
void FlowSave( hw_reg_set *preg ) /*******************************/ { int score; int i, j; int best; int num_blocks; int num_regs; int curr_reg; hw_reg_set *curr_push; reg_flow_info *reg_info; block *save; block *restore; instruction *ins; type_class_def reg_type; HW_CAsgn( flowedRegs, HW_EMPTY ); if( _IsntModel( FLOW_REG_SAVES ) ) return; if( !HaveDominatorInfo ) return; // we can't do this if we have push's which are 'live' at the end of a block // - this flag is set when we see a push being generated for a call in a different // block #if _TARGET & _TARG_INTEL if( CurrProc->targ.never_sp_frame ) return; #endif num_regs = CountRegs( *preg ); if( num_regs == 0 ) return; reg_info = CGAlloc( num_regs * sizeof( reg_flow_info ) ); num_blocks = CountBlocks(); InitBlockArray(); curr_push = PushRegs; for( curr_reg = 0; curr_reg < num_regs; curr_reg++ ) { while( !HW_Ovlap( *curr_push, *preg ) ) curr_push++; HW_Asgn( reg_info[curr_reg].reg, *curr_push ); reg_info[curr_reg].save = NULL; reg_info[curr_reg].restore = NULL; #if _TARGET & _TARG_INTEL if( HW_COvlap( *curr_push, HW_BP ) ) continue; // don't mess with BP - it's magical #endif GetRegUsage( ®_info[curr_reg] ); best = 0; for( i = 0; i < num_blocks; i++ ) { for( j = 0; j < num_blocks; j++ ) { if( PairOk( blockArray[i], blockArray[j], ®_info[0], curr_reg ) ) { // we use the number of blocks dominated by the save block plus // the number of blocks post-dominated by the restore block as a // rough metric for determining how much we like a given (valid) // pair of blocks - the more blocks dominated, the further 'in' // we have pushed the save, which should be good score = CountDomBits( &blockArray[i]->dom.dominator ); score += CountDomBits( &blockArray[j]->dom.post_dominator ); if( score > best ) { best = score; reg_info[curr_reg].save = blockArray[i]; reg_info[curr_reg].restore = blockArray[j]; } } } } // so now we know where we are going to save and restore the register // emit the instructions to do so, and remove reg from the set to push // in the normal prolog sequence save = reg_info[curr_reg].save; restore = reg_info[curr_reg].restore; if( ( save != NULL && save != HeadBlock ) && ( restore != NULL && !_IsBlkAttr( restore, BLK_RETURN ) ) ) { reg_type = WD; #if _TARGET & _TARG_INTEL if( IsSegReg( reg_info[curr_reg].reg ) ) { reg_type = U2; } #endif ins = MakeUnary( OP_PUSH, AllocRegName( reg_info[curr_reg].reg ), NULL, reg_type ); ResetGenEntry( ins ); PrefixIns( save->ins.hd.next, ins ); ins = MakeUnary( OP_POP, NULL, AllocRegName( reg_info[curr_reg].reg ), reg_type ); ins->num_operands = 0; ResetGenEntry( ins ); SuffixIns( restore->ins.hd.prev, ins ); HW_TurnOff( *preg, reg_info[curr_reg].reg ); HW_TurnOn( flowedRegs, reg_info[curr_reg].reg ); FixStackDepth( save, restore ); } curr_push++; } CGFree( reg_info ); }
extern type_class_def CallState( aux_handle aux, type_def *tipe, call_state *state ) /*******************************************************************/ { type_class_def class; uint i; hw_reg_set parms[20]; hw_reg_set *parm_src; hw_reg_set *parm_dst; hw_reg_set *pregs; call_class cclass; call_class *pcclass; risc_byte_seq *code; bool have_aux_code = FALSE; state->unalterable = FixedRegs(); if( FEAttr( AskForLblSym( CurrProc->label ) ) & FE_VARARGS ) { HW_TurnOn( state->unalterable, VarargsHomePtr() ); } // For code bursts only, query the #pragma aux instead of using // hardcoded calling convention. If it ever turns out that we need // to support more than a single calling convention, this will need // to change to work more like x86 if( !AskIfRTLabel( CurrProc->label ) ) { code = FEAuxInfo( aux, CALL_BYTES ); if( code != NULL ) { have_aux_code = TRUE; } } pregs = FEAuxInfo( aux, SAVE_REGS ); HW_CAsgn( state->modify, HW_FULL ); if( have_aux_code ) { HW_TurnOff( state->modify, *pregs ); } else { HW_TurnOff( state->modify, SavedRegs() ); } HW_CTurnOff( state->modify, HW_UNUSED ); state->used = state->modify; /* anything not saved is used */ state->attr = 0; pcclass = FEAuxInfo( aux, CALL_CLASS ); cclass = *pcclass; if( cclass & SETJMP_KLUGE ) { state->attr |= ROUTINE_IS_SETJMP; } if( cclass & SUICIDAL ) { state->attr |= ROUTINE_NEVER_RETURNS; } if( cclass & NO_MEMORY_CHANGED ) { state->attr |= ROUTINE_MODIFIES_NO_MEMORY; } if( cclass & NO_MEMORY_READ ) { state->attr |= ROUTINE_READS_NO_MEMORY; } i = 0; if( have_aux_code ) { parm_src = FEAuxInfo( aux, PARM_REGS ); } else { parm_src = ParmRegs(); } parm_dst = &parms[0]; for( ;; ) { *parm_dst = *parm_src; if( HW_CEqual( *parm_dst, HW_EMPTY ) ) break; if( HW_Ovlap( *parm_dst, state->unalterable ) ) { FEMessage( MSG_BAD_SAVE, aux ); } HW_CTurnOff( *parm_dst, HW_UNUSED ); parm_dst++; parm_src++; i++; } i++; state->parm.table = CGAlloc( i * sizeof( hw_reg_set ) ); Copy( parms, state->parm.table, i * sizeof( hw_reg_set ) ); HW_CAsgn( state->parm.used, HW_EMPTY ); state->parm.curr_entry = state->parm.table; state->parm.offset = 0; class = ReturnClass( tipe, state->attr ); UpdateReturn( state, tipe, class, aux ); return( class ); }
instruction *rMAKECALL( instruction *ins ) /********************************************* Using the table RTInfo[], do all the necessary stuff to turn instruction "ins" into a call to a runtime support routine. Move the parms into registers, and move the return register of the runtime routine into the result. Used for 386 and 370 versions */ { rtn_info *info; label_handle lbl; instruction *left_ins; instruction *new_ins; instruction *last_ins; name *reg_name; hw_reg_set regs; hw_reg_set all_regs; hw_reg_set tmp; rt_class rtindex; if( !_IsConvert( ins ) ) { rtindex = LookupRoutine( ins ); } else { /* look it up again in case we ran out of memory during expansion*/ rtindex = LookupConvertRoutine( ins ); } info = &RTInfo[rtindex]; regs = _ParmReg( info->left ); all_regs = regs; left_ins = MakeMove( ins->operands[0], AllocRegName( regs ), info->operand_class ); ins->operands[0] = left_ins->result; MoveSegOp( ins, left_ins, 0 ); PrefixIns( ins, left_ins ); regs = _ParmReg( info->right ); if( !HW_CEqual( regs, HW_EMPTY ) ) { new_ins = MakeMove( ins->operands[1], AllocRegName( regs ), info->operand_class ); ins->operands[1] = new_ins->result; MoveSegOp( ins, new_ins, 0 ); HW_TurnOn( all_regs, regs ); PrefixIns( ins, new_ins ); } #if _TARGET & _TARG_370 tmp = RAReg(); HW_TurnOn( all_regs, tmp ); tmp = LNReg(); HW_TurnOn( all_regs, tmp ); #elif _TARGET & _TARG_80386 { tmp = ReturnReg( WD, false ); HW_TurnOn( all_regs, tmp ); } #endif reg_name = AllocRegName( all_regs ); lbl = RTLabel( rtindex ); new_ins = NewIns( 3 ); new_ins->head.opcode = OP_CALL; new_ins->type_class = ins->type_class; new_ins->operands[CALL_OP_USED] = reg_name; new_ins->operands[CALL_OP_USED2] = reg_name; new_ins->operands[CALL_OP_ADDR] = AllocMemory( lbl, 0, CG_LBL, ins->type_class ); new_ins->result = NULL; new_ins->num_operands = 2; /* special case for OP_CALL*/ #if _TARGET & _TARG_AXP { HW_CTurnOn( all_regs, HW_FULL ); HW_TurnOff( all_regs, SavedRegs() ); HW_CTurnOff( all_regs, HW_UNUSED ); HW_TurnOn( all_regs, ReturnAddrReg() ); } #endif new_ins->zap = (register_name *)AllocRegName( all_regs ); /* all parm regs could be zapped*/ last_ins = new_ins; if( ins->result == NULL || _OpIsCondition( ins->head.opcode ) ) { /* comparison, still need conditional jumps*/ ins->operands[0] = AllocIntConst( 0 ); ins->operands[1] = AllocIntConst( 1 ); DelSeg( ins ); DoNothing( ins ); /* just conditional jumps for ins*/ PrefixIns( ins, new_ins ); new_ins->ins_flags |= INS_CC_USED; last_ins = ins; } else { regs = _ParmReg( info->result ); tmp = regs; HW_TurnOn( tmp, new_ins->zap->reg ); new_ins->zap = (register_name *)AllocRegName( tmp ); reg_name = AllocRegName( regs ); new_ins->result = reg_name; last_ins = MakeMove( reg_name, ins->result, ins->type_class ); ins->result = last_ins->operands[0]; MoveSegRes( ins, last_ins ); SuffixIns( ins, last_ins ); ReplIns( ins, new_ins ); } FixCallIns( new_ins ); UpdateLive( left_ins, last_ins ); return( left_ins ); }