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 ); }
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 ); }
name *StReturn( an retval, type_def *tipe, instruction **pins ) /****************************************************************/ { name *retp; name *ptr; name *off; name *seg; hw_reg_set reg; if( CurrProc->state.attr & ROUTINE_ALLOCS_RETURN ) { retp = CurrProc->targ.return_points; AddIns( MakeUnary( OP_LA, retp, AllocRegName( CurrProc->state.return_reg ), WD ) ); *pins = NULL; } else { if( _IsTargetModel( FLOATING_SS ) || _IsTargetModel( FLOATING_DS ) ) { ptr = AllocTemp( CP ); off = OffsetPart( ptr ); seg = SegmentPart( ptr ); AddIns( MakeMove( AllocRegName( HW_SS ), seg, U2 ) ); } else { ptr = AllocTemp( WD ); off = ptr; } AddIns( MakeMove( CurrProc->targ.return_points, off, WD ) ); retp = SAllocIndex( ptr, NULL, 0, TypeClass( retval->tipe ), tipe->length ); reg = ReturnReg( WD, false ); *pins = MakeMove( CurrProc->targ.return_points, AllocRegName( reg ), WD ); CurrProc->state.return_reg = reg; } return( retp ); }
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 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; } } }
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 ); }
name *BGNewTemp( type_def *tipe ) /**************************************/ { name *temp; temp = AllocTemp( TypeClass( tipe ) ); if( temp->n.size == 0 ) { temp->n.size = tipe->length; } return( temp ); }
extern name *MakeDisplay( name *op, int level ) /*************************************************/ { name *temp; name *reg; reg = AllocRegName( DisplayReg() ); temp = AllocTemp( U2 ); AddIns( MakeMove( DisplayField( level ), temp, reg->n.name_class ) ); op = AllocIndex( temp, NULL, op->t.location, op->n.name_class ); return( op ); }
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 *rMOVRESTEMP( instruction *ins ) /***********************************************/ { instruction *new_ins; name *name1; name1 = AllocTemp( ins->type_class ); new_ins = MakeMove( name1, ins->result, ins->type_class ); ins->result = name1; MoveSegRes( ins, new_ins ); SuffixIns( ins, new_ins ); MarkPossible( ins, name1, ResPossible( ins ) ); ins->u.gen_table = NULL; return( ins ); }
/* 370 */ instruction *rMOVRESREG( instruction *ins ) /**********************************************/ { instruction *new_ins; name *name1; name1 = AllocTemp( ins->type_class ); new_ins = MakeMove( name1, ins->result, ins->type_class ); ins->result = name1; MoveSegRes( ins, new_ins ); SuffixIns( ins, new_ins ); MarkPossible( ins, name1, ResPossible( ins ) ); ins->u.gen_table = NULL; GiveRegister( NameConflict( ins, name1 ), true ); return( ins ); }
extern an PassProcParm( an rtn ) { /**************************************/ name *op; name *reg; op = AllocTemp( XX ); op->n.size = TypePtr->length + SizeDisplayReg(); reg = AllocRegName( DisplayReg() ); AddIns( MakeMove( GenIns( rtn ), TempOffset( op, 0, ClassPointer ), ClassPointer ) ); AddIns( MakeMove( reg, TempOffset( op, TypePtr->length, reg->n.name_class ), reg->n.name_class ) ); return( AddrName( op, TypeProcParm ) ); }
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 ); }
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 ); } }
static void AddCall( instruction *ins, cn call ) { /****************************************************/ name *proc_name; if( _IsTargetModel(FLOATING_DS) && (call->state->attr&ROUTINE_NEEDS_DS_LOADED) ) { AddIns( MakeMove( NearSegment(), AllocRegName( HW_DS ), U2 ) ); } if( call->name->tipe == TypeProcParm ) { proc_name = AllocTemp( ClassPointer ); /* what to do? proc_name->usage |= USE_REGISTER;*/ AddIns( MakeMove( ins->operands[CALL_OP_ADDR], proc_name, ClassPointer )); ins->operands[CALL_OP_ADDR] = proc_name; SetDisplay( GenIns( call->name ) ); AddIns( ins ); SaveDisplay( OP_POP ); } else { AddCallIns( ins, call ); } }
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; } } }
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 ); }
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; } }
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; }
4, 1, 2, 1, }; static name *MakeIndex( instruction *memory_ins, name *memory, type_class_def class ) { /*****************************************************************************************/ name *op; name *temp; instruction *ins; i_flags flags; fe_attr attr; temp = AllocTemp( WD ); ins = MakeUnary( OP_LA, memory, temp, WD ); PrefixIns( memory_ins, ins ); // Note: this assumes we put Memory names on 8-byte boundaries flags = AlignmentToFlags( AlignmentMap[ memory->v.offset & 0x7 ] ); if( memory->m.alignment != 0 ) { flags = AlignmentToFlags( memory->m.alignment ); } if( memory->m.memory_type == CG_FE ) { attr = FEAttr( memory->v.symbol ); if( attr & FE_VOLATILE ) { flags |= X_VOLATILE; } if( attr & FE_THREAD_DATA ) { // this is for the kooky expansion in axpenc.c - we have // to call rdteb, which destroys R0
/* Take advantage of the SETcc instruction in cases such as * x = y ? 3 : 4; * by adding a constant to the result of SETcc to directly obtain * the result of the assignment. */ static bool FindFlowOut( block *blk ) { /*****************************************/ signed_64 false_cons; signed_64 true_cons; signed_64 one; signed_64 neg_one; signed_64 diff; instruction *ins; instruction *ins0; instruction *ins1; // instruction *prev; block *true_blk; block *false_blk; block *join_blk; block_edge *new_edge; bool reverse; name *u1temp; name *temp; name *result; name *konst; type_class_def class; for( ins = blk->ins.hd.prev; !_OpIsCondition( ins->head.opcode ); ) { ins = ins->head.prev; } // prev = ins->head.prev; if( TypeClassSize[ ins->type_class ] > WORD_SIZE ) return( FALSE ); true_blk = blk->edge[ _TrueIndex( ins ) ].destination.u.blk; if( true_blk->inputs != 1 ) return( FALSE ); if( true_blk->targets != 1 ) return( FALSE ); false_blk = blk->edge[ _FalseIndex( ins ) ].destination.u.blk; if( false_blk->inputs != 1 ) return( FALSE ); if( false_blk->targets != 1 ) return( FALSE ); join_blk = false_blk->edge[ 0 ].destination.u.blk; if( join_blk != true_blk->edge[ 0 ].destination.u.blk ) return( FALSE ); if( join_blk->inputs != 2 ) return( FALSE ); if( join_blk->class & UNKNOWN_DESTINATION ) return( FALSE ); ins0 = SetToConst( false_blk, &false_cons ); if( ins0 == NULL ) return( FALSE ); ins1 = SetToConst( true_blk, &true_cons ); if( ins1 == NULL ) return( FALSE ); I32ToI64( 1, &one ); I32ToI64( -1, &neg_one ); U64Sub( &true_cons, &false_cons, &diff ); if( U64Cmp( &diff, &neg_one ) == 0 ) { U64IncDec( &false_cons, -1 ); reverse = TRUE; } else { if( U64Cmp( &diff, &one ) != 0 ) return( FALSE ); reverse = FALSE; } result = ins0->result; if( result != ins1->result ) return( FALSE ); class = ins0->type_class; if( class != ins1->type_class ) return( FALSE ); if( reverse ) FlipCond( ins ); u1temp = AllocTemp( U1 ); temp = AllocTemp( class ); ins->result = u1temp; ins1 = MakeConvert( u1temp, temp, class, U1 ); SuffixIns( ins, ins1 ); ins = ins1; if( I64Test( &false_cons ) != 0 ) { konst = AllocS64Const( false_cons.u._32[I64LO32], false_cons.u._32[I64HI32] ); ins1 = MakeBinary( OP_ADD, temp, konst, result, class ); } else {
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 ); }
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 ) ); }