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 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 ); }