static name *GetNTTLSDataRef( instruction *ins, name *op, type_class_def tipe ) /********************************************************************************** Emit instructions to load allow a reference to op (a piece of TLS data) and return the resulting index name. */ { name *tls_index; name *tls_array; name *t1; name *t2; name *t3; name *temp_index; name *result_index; instruction *new_ins; tls_index = RTMemRef( RT_TLS_INDEX ); tls_array = RTMemRef( RT_TLS_ARRAY ); t1 = AllocTemp( WD ); t2 = AllocTemp( WD ); t3 = AllocTemp( WD ); new_ins = MakeMove( tls_array, t1, WD ); AddSegOverride( new_ins, HW_FS ); PrefixIns( ins, new_ins ); new_ins = MakeMove( tls_index, t2, WD ); PrefixIns( ins, new_ins ); new_ins = MakeBinary( OP_MUL, t2, AllocS32Const( 4 ), t2, WD ); PrefixIns( ins, new_ins ); new_ins = MakeBinary( OP_ADD, t1, t2, t1, WD ); PrefixIns( ins, new_ins ); temp_index = AllocIndex( t1, NULL, 0, WD ); new_ins = MakeMove( temp_index, t3, WD ); PrefixIns( ins, new_ins ); result_index = ScaleIndex( t3, op, op->v.offset, tipe, TypeClassSize[ tipe ], 0, 0 ); return( result_index ); }
static instruction *PromoteOperand( instruction *ins ) { /***********************************************************/ name *temp; instruction *new_ins; if( _IsFloating( ins->type_class ) ) { if( ins->type_class == FS ) { temp = AllocTemp( FD ); new_ins = MakeConvert( ins->operands[0], temp, ins->type_class, FD ); ins->operands[0] = temp; PrefixIns( ins, new_ins ); UpdateLive( new_ins, ins ); return( new_ins ); } } else { if( ins->type_class < U8 ) { temp = AllocTemp( U8 ); new_ins = MakeConvert( ins->operands[0], temp, ins->type_class, U8 ); ins->operands[0] = temp; PrefixIns( ins, new_ins ); UpdateLive( new_ins, ins ); return( new_ins ); } } return( NULL ); }
static void CheckOp( name **offsets, instruction *ins, name **pop ) { /************************************************************************ used by FixFarLocalRefs to change one far local reference to an index, using the appropriate multiple of 4K constant to get at the temporary. The constant values are adjusted after the prolog is generated. */ name *op; name *base; name *temp; unsigned_32 place; int i; instruction *new_ins; op = *pop; if( op->n.class == N_INDEXED ) { temp = op->i.index; if( temp->n.class != N_TEMP ) return; if( !( temp->t.temp_flags & FAR_LOCAL ) ) return; new_ins = MakeMove( temp, AllocTemp( temp->n.name_class ), temp->n.name_class ); *pop = ScaleIndex( new_ins->result, op->i.base, op->i.constant, op->n.class, op->n.size, op->i.scale, op->i.index_flags ); PrefixIns( ins, new_ins ); CheckOp( offsets, new_ins, &new_ins->operands[ 0 ] ); } if( op->n.class != N_TEMP ) return; if( !( op->t.temp_flags & FAR_LOCAL ) ) return; base = DeAlias( op ); place = base->t.location + ( op->v.offset - base->v.offset ); i = place/_4K; if( offsets[ i ] == NULL ) { /*set the symbol field in the AddrConst to non-NULL for score-boarder*/ new_ins = MakeMove( AllocAddrConst( (name *)&CurrProc, i, CONS_OFFSET, WD ), AllocTemp( WD ), WD ); offsets[ i ] = new_ins->result; PrefixIns( HeadBlock->ins.hd.next, new_ins ); } temp = AllocTemp( WD ), new_ins = MakeMove( offsets[ i ], temp, WD ); PrefixIns( ins, new_ins ); new_ins = MakeBinary( OP_ADD, temp, AllocRegName( DisplayReg() ), temp, WD); PrefixIns( ins, new_ins ); *pop = ScaleIndex( temp, op, place%_4K, op->n.name_class, op->n.size, 0, X_FAKE_BASE ); }
extern instruction *NeedIndex( instruction *ins ) { /******************************************************* Mark conflicts for any name used in instruction as as segment as NEEDS_SEGMENT, or split out the segment if it is marked as NEEDS_SEGMENT_SPLIT (move the segment operand to a temp and use the temp as the segment override). Also, if any index conflicts are marked as NEEDS_INDEX_SPLIT, split them out into a temp as well. */ name *temp; name *index; conflict_node *conf; name *name; if( ins->num_operands > NumOperands( ins ) ) { name = ins->operands[ins->num_operands - 1]; conf = NameConflict( ins, name ); if( conf != NULL && _Isnt( conf, CST_NEEDS_SEGMENT_SPLIT ) ) { _SetTrue( conf, CST_NEEDS_SEGMENT ); MarkSegment( ins, name ); } else if( name->n.class != N_REGISTER ) { if( conf != NULL ) { _SetFalse( conf, CST_NEEDS_SEGMENT ); _SetTrue( conf, CST_WAS_SEGMENT ); } temp = AllocTemp( U2 ); ins->operands[ins->num_operands - 1] = temp; PrefixIns( ins, MakeMove( name, temp, U2 ) ); MarkSegment( ins, temp ); _SetTrue( NameConflict( ins, temp ), CST_SEGMENT_SPLIT ); ins = ins->head.prev; } }
/* 370 */ instruction *rUSEREGISTER( instruction *ins ) /************************************************/ { instruction *new_ins; instruction *ins2; name *name1; name1 = ins->operands[0]; if( CanUseOp1( ins, name1 ) ) { new_ins = MakeMove( name1, ins->result, ins->type_class ); ins->result = name1; MoveSegRes( ins, new_ins ); SuffixIns( ins, new_ins ); new_ins = ins; } else { name1 = AllocTemp( ins->type_class ); new_ins = MakeMove( ins->operands[0], name1, ins->type_class ); CheckCC( ins, new_ins ); ins->operands[0] = name1; MoveSegOp( ins, new_ins, 0 ); PrefixIns( ins, new_ins ); ins2 = MakeMove( name1, ins->result, ins->type_class ); ins->result = name1; MoveSegRes( ins, ins2 ); SuffixIns( ins, ins2 ); MarkPossible( ins, name1, ResultPossible( ins ) ); ins->u.gen_table = NULL; GiveRegister( NameConflict( ins, name1 ), true ); } return( new_ins ); }
static name *GetGenericTLSDataRef( instruction *ins, name *op, type_class_def tipe ) /**************************************************************************************/ { name *tls; name *result_index; name *temp; instruction *new_ins; tls = CurrProc->targ.tls_index; if( tls == NULL ) { tls = AllocTemp( WD ); CurrProc->targ.tls_index = tls; if( !BlockByBlock ) { /* 2007-06-28 RomanT * Grrr... DropCall() inserts new ins _before_ old one, screwing * startup sequence. So keep call in first block, but make it * before next instruction of last one (== after last one). */ DropCall( HeadBlock->ins.hd.prev->head.next, tls ); } } if( BlockByBlock ) { DropCall( ins, tls ); } temp = AllocTemp( WD ); new_ins = MakeMove( tls, temp, WD ); PrefixIns( ins, new_ins ); result_index = ScaleIndex( temp, op, op->v.offset, tipe, TypeClassSize[ tipe ], 0, 0 ); return( result_index ); }
extern instruction *rSPLITMOVE( instruction *ins ) { /******************************************************/ instruction *new_ins; instruction *ins2; name *temp; CnvOpToInt( ins, 0 ); if( IndexOverlaps( ins, 0 ) ) { temp = AllocTemp( LONG_WORD ); new_ins = MakeMove( LowPart( ins->operands[ 0 ], WORD ), LowPart( temp, WORD ), WORD ); ins2 = MakeMove( HighPart( ins->operands[ 0 ], WORD ), HighPart( temp, WORD ), WORD ); DupSegOp( ins, new_ins, 0 ); DupSegOp( ins, ins2, 0 ); ins->operands[ 0 ] = temp; PrefixIns( ins, new_ins ); PrefixIns( ins, ins2 ); ins2 = MakeMove( LowPart( temp, WORD ), LowPart( ins->result, WORD ), WORD ); DupSegRes( ins, ins2 ); PrefixIns( ins, ins2 ); ins2 = MakeMove( HighPart( temp, WORD ), HighPart( ins->result, WORD ), WORD ); ReplIns( ins, ins2 ); } else { HalfType( ins ); new_ins = MakeMove( LowPart( ins->operands[ 0 ], ins->type_class ), LowPart( ins->result, ins->type_class ), ins->type_class ); DupSeg( ins, new_ins ); ins->operands[ 0 ] = HighPart( ins->operands[ 0 ], ins->type_class ); ins->result = HighPart( ins->result, ins->type_class ); if( new_ins->result->n.class == N_REGISTER && ins->operands[ 0 ]->n.class == N_REGISTER && HW_Ovlap( new_ins->result->r.reg, ins->operands[ 0 ]->r.reg ) ) { SuffixIns( ins, new_ins ); new_ins = ins; } else { PrefixIns( ins, new_ins ); } }
instruction *rCLRHI_BW( instruction *ins ) /*********************************************/ { instruction *new_ins; instruction *ins2; name *name1; type_class_def half_type_class; half_type_class = HalfClass[ins->type_class]; name1 = AllocTemp( ins->type_class ); new_ins = MakeMove( ins->operands[0], LowPart( name1, half_type_class ), half_type_class ); ins->operands[0] = name1; MoveSegOp( ins, new_ins, 0 ); PrefixIns( ins, new_ins ); ins2 = MoveConst( 0, HighPart( name1, half_type_class ), half_type_class ); PrefixIns( ins, ins2 ); ins->head.opcode = OP_MOV; ins->table = NULL; ins->u.gen_table = NULL; return( new_ins ); }
static void DropCall( instruction *ins, name *temp ) /******************************************************/ { name *eax_name; name *null_name; instruction *new_ins; null_name = AllocRegName( HW_EMPTY ); eax_name = AllocRegName( HW_EAX ); new_ins = NewIns( 3 ); new_ins->head.opcode = OP_CALL; new_ins->type_class = WD; new_ins->operands[ CALL_OP_USED ] = null_name; new_ins->operands[ CALL_OP_USED2 ] = null_name; new_ins->operands[ CALL_OP_ADDR ]= RTMemRef( RT_TLS_REGION ); new_ins->result = eax_name; new_ins->zap = &eax_name->r; new_ins->num_operands = 2; /* special case for OP_CALL*/ PrefixIns( ins, new_ins ); new_ins = MakeMove( eax_name, temp, WD ); PrefixIns( ins, new_ins ); }
instruction *rMOVOP2TEMP( instruction *ins ) /***********************************************/ { instruction *new_ins; name *name1; name1 = AllocTemp( ins->type_class ); new_ins = MakeMove( ins->operands[1], name1, ins->type_class ); ins->operands[1] = name1; MoveSegOp( ins, new_ins, 0 ); PrefixIns( ins, new_ins ); return( new_ins ); }
instruction *rMOVOP1TEMP( instruction *ins ) /**********************************************/ { instruction *new_ins; type_class_def type_class; name *name; type_class = _OpClass( ins ); name = AllocTemp( type_class ); new_ins = MakeMove( ins->operands[0], name, type_class ); ins->operands[0] = name; MoveSegOp( ins, new_ins, 0 ); PrefixIns( ins, new_ins ); return( new_ins ); }
instruction *rOP2REG( instruction *ins ) /*******************************************/ { instruction *new_ins; name *name1; type_class_def type_class; type_class = _OpClass( ins ); name1 = AllocTemp( type_class ); new_ins = MakeMove( ins->operands[1], name1, type_class ); ins->operands[1] = name1; MoveSegOp( ins, new_ins, 0 ); PrefixIns( ins, new_ins ); MarkPossible( ins, name1, Op1Possible( ins ) ); ins->u.gen_table = NULL; GiveRegister( NameConflict( ins, name1 ), true ); return( new_ins ); }
instruction *rOP1RESREG( instruction *ins ) /**********************************************/ { instruction *new_ins; instruction *ins2; name *name1; name *name2; name1 = AllocRegName( Op1Reg( ins ) ); new_ins = MakeMove( ins->operands[0], name1, _OpClass( ins ) ); ins->operands[0] = name1; MoveSegOp( ins, new_ins, 0 ); PrefixIns( ins, new_ins ); name2 = AllocRegName( ResultReg( ins ) ); ins2 = MakeMove( name2, ins->result, ins->type_class ); ins->result = name2; MoveSegRes( ins, ins2 ); SuffixIns( ins, ins2 ); return( new_ins ); }
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 ); }
static void ExpandTlsOp( instruction *ins, name **pop ) /********************************************************** If *pop is a ref to a piece of thread-local data, replace it by a ref to an index [t1] and prepend the magic sequence to get the address of a piece of tls data to the instruction. Here is the sequence to access variable foo: mov fs:__tls_array -> t1 mov __tls_index -> t2 mov t2 * 4 -> t2 add t1, t2 -> t1 mov [ t1 ] -> t3 mov foo[ t3 ] -> result */ { fe_attr attr; name *op; name *temp; name *tls_data; name *index; name *base; instruction *new_ins; op = *pop; switch( op->n.class ) { case N_MEMORY: if( op->m.memory_type == CG_FE ) { attr = FEAttr( op->v.symbol ); if( ( attr & FE_THREAD_DATA ) != 0 ) { *pop = GetTLSDataRef( ins, op, _OpClass(ins) ); } } break; case N_INDEXED: // gotta check for the base being one of these stupid TLS things if( op->i.base != NULL && ( op->i.index_flags & X_FAKE_BASE ) == 0 ) { base = op->i.base; if( base->n.class != N_MEMORY || base->m.memory_type != CG_FE ) break; attr = FEAttr( base->v.symbol ); if( ( attr & FE_THREAD_DATA ) == 0 ) break; tls_data = GetTLSDataRef( ins, base, _OpClass(ins) ); temp = AllocTemp( WD ); new_ins = MakeUnary( OP_LA, tls_data, temp, WD ); PrefixIns( ins, new_ins ); index = op->i.index; if( op->i.scale != 0 ) { const signed_32 values[] = { 1, 2, 4, 8, 16 }; if( op->i.scale > 4 ) _Zoiks( ZOIKS_134 ); index = AllocTemp( WD ); new_ins = MakeBinary( OP_MUL, op->i.index, AllocS32Const( values[ op->i.scale ] ), index, WD ); PrefixIns( ins, new_ins ); } new_ins = MakeBinary( OP_ADD, temp, index, temp, WD ); PrefixIns( ins, new_ins ); *pop = ScaleIndex( temp, NULL, 0, _OpClass(ins), TypeClassSize[ _OpClass(ins) ], 0, 0 ); } break; }
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 ); }
extern instruction *rSPLITOP( instruction *ins ) { /****************************************************/ instruction *new_ins; instruction *ins2; name *temp; if( IndexOverlaps( ins, 0 ) || IndexOverlaps( ins, 1 ) ) { temp = AllocTemp( LONG_WORD ); HalfType( ins ); new_ins = MakeBinary( ins->head.opcode, LowPart( ins->operands[ 0 ], WORD ), LowPart( ins->operands[ 1 ], WORD ), LowPart( temp, WORD ), WORD ); ins2 = MakeBinary( ins->head.opcode, HighPart( ins->operands[ 0 ], WORD ), HighPart( ins->operands[ 1 ], WORD ), HighPart( temp, WORD ), WORD ); if( ins->head.opcode == OP_ADD ) { ins2->head.opcode = OP_EXT_ADD; } else if( ins->head.opcode == OP_SUB ) { ins2->head.opcode = OP_EXT_SUB; } ins2->table = CodeTable( ins2 ); new_ins->table = ins2->table; DupSegOp( ins, new_ins, 0 ); DupSegOp( ins, ins2, 0 ); DupSegOp( ins, new_ins, 1 ); DupSegOp( ins, ins2, 1 ); ins->operands[ 0 ] = temp; ins->operands[ 1 ] = temp; PrefixIns( ins, new_ins ); PrefixIns( ins, ins2 ); ins2 = MakeMove( LowPart( temp, WORD ), LowPart( ins->result, WORD ), WORD ); DupSegRes( ins, ins2 ); PrefixIns( ins, ins2 ); ins2 = MakeMove( HighPart( temp, WORD ), HighPart( ins->result, WORD ), WORD ); DupSegRes( ins, ins2 ); ReplIns( ins, ins2 ); } else { HalfType( ins ); new_ins = MakeBinary( ins->head.opcode, LowPart( ins->operands[ 0 ], ins->type_class ), LowPart( ins->operands[ 1 ], ins->type_class ), LowPart( ins->result, ins->type_class ), ins->type_class ); DupSeg( ins, new_ins ); ins->operands[ 0 ] = HighPart( ins->operands[ 0 ], ins->type_class ); ins->operands[ 1 ] = HighPart( ins->operands[ 1 ], ins->type_class ); ins->result = HighPart( ins->result, ins->type_class ); if( ins->head.opcode == OP_ADD ) { ins->head.opcode = OP_EXT_ADD; } else if( ins->head.opcode == OP_SUB ) { ins->head.opcode = OP_EXT_SUB; } /* Assign fake reduce table (from OP_EXT) to new_ins; default reduce table can generate INC and DEC which'll not set condition codes */ ins->table = CodeTable( ins ); new_ins->table = ins->table; PrefixIns( ins, new_ins ); } new_ins->ins_flags |= INS_CC_USED; return( new_ins ); }