//Check that all basic blocks should only end with terminator IR. void IRBB::verify() { UINT c = 0; C<IR*> * ct; for (IR * ir = BB_irlist(this).get_head(&ct); ir != NULL; ir = BB_irlist(this).get_next(&ct)) { ASSERT0(ir->is_single()); ASSERT0(ir->get_bb() == this); switch (IR_code(ir)) { case IR_ST: case IR_STPR: case IR_STARRAY: case IR_IST: case IR_PHI: case IR_REGION: case IR_CALL: case IR_ICALL: case IR_GOTO: case IR_IGOTO: case IR_TRUEBR: case IR_FALSEBR: case IR_RETURN: case IR_SWITCH: break; default: ASSERT(0, ("BB does not supported this kind of IR.")); } if (is_bb_down_boundary(ir)) { ASSERT(ir == BB_last_ir(this), ("invalid BB down boundary.")); } c++; } ASSERT0(c == getNumOfIR()); }
//Return true if 'occ' does not be modified till meeting 'use_ir'. //e.g: // xx = occ //def_ir // .. // .. // yy = xx //use_ir // //'def_ir': ir stmt. //'occ': opnd of 'def_ir' //'use_ir': stmt in use-list of 'def_ir'. bool IR_CP::is_available(IR const* def_ir, IR const* occ, IR * use_ir) { if (def_ir == use_ir) { return false; } if (occ->is_const()) { return true; } //Need check overlapped MDSet. //e.g: Suppose occ is '*p + *q', p->a, q->b. //occ can NOT reach 'def_ir' if one of p, q, a, b //modified during the path. IRBB * defbb = def_ir->get_bb(); IRBB * usebb = use_ir->get_bb(); if (defbb == usebb) { //Both def_ir and use_ir are in same BB. C<IR*> * ir_holder = NULL; bool f = BB_irlist(defbb).find(const_cast<IR*>(def_ir), &ir_holder); CK_USE(f); IR * ir; for (ir = BB_irlist(defbb).get_next(&ir_holder); ir != NULL && ir != use_ir; ir = BB_irlist(defbb).get_next(&ir_holder)) { if (m_du->is_may_def(ir, occ, true)) { return false; } } if (ir == NULL) { ;//use_ir appears prior to def_ir. Do more check via live_in_expr. } else { ASSERT(ir == use_ir, ("def_ir should be in same bb to use_ir")); return true; } } ASSERT0(use_ir->is_stmt()); DefDBitSetCore const* availin_expr = m_du->getAvailInExpr(BB_id(usebb), NULL); ASSERT0(availin_expr); if (availin_expr->is_contain(IR_id(occ))) { IR * u; for (u = BB_first_ir(usebb); u != use_ir && u != NULL; u = BB_next_ir(usebb)) { //Check if 'u' override occ's value. if (m_du->is_may_def(u, occ, true)) { return false; } } ASSERT(u != NULL && u == use_ir, ("Not find use_ir in bb, may be it has " "been removed by other optimization")); return true; } return false; }
void IRBB::dump(Region * ru) { if (g_tfile == NULL) { return; } g_indent = 0; fprintf(g_tfile, "\n----- BB%d ------", BB_id(this)); if (get_lab_list().get_elem_count() > 0) { fprintf(g_tfile, "\nLABEL:"); dumpBBLabel(get_lab_list(), g_tfile); } //Attributes fprintf(g_tfile, "\nATTR:"); if (BB_is_entry(this)) { fprintf(g_tfile, "entry_bb "); } //if (BB_is_exit(this)) { // fprintf(g_tfile, "exit_bb "); //} if (BB_is_fallthrough(this)) { fprintf(g_tfile, "fall_through "); } if (BB_is_target(this)) { fprintf(g_tfile, "branch_target "); } //IR list fprintf(g_tfile, "\nSTMT NUM:%d", getNumOfIR()); g_indent += 3; TypeMgr * dm = ru->get_type_mgr(); for (IR * ir = BB_first_ir(this); ir != NULL; ir = BB_irlist(this).get_next()) { ASSERT0(IR_next(ir) == NULL && IR_prev(ir) == NULL); ASSERT0(ir->get_bb() == this); dump_ir(ir, dm, NULL, true, true, false); } g_indent -= 3; fprintf(g_tfile, "\n"); fflush(g_tfile); }
/* Encode expression for single BB. Scan IR statement literally, and encoding it for generating the unique id for each individual expressions, and update the 'GEN-SET' and 'KILL-SET' of IR-EXPR for BB as well as. */ void IR_EXPR_TAB::encode_bb(IRBB * bb) { C<IR*> * ct; for (IR * ir = BB_irlist(bb).get_head(&ct); ir != NULL; ir = BB_irlist(bb).get_next(&ct)) { ASSERT0(ir->is_stmt()); switch (IR_code(ir)) { case IR_ST: { ExpRep * ie = encode_expr(ST_rhs(ir)); if (ie != NULL) { set_map_ir2ir_expr(ST_rhs(ir), ie); } } break; case IR_STPR: { ExpRep * ie = encode_expr(STPR_rhs(ir)); if (ie != NULL) { set_map_ir2ir_expr(STPR_rhs(ir), ie); } } break; case IR_STARRAY: { ExpRep * ie = encode_expr(ARR_base(ir)); if (ie != NULL) { set_map_ir2ir_expr(ARR_base(ir), ie); } for (IR * sub = ARR_sub_list(ir); sub != NULL; sub = IR_next(sub)) { ExpRep * ie = encode_expr(sub); if (ie != NULL) { set_map_ir2ir_expr(sub, ie); } } ie = encode_expr(STARR_rhs(ir)); if (ie != NULL) { set_map_ir2ir_expr(STARR_rhs(ir), ie); } } break; case IR_IST: { ExpRep * ie = encode_expr(IST_rhs(ir)); if (ie != NULL) { set_map_ir2ir_expr(IST_rhs(ir), ie); } ie = encode_istore_memaddr(IST_base(ir)); if (ie != NULL) { set_map_ir2ir_expr(IST_base(ir), ie); } } break; case IR_ICALL: //indirective call { ExpRep * ie = encode_expr(ICALL_callee(ir)); if (ie != NULL) { set_map_ir2ir_expr(ICALL_callee(ir), ie); } } case IR_CALL: { IR * parm = CALL_param_list(ir); while (parm != NULL) { ExpRep * ie = encode_expr(parm); if (ie != NULL) { set_map_ir2ir_expr(parm, ie); } parm = IR_next(parm); } } break; case IR_GOTO: break; case IR_IGOTO: { ExpRep * ie = encode_expr(IGOTO_vexp(ir)); if (ie != NULL) { set_map_ir2ir_expr(IGOTO_vexp(ir), ie); } } break; case IR_DO_WHILE: case IR_WHILE_DO: case IR_DO_LOOP: //loop with init , boundary , and step info case IR_IF: ASSERT(0, ("High level IR should be simplified")); break; case IR_LABEL: break; case IR_CASE: case IR_REGION: break; case IR_TRUEBR: case IR_FALSEBR: { ExpRep * ie = encode_expr(BR_det(ir)); if (ie != NULL) { set_map_ir2ir_expr(BR_det(ir), ie); } } break; case IR_SWITCH: { ExpRep * ie = encode_expr(SWITCH_vexp(ir)); if (ie != NULL) { set_map_ir2ir_expr(SWITCH_vexp(ir), ie); } } break; case IR_RETURN: { ExpRep * ie = encode_expr(RET_exp(ir)); if (ie != NULL) { set_map_ir2ir_expr(RET_exp(ir), ie); } } break; case IR_PHI: break; default: ASSERT0(0); } //end switch } //end for IR //dump_ir_expr_tab(); }
//'usevec': for local used. bool IR_CP::doProp(IN IRBB * bb, Vector<IR*> & usevec) { bool change = false; C<IR*> * cur_iter, * next_iter; for (BB_irlist(bb).get_head(&cur_iter), next_iter = cur_iter; cur_iter != NULL; cur_iter = next_iter) { IR * def_stmt = cur_iter->val(); BB_irlist(bb).get_next(&next_iter); if (!is_copy(def_stmt)) { continue; } DUSet const* useset = NULL; UINT num_of_use = 0; SSAInfo * ssainfo = NULL; bool ssadu = false; if ((ssainfo = def_stmt->get_ssainfo()) != NULL && SSA_uses(ssainfo).get_elem_count() != 0) { //Record use_stmt in another vector to facilitate this function //if it is not in use-list any more after copy-propagation. SEGIter * sc; for (INT u = SSA_uses(ssainfo).get_first(&sc); u >= 0; u = SSA_uses(ssainfo).get_next(u, &sc)) { IR * use = m_ru->get_ir(u); ASSERT0(use); usevec.set(num_of_use, use); num_of_use++; } ssadu = true; } else if (def_stmt->get_exact_ref() == NULL && !def_stmt->is_void()) { //Allowing copy propagate exact or VOID value. continue; } else if ((useset = def_stmt->readDUSet()) != NULL && useset->get_elem_count() != 0) { //Record use_stmt in another vector to facilitate this function //if it is not in use-list any more after copy-propagation. DUIter di = NULL; for (INT u = useset->get_first(&di); u >= 0; u = useset->get_next(u, &di)) { IR * use = m_ru->get_ir(u); usevec.set(num_of_use, use); num_of_use++; } } else { continue; } IR const* prop_value = get_propagated_value(def_stmt); for (UINT i = 0; i < num_of_use; i++) { IR * use = usevec.get(i); ASSERT0(use->is_exp()); IR * use_stmt = use->get_stmt(); ASSERT0(use_stmt->is_stmt()); ASSERT0(use_stmt->get_bb() != NULL); IRBB * use_bb = use_stmt->get_bb(); if (!ssadu && !(bb == use_bb && bb->is_dom(def_stmt, use_stmt, true)) && !m_cfg->is_dom(BB_id(bb), BB_id(use_bb))) { //'def_stmt' must dominate 'use_stmt'. //e.g: // if (...) { // g = 10; //S1 // } // ... = g; //S2 //g can not be propagted since S1 is not dominate S2. continue; } if (!is_available(def_stmt, prop_value, use_stmt)) { //The value that will be propagated can //not be killed during 'ir' and 'use_stmt'. //e.g: // g = a; //S1 // if (...) { // a = ...; //S3 // } // ... = g; //S2 //g can not be propagted since a is killed by S3. continue; } if (!ssadu && !m_du->isExactAndUniqueDef(def_stmt, use)) { //Only single definition is allowed. //e.g: // g = 20; //S3 // if (...) { // g = 10; //S1 // } // ... = g; //S2 //g can not be propagted since there are //more than one definitions are able to get to S2. continue; } if (!canBeCandidate(prop_value)) { continue; } CPCtx lchange; IR * old_use_stmt = use_stmt; replaceExp(use, prop_value, lchange, ssadu); ASSERT(use_stmt && use_stmt->is_stmt(), ("ensure use_stmt still legal")); change |= CPC_change(lchange); if (!CPC_change(lchange)) { continue; } //Indicate whether use_stmt is the next stmt of def_stmt. bool is_next = false; if (next_iter != NULL && use_stmt == next_iter->val()) { is_next = true; } RefineCtx rf; use_stmt = m_ru->refineIR(use_stmt, change, rf); if (use_stmt == NULL && is_next) { //use_stmt has been optimized and removed by refineIR(). next_iter = cur_iter; BB_irlist(bb).get_next(&next_iter); } if (use_stmt != NULL && use_stmt != old_use_stmt) { //use_stmt has been removed and new stmt generated. ASSERT(old_use_stmt->is_undef(), ("the old one should be freed")); C<IR*> * irct = NULL; BB_irlist(use_bb).find(old_use_stmt, &irct); ASSERT0(irct); BB_irlist(use_bb).insert_before(use_stmt, irct); BB_irlist(use_bb).remove(irct); } } //end for each USE } //end for IR return change; }