static bool NextCmp( instruction *ins ) { /*********************************************/ instruction *next; next = ins->head.next; if( !_OpIsCondition( next->head.opcode ) ) return( FALSE ); if( next->table == DoNop ) return( TRUE ); if( next->u.gen_table == NULL ) return( FALSE ); if( next->u.gen_table->generate != G_NO ) return( FALSE ); return( TRUE ); }
static instruction *FindOneCond( block *blk ) /************************************************/ { instruction *ins; instruction *cond; cond = NULL; for( ins = blk->ins.hd.next; ins->head.opcode != OP_BLOCK; ins = ins->head.next ) { if( _OpIsCondition( ins->head.opcode ) ) { if( cond != NULL ) return( NULL ); cond = ins; } } return( cond ); }
static bool isNiceCondIns( instruction *ins ) /************************************************ * Figure out if an instruction can be converted to OP_SET_LESS */ { opcode_defs oc; oc = ins->head.opcode; if( !_OpIsCondition( oc ) ) return( FALSE ); if( oc == OP_CMP_LESS || oc == OP_CMP_GREATER ) return( TRUE ); if( (oc == OP_CMP_LESS_EQUAL) && (ins->operands[1]->n.class == N_CONSTANT) && (ins->operands[1]->c.const_type == CONS_ABSOLUTE) ) return( TRUE ); if( (oc == OP_CMP_GREATER_EQUAL) && (ins->operands[1]->n.class == N_CONSTANT) && (ins->operands[1]->c.const_type == CONS_ABSOLUTE) ) return( TRUE ); return( FALSE ); }
/* 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 {
static bool FindFlowOut( block *blk ) /***************************************/ { signed_32 false_cons; signed_32 true_cons; instruction *ins; instruction *ins0; instruction *ins1; block *true; block *false; block *join; block_edge *new_edge; bool reverse; name *u4temp; name *temp; name *result; type_class_def class; opcode_defs oc; ins = blk->ins.hd.prev; while( !_OpIsCondition( ins->head.opcode ) ) { ins = ins->head.prev; } if( !isNiceCondIns( ins ) ) return( FALSE ); if( TypeClassSize[ ins->type_class ] > WORD_SIZE ) return( FALSE ); true = blk->edge[ _TrueIndex( ins ) ].destination.u.blk; if( true->inputs != 1 ) return( FALSE ); if( true->targets != 1 ) return( FALSE ); false = blk->edge[ _FalseIndex( ins ) ].destination.u.blk; if( false->inputs != 1 ) return( FALSE ); if( false->targets != 1 ) return( FALSE ); join = false->edge[0].destination.u.blk; if( join != true->edge[0].destination.u.blk ) return( FALSE ); if( join->inputs != 2 ) return( FALSE ); if( join->class & UNKNOWN_DESTINATION ) return( FALSE ); ins0 = SetToConst( false, &false_cons ); if( ins0 == NULL ) return( FALSE ); ins1 = SetToConst( true, &true_cons ); if( ins1 == NULL ) return( FALSE ); if( true_cons - false_cons == -1 ) { true_cons = false_cons; false_cons = true_cons - 1; reverse = TRUE; } else { if( true_cons - false_cons != 1 ) return( FALSE ); reverse = FALSE; } result = ins0->result; if( result != ins1->result ) return( FALSE ); class = ins0->type_class; if( class != ins1->type_class ) return( FALSE ); oc = ins->head.opcode; if( oc == OP_CMP_GREATER || oc == OP_CMP_GREATER_EQUAL ) reverse = !reverse; /* Replace 'x <= const' with 'x < const + 1' */ if( oc == OP_CMP_LESS_EQUAL || oc == OP_CMP_GREATER_EQUAL ) { signed_32 value; name *op1; op1 = ins->operands[1]; assert( op1->n.class == N_CONSTANT && op1->c.const_type == CONS_ABSOLUTE ); value = op1->c.int_value; if( oc == OP_CMP_LESS_EQUAL ) value += 1; else value -= 1; ins->operands[1] = AllocS32Const( value ); }
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 ); }