/* Hoist det of loop. e.g: while (a=10,b+=3,c<a) { IR-LIST; } be replaced by a = 10; b += 3; while (c<a) { IR-LIST; a = 10; b += 3; } */ bool IR_CFS_OPT::hoist_loop(IR ** head, IR * ir) { IS_TRUE(IR_type(ir)==IR_DO_WHILE || IR_type(ir)==IR_WHILE_DO || IR_type(ir)==IR_DO_LOOP, ("need LOOP")); IS_TRUE(LOOP_det(ir), ("DET is NULL")); IR * det = LOOP_det(ir); INT i = 0; while (det != NULL) { i++; det = IR_next(det); } IR * new_list = NULL, * new_body_list = NULL; if (i > 1) { det = LOOP_det(ir); while (i > 1) { IR * c = det; IS_TRUE(c->is_stmt(), ("Non-stmt ir should be remove " "during reshape_ir_tree()")); det = IR_next(det); remove(&LOOP_det(ir), c); add_next(&new_list, c); i--; } new_body_list = m_ru->dup_irs_list(new_list); insertbefore(head, ir, new_list); add_next(&LOOP_body(ir), new_body_list); return true; } return false; }
VN * IR_GVN::comp_sc_by_anon_domdef(IR const* exp, IR const* domdef, bool & change) { IS_TRUE0((IR_type(exp) == IR_LD || IR_type(exp) == IR_PR) && m_du->is_may_def(domdef, exp, false)); SCVNE2VN * vnexp_map = m_def2sctab.get(domdef); UINT dtsz = exp->get_dt_size(m_dm); MD const* md = exp->get_exact_ref(); IS_TRUE0(md); VNE_SC vexp(MD_id(md), exp->get_ofst(), dtsz); /* NOTE: foo(); v1; //s1 goo(); v1; //s2 vn of s1 should not same with s2. */ if (vnexp_map == NULL) { vnexp_map = new SCVNE2VN(m_pool, 16); //bsize to be evaluate. m_def2sctab.set(domdef, vnexp_map); } VN * vn = vnexp_map->get(&vexp); if (vn == NULL) { vn = new_vn(); VN_type(vn) = VN_VAR; vnexp_map->setv((OBJTY)&vexp, vn); } m_ir2vn.set(IR_id(exp), vn); change = true; return vn; }
//Compute VN for array according to anonymous domdef. VN * IR_GVN::comp_array_by_anon_domdef(IR const* arr, VN const* basevn, VN const* ofstvn, IR const* domdef, bool & change) { IS_TRUE0(IR_type(arr) == IR_ARRAY && m_du->is_may_def(domdef, arr, false)); ARR_VNE2VN * vnexp_map = m_def2arrtab.get(domdef); UINT dtsz = arr->get_dt_size(m_dm); VNE_ARR vexp(VN_id(basevn), VN_id(ofstvn), ARR_ofst(arr), dtsz); /* NOTE: foo(); array(v1); //s1 goo(); array(v1); //s2 vn of s1 should not same with s2. */ if (vnexp_map == NULL) { vnexp_map = new ARR_VNE2VN(m_pool, 16); //bsize to be evaluate. m_def2arrtab.set(domdef, vnexp_map); } VN * vn = vnexp_map->get(&vexp); if (vn == NULL) { vn = new_vn(); VN_type(vn) = VN_OP; VN_op(vn) = IR_ARRAY; vnexp_map->setv((OBJTY)&vexp, vn); } m_ir2vn.set(IR_id(arr), vn); change = true; return vn; }
//Compute VN for ild according to anonymous domdef. VN * IR_GVN::comp_ild_by_anon_domdef(IR const* ild, VN const* mlvn, IR const* domdef, bool & change) { IS_TRUE0(IR_type(ild) == IR_ILD && m_du->is_may_def(domdef, ild, false)); ILD_VNE2VN * vnexp_map = m_def2ildtab.get(domdef); UINT dtsz = ild->get_dt_size(m_dm); VNE_ILD vexp(VN_id(mlvn), ILD_ofst(ild), dtsz); /* NOTE: foo(); ild(v1); //s1 goo(); ild(v1); //s2 vn of s1 should not same with s2. */ if (vnexp_map == NULL) { vnexp_map = new ILD_VNE2VN(m_pool, 16); //bsize to be evaluate. m_def2ildtab.set(domdef, vnexp_map); } VN * ildvn = vnexp_map->get(&vexp); if (ildvn == NULL) { ildvn = new_vn(); VN_type(ildvn) = VN_OP; VN_op(ildvn) = IR_ILD; vnexp_map->setv((OBJTY)&vexp, ildvn); } m_ir2vn.set(IR_id(ild), ildvn); change = true; return ildvn; }
//Return true if gvn is able to determine the result of 'ir'. bool IR_GVN::calc_cond_must_val(IN IR const* ir, bool & must_true, bool & must_false) { must_true = false; must_false = false; IS_TRUE0(ir->is_judge()); VN const* v1 = m_ir2vn.get(IR_id(BIN_opnd0(ir))); VN const* v2 = m_ir2vn.get(IR_id(BIN_opnd1(ir))); if (v1 == NULL || v2 == NULL) return false; switch (IR_type(ir)) { case IR_LT: case IR_GT: if (v1 == v2) { must_true = false; must_false = true; return true; } break; case IR_LE: case IR_GE: if (v1 == v2) { must_true = true; must_false = false; return true; } break; case IR_NE: if (v1 == v2) { must_true = false; must_false = true; return true; } if (v1 != v2) { must_true = true; must_false = false; return true; } IS_TRUE0(0); break; case IR_EQ: if (v1 == v2) { must_true = true; must_false = false; return true; } if (v1 != v2) { must_true = false; must_false = true; return true; } IS_TRUE0(0); break; case IR_LAND: case IR_LOR: case IR_LNOT: break; default: IS_TRUE0(0); } return false; }
/* Canonicalize det of IF. e.g: if (a=10,b+=3,c<a) {...} be replaced by a = 10; b += 3; if (c<a) {...} */ bool IR_CFS_OPT::hoist_if(IR ** head, IR * ir) { IS_TRUE(IR_type(ir) == IR_IF, ("need IF")); IS_TRUE(IF_det(ir), ("DET is NULL")); IR * det = IF_det(ir); INT i = 0; while (det != NULL) { i++; det = IR_next(det); } IR * new_list = NULL; if (i > 1) { det = IF_det(ir); while (i > 1) { IR * c = det; IS_TRUE(c->is_stmt(), ("Non-stmt ir should be remove during reshape_ir_tree()")); det = IR_next(det); remove(&IF_det(ir), c); add_next(&new_list, c); i--; } insertbefore(head, ir, new_list); return true; } return false; }
/* Control flow struct optimizations. Transform follow struct to do-while loop LABEL: IR-LIST IF DET GOTO LABEL ...(DEAD CODE) ELSE FALSE-PART ENDIF is replace by DO { IR-LIST } WHILE DET FALSE-PART */ bool IR_CFS_OPT::trans_to_do_while_loop(IR ** head, IR * ir) { IS_TRUE(head != NULL && *head != NULL, ("invalid parameter")); if (ir->is_lab()) { IR * t = ir; LABEL_INFO * li = LAB_lab(ir); while (t != NULL) { if (IR_type(t) == IR_IF) { if (IF_truebody(t) != NULL && IR_type(IF_truebody(t)) == IR_GOTO && is_same_label(LAB_lab(ir), GOTO_lab(IF_truebody(t)))) { //start transform... IR * dowhile = m_ru->new_ir(IR_DO_WHILE); LOOP_det(dowhile) = m_ru->dup_irs(LOOP_det(t)); IR * if_stmt = t; t = IR_next(ir); while (t != NULL && t != if_stmt) { IR * c = t; t = IR_next(t); remove(head, c); add_next(&LOOP_body(dowhile), c); } IS_TRUE(t == if_stmt, ("???")); remove(head, if_stmt); if (IF_falsebody(if_stmt)) { add_next(&dowhile, IF_falsebody(if_stmt)); IF_falsebody(if_stmt) = NULL; } insertafter(&ir, dowhile); m_ru->free_irs(if_stmt); //free IF remove(head, ir); m_ru->free_irs(ir); //free LABEL return true; } } t = IR_next(t); } } return false; }
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; }
void IR_GVN::dump_h1(IR const* k, VN * x) { fprintf(g_tfile, "\n\t%s", IRTNAME(IR_type(k))); if (k->is_pr()) { fprintf(g_tfile, "%d", PR_no(k)); } fprintf(g_tfile, " id:%d ", IR_id(k)); if (x != NULL) { fprintf(g_tfile, "vn%d", VN_id(x)); } else { fprintf(g_tfile, "--"); } }
ExpRep * IR_EXPR_TAB::encode_expr(IN IR * ir) { if (ir == NULL) return NULL; ASSERT0(ir->is_exp()); switch (IR_type(ir)) { case IR_ID: case IR_LD: case IR_LDA: case IR_CONST: case IR_PR: return NULL; case IR_ILD: case IR_ADD: case IR_SUB: case IR_MUL: case IR_DIV: case IR_REM: case IR_MOD: case IR_LAND: //logical and && case IR_LOR: //logical or || case IR_BAND: //bit and & case IR_BOR: //bit or | case IR_XOR: case IR_BNOT: //bitwise not case IR_LNOT: //logical not case IR_NEG: case IR_LT: case IR_LE: case IR_GT: case IR_GE: case IR_EQ: case IR_NE: case IR_ARRAY: case IR_ASR: case IR_LSR: case IR_LSL: case IR_CVT: //type convertion case IR_SELECT: //formulized determinate-expr?exp:exp { ExpRep * ie = append_expr(ir); ASSERT(!EXPR_occ_list(ie).find(ir), ("process same IR repeated.")); EXPR_occ_list(ie).append_tail(ir); return ie; } default: ASSERT0(0); } return NULL; }
//ONLY used in this file bool IR_CFS_OPT::is_non_branch_ir(IR * ir) { if (ir == NULL) { return false; } switch (IR_type(ir)) { case IR_ST: //store case IR_IST: //indirective store case IR_CALL: case IR_ICALL: //indirective call return true; default: return false; } return false; }
VN * IR_GVN::comp_sc(IR const* exp, bool & change) { 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* du = m_du->get_du_c(exp); IS_TRUE(du, ("This situation should be catched in comp_mem()")); IS_TRUE0(du->get_elem_count() > 0); IR const* exp_stmt = const_cast<IR*>(exp)->get_stmt(); IR const* domdef = m_du->find_dom_def(exp, exp_stmt, du, false); if (domdef == NULL) { return NULL; } if (domdef->is_stid() && ST_ofst(domdef) != exp->get_ofst()) { return NULL; } if (!domdef->is_stid() && !domdef->is_stpr()) { return comp_sc_by_anon_domdef(exp, domdef, change); } switch (IR_type(exp)) { case IR_LD: if (domdef->is_stpr() || (LD_idinfo(exp) != ST_idinfo(domdef))) { return NULL; } break; case IR_PR: if (domdef->is_stid() || PR_no(exp) != STPR_no(domdef)) { return NULL; } break; default: IS_TRUE(0, ("unsupport")); } VN * uni_vn = m_ir2vn.get(IR_id(domdef)); if (uni_vn == NULL) { uni_vn = new_vn(); VN_type(uni_vn) = VN_VAR; m_ir2vn.set(IR_id(domdef), uni_vn); } m_ir2vn.set(IR_id(exp), uni_vn); change = true; return uni_vn; }
UINT IR_EXPR_TAB::compute_hash_key(IR const* ir) { ASSERT0(ir != NULL); UINT hval = IR_type(ir) + (ir->get_offset() + 1) + (UINT)(size_t)IR_dt(ir); if (ir->is_id()) { VAR * var = ID_info(ir); /* SYM * name = VAR_name(id_info); CHAR * s = SYM_name(name); UINT v = 0 ; while (*s != 0) { v += (UINT)(*s++); } hval += v; */ hval += 5 * (UINT)(size_t)var; } return hval; }
/* The followed forms if (cond) { } else { IR-list } is replaced by if (!cond) { IR-list } */ bool IR_CFS_OPT::trans_if2(IR ** head, IR * ir) { IS_TRUE(head && *head, ("invalid parameter")); if (ir == NULL || IR_type(ir) != IR_IF) { return false; } //Check true part if (!IF_truebody(ir)) { if (IF_falsebody(ir) == NULL) { remove(head, ir); m_ru->free_irs(ir); return true; } m_ru->invert_cond(&IF_det(ir)); IF_truebody(ir) = IF_falsebody(ir); IF_falsebody(ir) = NULL; return true; } return false; }
void IR_GVN::process_bb(IR_BB * bb, bool & change) { C<IR*> * ct; for (IR * ir = IR_BB_ir_list(bb).get_head(&ct); ir != NULL; ir = IR_BB_ir_list(bb).get_next(&ct)) { switch (IR_type(ir)) { case IR_ST: case IR_STPR: case IR_IST: process_st(ir, change); break; case IR_CALL: case IR_ICALL: process_call(ir, change); break; case IR_TRUEBR: case IR_FALSEBR: comp_vn(BR_det(ir), change); break; case IR_SWITCH: comp_vn(SWITCH_vexp(ir), change); break; case IR_IGOTO: comp_vn(IGOTO_vexp(ir), change); break; case IR_RETURN: comp_vn(RET_exp(ir), change); break; case IR_REGION: process_region(ir, change); break; case IR_PHI: process_phi(ir, change); break; case IR_GOTO: break; default: IS_TRUE0(0); } } }
void handle_ld(IR * ld, MD2MDS * mx) { IS_TRUE0(IR_type(ld) == IR_LD && mx); IR_AI * ai = IR_ai(ld); if (ai == NULL) { return; } TBAA_AI * ty = (TBAA_AI*)ai->get(IRAI_TBAA); if (ty == NULL) { return; } MD * md = m_tyid2md.get(ty->tyid); if (md != NULL) { MD const* t = alloc_ld_md(ld); set_point_to_set_add_md(t, *mx, md); return; } CHAR buf[64]; sprintf(buf, "dummy%d", ty->tyid); VAR * dummy = m_var_mgr->register_var(buf, D_MC, D_UNDEF, 0, 1, 1, VAR_GLOBAL); VAR_is_addr_taken(dummy) = true; VAR_allocable(dummy) = false; m_ru->add_to_var_tab(dummy); MD dummy_md; MD_base(&dummy_md) = dummy; MD_size(&dummy_md) = 0; MD_ty(&dummy_md) = MD_UNBOUND; MD_is_addr_taken(&dummy_md) = true; MD * entry = m_md_sys->register_md(dummy_md); m_tyid2md.set(ty->tyid, entry); MD const* t = alloc_ld_md(ld); set_point_to_set_add_md(t, *mx, entry); }
/* 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_type(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(); }
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; }
//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_type(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); } }
/* The followed forms x is signed IF(x > 0x7FFFFFFF) {a=1} ELSE {b=1} => b=1 IF(x < 0x80000000) {a=1} ELSE {b=1} => b=1 x is unsigned IF(x > 0xFFFFFFFF){a=1} ELSE {b=1} => b=1 IF(x < 0x0) {a=1} ELSE {b=1} => b=1 */ bool IR_CFS_OPT::trans_if3(IR ** head, IR * ir) { IS_TRUE(head && *head, ("invalid parameter")); if (ir == NULL || IR_type(ir) != IR_IF) { return false; } IR * det = IF_det(ir); if (IR_type(det) == IR_GT) { IR * opnd0 = BIN_opnd0(det); IR * opnd1 = BIN_opnd1(det); DTD const* op0_rty = opnd0->get_dtd(m_dm); DTD const* op1_rty = opnd1->get_dtd(m_dm); if (IR_type(opnd0) == IR_LD && opnd1->is_const() && opnd0->is_int(m_dm) && CONST_int_val(opnd1) == MAX_INT_VALUE) { //x is signed, if(x>0x7FFFFFFF) {a=1} else {b=1} => b=1 IR * new_ir = NULL; if (IF_falsebody(ir)) { new_ir = m_ru->dup_irs(IF_falsebody(ir)); } replace(head, ir, new_ir); //Revise IR_parent. IR_parent(new_ir) = IR_parent(ir); m_ru->free_irs(ir); return true; } else if (IR_type(opnd0) == IR_LD && IR_is_const(opnd1) && opnd0->is_uint(m_dm) && CONST_int_val(opnd1) == MAX_UINT_VALUE) { //x is unsigned, if(x>0xFFFFFFFF) {a=1} else {b=1} => b=1 IR * new_ir = NULL; if (IF_falsebody(ir)) { new_ir = m_ru->dup_irs(IF_falsebody(ir)); } replace(head, ir, new_ir); //Revise IR_parent. IR_parent(new_ir) = IR_parent(ir); m_ru->free_irs(ir); return true; } } else if (IR_type(det) == IR_LT) { IR * opnd0 = BIN_opnd0(det); IR * opnd1 = BIN_opnd1(det); DTD const* op0_rty = opnd0->get_dtd(m_dm); DTD const* op1_rty = opnd1->get_dtd(m_dm); if (IR_type(opnd0) == IR_LD && IR_is_const(opnd1) && opnd0->is_int(m_dm) && CONST_int_val(opnd1) == MIN_INT_VALUE) { //x is signed, IF(x < 0x80000000) {a=1} ELSE {b=1} => b=1 IR * new_ir = NULL; if (IF_falsebody(ir)) { new_ir = m_ru->dup_irs(IF_falsebody(ir)); } replace(head, ir, new_ir); m_ru->free_irs(ir); return true; } else if (IR_type(opnd0) == IR_LD && IR_is_const(opnd1) && opnd0->is_uint(m_dm) && CONST_int_val(opnd1) == 0) { //x is unsigned, if(x<0) {a=1} else {b=1} => b=1 IR * new_ir = NULL; if (IF_falsebody(ir)) { new_ir = m_ru->dup_irs(IF_falsebody(ir)); } replace(head, ir, new_ir); //Revise IR_parent. IR_parent(new_ir) = IR_parent(ir); m_ru->free_irs(ir); return true; } } return false; }
bool IR_CFS_OPT::perform_cfs_optimization(IN OUT IR ** ir_list, IN SIMP_CTX const& sc) { bool change = false; for (IR * ir = *ir_list; ir != NULL;) { if (trans_to_do_while_loop(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (IR_type(ir) == IR_IF && trans_if1(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (IR_type(ir) == IR_IF && trans_if2(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (IR_type(ir) == IR_IF && trans_if3(ir_list, ir)) { change = true; ir = *ir_list; continue; } switch (IR_type(ir)) { case IR_IF: if (hoist_if(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (perform_cfs_optimization(&IF_truebody(ir), sc)) { change = true; ir = *ir_list; continue; } if (perform_cfs_optimization(&IF_falsebody(ir), sc)) { change = true; ir = *ir_list; continue; } break; case IR_DO_WHILE: case IR_WHILE_DO: case IR_DO_LOOP: if (hoist_loop(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (perform_cfs_optimization(&LOOP_body(ir), sc)) { change = true; ir = *ir_list; continue; } break; case IR_SWITCH: if (perform_cfs_optimization(&SWITCH_body(ir), sc)) { change = true; ir = *ir_list; continue; } break; default:; } //end switch ir = IR_next(ir); } return change; }
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); }
/* The followed forms if (cond) { t=1 a=1 goto L1; } f=1 goto L2; L1: is replaced by if (!cond) { f=1 goto L2; } t=1 a=1 L1: 'goto L1' is removed and free, and L1 is removed if it is not a target of some other instruction. */ bool IR_CFS_OPT::trans_if1(IR ** head, IR * ir) { IS_TRUE(head && *head, ("invalid parameter")); if (ir == NULL || IR_type(ir) != IR_IF) { return false; } //Check true part. IR * t = IF_truebody(ir); while (t != NULL) { if (!is_non_branch_ir(t)) { break; } t = IR_next(t); } if (t != NULL && IR_next(t) == NULL && IR_type(t) == IR_GOTO) { IR * first_goto = t; t = IR_next(ir); while (t != NULL) { if (!is_non_branch_ir(t)) break; t = IR_next(t); } if (t != NULL && IR_type(t) == IR_GOTO) { IR * second_goto = t; if (IR_next(second_goto) != NULL && IR_next(second_goto)->is_lab() && is_same_label(GOTO_lab(first_goto), LAB_lab(IR_next(second_goto)))) { //Here we start to transform... m_ru->invert_cond(&IF_det(ir)); IR * new_list1 = NULL; IR * new_list2 = NULL; t = IF_truebody(ir); //Split true body of IF. IR * last = NULL; while (t != first_goto) { IR * c = t; t = IR_next(t); remove(&IF_truebody(ir), c); add_next(&new_list1, &last, c); } IS_TRUE(t && t == first_goto, ("invalid control flow")); remove(&IF_truebody(ir), first_goto); m_ru->free_irs(first_goto); //Split all irs between IF and L1. t = IR_next(ir); while (t != second_goto) { IR * c = t; t = IR_next(t); remove(head, c); add_next(&new_list2, c); } IS_TRUE(t != NULL && t == second_goto, ("???")); remove(head, second_goto); add_next(&new_list2, second_goto); //Swap new_list1 and new_list2 insertbefore(&IF_truebody(ir), IF_truebody(ir), new_list2); //Update the IR_parent for new_list2. for (IR * tmp = new_list2; tmp != NULL; tmp = IR_next(tmp)) { IR_parent(tmp) = ir; } IS_TRUE(IF_truebody(ir) == new_list2, ("illegal insertbefore<T>")); insertafter(&ir, new_list1); //Update the IR_parent for new_list1. for (IR * tmp = new_list1; tmp != NULL; tmp = IR_next(tmp)) { IR_parent(tmp) = IR_parent(ir); } return true; } } } return false; }
VN * IR_GVN::comp_vn(IR const* exp, bool & change) { IS_TRUE0(exp); switch (IR_type(exp)) { case IR_ADD: case IR_SUB: case IR_MUL: case IR_DIV: case IR_REM: case IR_MOD: case IR_LAND: //logical and && case IR_LOR: //logical or || case IR_BAND: //inclusive and & case IR_BOR: //inclusive or | case IR_XOR: //exclusive or case IR_LT: case IR_LE: case IR_GT: case IR_GE: case IR_EQ: //== case IR_NE: //!= case IR_ASR: case IR_LSR: case IR_LSL: { VN * vn1 = comp_vn(BIN_opnd0(exp), change); VN * vn2 = comp_vn(BIN_opnd1(exp), change); if (vn1 == NULL || vn2 == NULL) { if (m_ir2vn.get(IR_id(exp)) != NULL) { m_ir2vn.set(IR_id(exp), NULL); change = true; } return NULL; } VN * x = register_bin_vn((IR_TYPE)IR_type(exp), vn1, vn2); if (m_ir2vn.get(IR_id(exp)) != x) { m_ir2vn.set(IR_id(exp), x); change = true; } return x; } break; case IR_BNOT: //bitwise not case IR_LNOT: //logical not case IR_NEG: //negative { VN * x = comp_vn(UNA_opnd0(exp), change); if (x == NULL) { if (m_ir2vn.get(IR_id(exp)) != NULL) { m_ir2vn.set(IR_id(exp), NULL); change = true; } return NULL; } x = register_uni_vn((IR_TYPE)IR_type(exp), x); if (m_ir2vn.get(IR_id(exp)) != x) { m_ir2vn.set(IR_id(exp), x); change = true; } return x; } break; case IR_CVT: //type convertion { VN * x = comp_vn(CVT_exp(exp), change); if (x == NULL) { if (m_ir2vn.get(IR_id(exp)) != NULL) { m_ir2vn.set(IR_id(exp), NULL); change = true; } return NULL; } x = register_uni_vn((IR_TYPE)IR_type(exp), x); if (m_ir2vn.get(IR_id(exp)) != x) { m_ir2vn.set(IR_id(exp), x); change = true; } return x; } break; case IR_LDA: { IR const* ldabase = LDA_base(exp); VN * basevn; if (IR_type(ldabase) == IR_ID) { MD const* emd = ldabase->get_exact_ref(); if (emd == NULL) { //e.g: p = &"blabla", regard MD of "blabla" as inexact. IS_TRUE(ldabase->is_str(m_dm), ("only string's MD can be inexact.")); if (m_is_comp_lda_string) { emd = m_du->get_effect_use_md(ldabase); IS_TRUE(emd, ("string should have effect MD")); basevn = register_md_vn(emd); } else { basevn = NULL; } } else { IS_TRUE0(emd); basevn = register_md_vn(emd); } } else { basevn = comp_vn(LDA_base(exp), change); } if (basevn == NULL) { if (m_ir2vn.get(IR_id(exp)) != NULL) { m_ir2vn.set(IR_id(exp), NULL); change = true; } return NULL; } VN * ofstvn = register_int_vn(LDA_ofst(exp)); VN * x = register_bin_vn(IR_LDA, basevn, ofstvn); if (m_ir2vn.get(IR_id(exp)) != x) { m_ir2vn.set(IR_id(exp), x); change = true; } return x; } break; //case IR_ID: case IR_LD: case IR_PR: return comp_sc(exp, change); case IR_ARRAY: return comp_array(exp, change); case IR_ILD: return comp_ild(exp, change); case IR_CONST: { VN * x = m_ir2vn.get(IR_id(exp)); if (x != NULL) { return x; } if (exp->is_int(m_dm)) { x = register_int_vn(CONST_int_val(exp)); } else if (exp->is_fp(m_dm)) { if (!m_is_vn_fp) { return NULL; } x = register_fp_vn(CONST_fp_val(exp)); } else if (exp->is_str(m_dm)) { x = register_str_vn(CONST_str_val(exp)); } else { IS_TRUE(0, ("unsupport const type")); } IS_TRUE0(x); m_ir2vn.set(IR_id(exp), x); change = true; return x; } break; default: break; } return NULL; }
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; }