/* 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; }
/* 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; }
//Before removing bb, revising phi opnd if there are phis //in one of bb's successors. void IRBB::removeSuccessorPhiOpnd(CFG<IRBB, IR> * cfg) { IR_CFG * ircfg = (IR_CFG*)cfg; Region * ru = ircfg->get_ru(); 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); UINT const pos = ircfg->WhichPred(this, 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)) == cnt_list(VERTEX_in_list(succ_vex))); IR * opnd; UINT lpos = pos; for (opnd = PHI_opnd_list(ir); lpos != 0; opnd = IR_next(opnd)) { ASSERT0(opnd); lpos--; } opnd->removeSSAUse(); ((CPhi*)ir)->removeOpnd(opnd); ru->freeIRTree(opnd); } } }
//Record IR list into 'irset'. void CFS_MGR::record_ir_stmt(IR * ir_list, BITSET & irset) { while (ir_list != NULL) { irset.bunion(IR_id(ir_list)); ir_list = IR_next(ir_list); } }
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); } }
/* 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_phi(IR const* ir, bool & change) { VN * phivn = NULL; IR const* p = PHI_opnd_list(ir); if (p != NULL) { phivn = comp_vn(p, change); p = IR_next(p); } for (; p != NULL; p = IR_next(p)) { VN * opndvn = comp_vn(p, change); if (phivn != NULL && phivn != opndvn) { phivn = NULL; } } if (m_ir2vn.get(IR_id(ir)) != phivn) { IS_TRUE0(m_ir2vn.get(IR_id(ir)) == NULL); m_ir2vn.set(IR_id(ir), phivn); change = true; } }
void IR_GVN::process_call(IR const* ir, bool & change) { for (IR const* p = CALL_param_list(ir); p != NULL; p = IR_next(p)) { comp_vn(p, change); } VN * x = m_ir2vn.get(IR_id(ir)); if (x == NULL) { x = new_vn(); VN_type(x) = VN_VAR; change = true; m_ir2vn.set(IR_id(ir), x); } return; }
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); }
//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 = IR_next(opnd)) { 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); } } }
//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_next(ir) == NULL && IR_prev(ir) == NULL); 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 (ir->is_calls_stmt() || ir->is_cond_br() || ir->is_multicond_br() || ir->is_uncond_br()) { ASSERT(ir == BB_last_ir(this), ("invalid bb boundary.")); } c++; } ASSERT0(c == getNumOfIR()); }
/* 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; }
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; }
//The followed forms // if (cond) { // t=1 // a=1 // goto L1; // } // f=1 // goto L2; // L1: // //is replaced with // // 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::transformIf1(IR ** head, IR * ir) { ASSERT(head && *head, ("invalid parameter")); if (ir == NULL || !ir->is_if()) { return false; } //Check true part. IR * t = IF_truebody(ir); while (t != NULL) { if (!is_non_branch_ir(t)) { break; } t = t->get_next(); } if (t != NULL && t->get_next() == NULL && t->is_goto()) { IR * first_goto = t; t = ir->get_next(); while (t != NULL) { if (!is_non_branch_ir(t)) { break; } t = t->get_next(); } if (t != NULL && t->is_goto()) { IR * second_goto = t; if (IR_next(second_goto) != NULL && IR_next(second_goto)->is_lab() && isSameLabel(GOTO_lab(first_goto), LAB_lab(IR_next(second_goto)))) { //Start transforming. m_ru->invertCondition(&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 = t->get_next(); xcom::remove(&IF_truebody(ir), c); xcom::add_next(&new_list1, &last, c); } ASSERT(t && t == first_goto, ("invalid control flow")); xcom::remove(&IF_truebody(ir), first_goto); m_ru->freeIRTree(first_goto); //Split all irs between IF and L1. t = ir->get_next(); while (t != second_goto) { IR * c = t; t = t->get_next(); xcom::remove(head, c); xcom::add_next(&new_list2, c); } ASSERT(t != NULL && t == second_goto, ("???")); xcom::remove(head, second_goto); xcom::add_next(&new_list2, second_goto); //Swap new_list1 and new_list2 xcom::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; } ASSERT(IF_truebody(ir) == new_list2, ("illegal insertbefore<T>")); xcom::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; }
/* 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; }