//Check and replace 'exp' with 'cand_expr' if they are //equal, and update SSA info. If 'cand_expr' is NOT leaf, //that will create redundant computation, and //depends on later Redundancy Elimination to reverse back. // //'cand_expr': substitute cand_expr for exp. // e.g: exp is pr1 of S2, cand_expr is 10. // pr1 = 10 //S1 // g = pr1 //S2 // => // pr1 = 10 // g = 10 // //NOTE: Do NOT handle stmt. void IR_CP::replaceExpViaSSADu(IR * exp, IR const* cand_expr, IN OUT CPCtx & ctx) { ASSERT0(exp && exp->is_exp() && cand_expr && cand_expr->is_exp()); ASSERT0(exp->get_exact_ref()); if (!checkTypeConsistency(exp, cand_expr)) { return; } IR * parent = IR_parent(exp); if (parent->is_ild()) { CPC_need_recomp_aa(ctx) = true; } else if (parent->is_ist() && exp == IST_base(parent)) { if (!cand_expr->is_ld() && !cand_expr->is_pr() && !cand_expr->is_lda()) { return; } CPC_need_recomp_aa(ctx) = true; } IR * newir = m_ru->dupIRTree(cand_expr); if (cand_expr->is_read_pr() && PR_ssainfo(cand_expr) != NULL) { PR_ssainfo(newir) = PR_ssainfo(cand_expr); SSA_uses(PR_ssainfo(newir)).append(newir); } else { m_du->copyIRTreeDU(newir, cand_expr, true); } //cand_expr may be IR tree. And there might be PR or LD on the tree. newir->copyRefForTree(cand_expr, m_ru); //Add SSA use for new exp. SSAInfo * cand_ssainfo = NULL; if ((cand_ssainfo = cand_expr->get_ssainfo()) != NULL) { SSA_uses(cand_ssainfo).append(newir); } //Remove old exp SSA use. SSAInfo * exp_ssainfo = exp->get_ssainfo(); ASSERT0(exp_ssainfo); ASSERT0(SSA_uses(exp_ssainfo).find(exp)); SSA_uses(exp_ssainfo).remove(exp); CPC_change(ctx) = true; ASSERT0(exp->get_stmt()); bool doit = parent->replaceKid(exp, newir, false); ASSERT0(doit); UNUSED(doit); m_ru->freeIRTree(exp); }
//Duplicate and add an operand that indicated by opnd_pos at phi stmt //in one of bb's successors. void IRBB::dupSuccessorPhiOpnd(CFG<IRBB, IR> * cfg, Region * ru, UINT opnd_pos) { IR_CFG * ircfg = (IR_CFG*)cfg; Vertex * vex = ircfg->get_vertex(BB_id(this)); ASSERT0(vex); for (EdgeC * out = VERTEX_out_list(vex); out != NULL; out = EC_next(out)) { Vertex * succ_vex = EDGE_to(EC_edge(out)); IRBB * succ = ircfg->get_bb(VERTEX_id(succ_vex)); ASSERT0(succ); for (IR * ir = BB_first_ir(succ); ir != NULL; ir = BB_next_ir(succ)) { if (!ir->is_phi()) { break; } ASSERT0(cnt_list(PHI_opnd_list(ir)) >= opnd_pos); IR * opnd; UINT lpos = opnd_pos; for (opnd = PHI_opnd_list(ir); lpos != 0; opnd = opnd->get_next()) { ASSERT0(opnd); lpos--; } IR * newopnd = ru->dupIRTree(opnd); if (opnd->is_read_pr()) { newopnd->copyRef(opnd, ru); ASSERT0(PR_ssainfo(opnd)); PR_ssainfo(newopnd) = PR_ssainfo(opnd); SSA_uses(PR_ssainfo(newopnd)).append(newopnd); } ((CPhi*)ir)->addOpnd(newopnd); } } }
//'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; }