void IR_GVN::comp_array_addr_ref(IR const* ir, bool & change) { IS_TRUE0(ir->is_st_array()); IR const* arr = IST_base(ir); comp_vn(ARR_base(arr), change); for (IR const* s = ARR_sub_list(arr); s != NULL; s = IR_next(s)) { comp_vn(s, change); } }
void IR_GVN::process_st(IR const* ir, bool & change) { if (IR_type(ir) == IR_IST) { if (IR_type(IST_base(ir)) == IR_ARRAY) { comp_array_addr_ref(ir, change); } else { comp_vn(IST_base(ir), change); } } VN * x = comp_vn(ir->get_rhs(), change); if (x == NULL) { return; } //IST's vn may be set by its dominated use-stmt ILD. if (m_ir2vn.get(IR_id(ir)) != x) { IS_TRUE0(m_ir2vn.get(IR_id(ir)) == NULL); m_ir2vn.set(IR_id(ir), x); change = true; } return; }
//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); }
//Check and replace 'ir' with 'cand_expr' if they are //equal, and update DU info. If 'cand_expr' is NOT leaf, //that will create redundant computation, and //depends on later Redundancy Elimination to reverse back. //exp: expression which will be replaced. // //cand_expr: substitute cand_expr for exp. // e.g: cand_expr is *p, cand_expr_md is MD3 // *p(MD3) = 10 //p point to MD3 // ... // g = *q(MD3) //q point to MD3 // //exp_use_ssadu: true if exp used SSA du info. // //NOTE: Do NOT handle stmt. void IR_CP::replaceExp(IR * exp, IR const* cand_expr, IN OUT CPCtx & ctx, bool exp_use_ssadu) { ASSERT0(exp && exp->is_exp() && cand_expr); 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); m_du->copyIRTreeDU(newir, cand_expr, true); ASSERT0(cand_expr->get_stmt()); if (exp_use_ssadu) { //Remove exp SSA use. ASSERT0(exp->get_ssainfo()); ASSERT0(exp->get_ssainfo()->get_uses().find(exp)); exp->removeSSAUse(); } else { m_du->removeUseOutFromDefset(exp); } CPC_change(ctx) = true; ASSERT0(exp->get_stmt()); bool doit = parent->replaceKid(exp, newir, false); ASSERT0(doit); UNUSED(doit); m_ru->freeIRTree(exp); }
/* 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(); }
//Remove all expr for given stmt out of occ list in expr-tab. void IR_EXPR_TAB::remove_occs(IR * ir) { ASSERT0(ir->is_stmt()); switch (IR_code(ir)) { case IR_ST: { IR * stv = ST_rhs(ir); if (stv->is_const()) { return; } this->remove_occ(stv); } break; case IR_IST: { IR * stv = IST_rhs(ir); if (!stv->is_const()) { this->remove_occ(stv); } IR * m = IST_base(ir); if (m->is_const()) { return; } this->remove_occ(m); } break; case IR_CALL: case IR_ICALL: { IR * p = CALL_param_list(ir); while (p != NULL) { if (!p->is_const()) { this->remove_occ(p); } p = IR_next(p); } } break; case IR_TRUEBR: case IR_FALSEBR: this->remove_occ(BR_det(ir)); break; case IR_SWITCH: ASSERT0(SWITCH_vexp(ir)); if (!SWITCH_vexp(ir)->is_const()) { this->remove_occ(SWITCH_vexp(ir)); } break; case IR_IGOTO: ASSERT0(IGOTO_vexp(ir)); if (!IGOTO_vexp(ir)->is_const()) { this->remove_occ(IGOTO_vexp(ir)); } break; case IR_RETURN: if (RET_exp(ir) != NULL) { if (!RET_exp(ir)->is_const()) { this->remove_occ(RET_exp(ir)); } } break; case IR_GOTO: case IR_DO_WHILE: case IR_WHILE_DO: case IR_DO_LOOP: case IR_IF: case IR_LABEL: case IR_CASE: case IR_BREAK: case IR_CONTINUE: case IR_PHI: break; default: ASSERT0(0); } }
VN * IR_GVN::comp_array(IR const* exp, bool & change) { IS_TRUE0(IR_type(exp) == IR_ARRAY); for (IR const* s = ARR_sub_list(exp); s != NULL; s = IR_next(s)) { comp_vn(s, change); } VN * evn = m_ir2vn.get(IR_id(exp)); if (evn != NULL) { return evn; } evn = comp_mem(exp, change); if (evn != NULL) { return evn; } VN const* abase_vn = NULL; VN const* aofst_vn = NULL; if (((CARRAY*)exp)->get_dimn() == 1) { //only handle one dim array. abase_vn = comp_vn(ARR_base(exp), change); if (abase_vn == NULL) { return NULL; } aofst_vn = m_ir2vn.get(IR_id(ARR_sub_list(exp))); if (aofst_vn == NULL) { return NULL; } } else { return NULL; } DU_SET const* du = m_du->get_du_c(exp); if (du == NULL || du->get_elem_count() == 0) { //Array does not have any DEF. VN * x = register_qua_vn(IR_ARRAY, abase_vn, aofst_vn, register_int_vn(ARR_ofst(exp)), register_int_vn(exp->get_dt_size(m_dm))); if (m_ir2vn.get(IR_id(exp)) != x) { m_ir2vn.set(IR_id(exp), x); change = true; } return x; } IR const* exp_stmt = const_cast<IR*>(exp)->get_stmt(); IS_TRUE0(exp_stmt->is_stmt()); IR const* domdef = m_du->find_dom_def(exp, exp_stmt, du, false); if (domdef == NULL) { return NULL; } if (domdef->is_st_array() && IST_ofst(domdef) != ARR_ofst(exp)) { return NULL; } if (!domdef->is_st_array()) { return comp_array_by_anon_domdef(exp, abase_vn, aofst_vn, domdef, change); } IS_TRUE0(IR_type(domdef) == IR_IST); //Check if VN expression is match. IR const* narr = IST_base(domdef); IS_TRUE(((CARRAY*)narr)->get_dimn() == 1, ("only handle one dim array.")); VN const* b = m_ir2vn.get(IR_id(ARR_base(narr))); if (b == NULL || b != abase_vn) { return NULL; } VN const* o = m_ir2vn.get(IR_id(ARR_sub_list(narr))); if (o == NULL || o != aofst_vn) { return NULL; } VN * uni_vn = m_ir2vn.get(IR_id(domdef)); if (uni_vn == NULL) { uni_vn = register_qua_vn(IR_ARRAY, abase_vn, aofst_vn, register_int_vn(ARR_ofst(exp)), register_int_vn(exp->get_dt_size(m_dm))); m_ir2vn.set(IR_id(domdef), uni_vn); m_ir2vn.set(IR_id(narr), uni_vn); } m_ir2vn.set(IR_id(exp), uni_vn); change = true; return uni_vn; }
VN * IR_GVN::comp_ild(IR const* exp, bool & change) { IS_TRUE0(IR_type(exp) == IR_ILD); VN * mlvn = comp_vn(ILD_base(exp), change); if (mlvn == NULL) { IS_TRUE0(m_ir2vn.get(IR_id(exp)) == NULL); IS_TRUE0(m_ir2vn.get(IR_id(ILD_base(exp))) == NULL); return NULL; } VN * evn = m_ir2vn.get(IR_id(exp)); if (evn != NULL) { return evn; } evn = comp_mem(exp, change); if (evn != NULL) { return evn; } DU_SET const* defset = m_du->get_du_c(exp); if (defset == NULL || defset->get_elem_count() == 0) { VN * v = register_tri_vn(IR_ILD, mlvn, register_int_vn(ILD_ofst(exp)), register_int_vn(exp->get_dt_size(m_dm))); m_ir2vn.set(IR_id(exp), v); return v; } IR const* exp_stmt = const_cast<IR*>(exp)->get_stmt(); IR const* domdef = m_stmt2domdef.get(exp_stmt); if (domdef == NULL) { domdef = m_du->find_dom_def(exp, exp_stmt, defset, false); if (domdef != NULL) { m_stmt2domdef.set(exp_stmt, domdef); } } if (domdef == NULL) { return NULL; } /* //ofst will be distinguished in comp_ild_by_anon_domdef(), so //we do not need to differentiate the various offset of ild and ist. if (IR_type(domdef) == IR_IST && !domdef->is_st_array() && IST_ofst(domdef) != ILD_ofst(exp)) { return NULL; } */ if (IR_type(domdef) != IR_IST || domdef->is_st_array() || IST_ofst(domdef) != ILD_ofst(exp)) { return comp_ild_by_anon_domdef(exp, mlvn, domdef, change); } //domdef is ist and the offset is matched. //Check if IR expression is match. VN const* mcvn = m_ir2vn.get(IR_id(IST_base(domdef))); if (mcvn == NULL || mcvn != mlvn) { return NULL; } VN * uni_vn = m_ir2vn.get(IR_id(domdef)); if (uni_vn == NULL) { uni_vn = register_tri_vn(IR_ILD, mlvn, register_int_vn(ILD_ofst(exp)), register_int_vn(exp->get_dt_size(m_dm))); m_ir2vn.set(IR_id(domdef), uni_vn); } m_ir2vn.set(IR_id(exp), uni_vn); change = true; return uni_vn; }
void IR_GVN::dump_bb(UINT bbid) { if (g_tfile == NULL) { return; } IR_BB * bb = m_ru->get_bb(bbid); IS_TRUE0(bb); CIR_ITER ii; fprintf(g_tfile, "\n-- BB%d ", IR_BB_id(bb)); dump_bb_labs(IR_BB_lab_list(bb)); fprintf(g_tfile, "\n"); for (IR * ir = IR_BB_first_ir(bb); ir != NULL; ir = IR_BB_next_ir(bb)) { dump_ir(ir, m_ru->get_dm()); fprintf(g_tfile, "\n"); VN * x = m_ir2vn.get(IR_id(ir)); if (x != NULL) { fprintf(g_tfile, "vn%d", VN_id(x)); } fprintf(g_tfile, " <- {"); switch (IR_type(ir)) { case IR_ST: ii.clean(); for (IR const* k = ir_iter_init_c(ST_rhs(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } break; case IR_STPR: ii.clean(); for (IR const* k = ir_iter_init_c(STPR_rhs(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } break; case IR_IST: ii.clean(); for (IR const* k = ir_iter_init_c(IST_rhs(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } ii.clean(); for (IR const* k = ir_iter_init_c(IST_base(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } break; case IR_CALL: case IR_ICALL: { ii.clean(); for (IR const* k = ir_iter_init_c(CALL_param_list(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } } break; case IR_TRUEBR: case IR_FALSEBR: ii.clean(); for (IR const* k = ir_iter_init_c(BR_det(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } break; case IR_SWITCH: ii.clean(); for (IR const* k = ir_iter_init_c(SWITCH_vexp(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } break; case IR_IGOTO: ii.clean(); for (IR const* k = ir_iter_init_c(IGOTO_vexp(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } break; case IR_RETURN: ii.clean(); for (IR const* k = ir_iter_init_c(RET_exp(ir), ii); k != NULL; k = ir_iter_next_c(ii)) { VN * x = m_ir2vn.get(IR_id(k)); dump_h1(k, x); } break; case IR_GOTO: break; case IR_REGION: IS_TRUE0(0); //TODO break; default: IS_TRUE0(0); } fprintf(g_tfile, " }"); } fflush(g_tfile); }