//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::hoistIf(IR ** head, IR * ir) { ASSERT(ir->is_if(), ("need IF")); ASSERT(IF_det(ir), ("DET is NULL")); IR * det = IF_det(ir); INT i = 0; while (det != NULL) { i++; det = det->get_next(); } IR * new_list = NULL; if (i > 1) { det = IF_det(ir); while (i > 1) { IR * c = det; ASSERT(c->is_stmt(), ("Non-stmt ir should be remove during reshape_ir_tree()")); det = det->get_next(); xcom::remove(&IF_det(ir), c); xcom::add_next(&new_list, c); i--; } xcom::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::hoistLoop(IR ** head, IR * ir) { ASSERT0(ir->is_dowhile() || ir->is_whiledo() || ir->is_doloop()); ASSERT(LOOP_det(ir), ("DET is NULL")); IR * det = LOOP_det(ir); INT i = 0; while (det != NULL) { i++; det = det->get_next(); } IR * new_list = NULL, * new_body_list = NULL; if (i > 1) { det = LOOP_det(ir); while (i > 1) { IR * c = det; ASSERT(c->is_stmt(), ("Non-stmt ir should be remove " "during reshape_ir_tree()")); det = det->get_next(); xcom::remove(&LOOP_det(ir), c); xcom::add_next(&new_list, c); i--; } new_body_list = m_ru->dupIRTreeList(new_list); xcom::insertbefore(head, ir, new_list); xcom::add_next(&LOOP_body(ir), new_body_list); return true; } return false; }
//Before removing bb or change bb successor, //you need remove the related PHI operand if BB successor has PHI stmt. void IRBB::removeSuccessorDesignatePhiOpnd(CFG<IRBB, IR> * cfg, IRBB * succ) { ASSERT0(cfg && succ); IR_CFG * ircfg = (IR_CFG*)cfg; Region * ru = ircfg->get_ru(); 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)) == succ->getNumOfPred(cfg)); IR * opnd; UINT lpos = pos; for (opnd = PHI_opnd_list(ir); lpos != 0; opnd = opnd->get_next()) { ASSERT0(opnd); lpos--; } if (opnd == NULL) { //PHI does not contain any operand. continue; } opnd->removeSSAUse(); ((CPhi*)ir)->removeOpnd(opnd); ru->freeIRTree(opnd); } }
//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::transformToDoWhile(IR ** head, IR * ir) { ASSERT(head != NULL && *head != NULL, ("invalid parameter")); if (!ir->is_lab()) { return false; } for (IR * t = ir; t != NULL; t = t->get_next()) { if (!t->is_if()) { continue; } if (IF_truebody(t) != NULL && IF_truebody(t)->is_goto() && isSameLabel(LAB_lab(ir), GOTO_lab(IF_truebody(t)))) { //Start transform. IR * dowhile = m_ru->allocIR(IR_DO_WHILE); LOOP_det(dowhile) = m_ru->dupIRTree(LOOP_det(t)); IR * if_stmt = t; t = ir->get_next(); while (t != NULL && t != if_stmt) { IR * c = t; t = t->get_next(); xcom::remove(head, c); xcom::add_next(&LOOP_body(dowhile), c); } ASSERT(t == if_stmt, ("illegal IR layout")); xcom::remove(head, if_stmt); if (IF_falsebody(if_stmt)) { xcom::add_next(&dowhile, IF_falsebody(if_stmt)); IF_falsebody(if_stmt) = NULL; } xcom::insertafter(&ir, dowhile); m_ru->freeIRTree(if_stmt); //free IF xcom::remove(head, ir); m_ru->freeIRTree(ir); //free LABEL return true; } } return false; }
//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); } } }
bool IR_CFS_OPT::CfsOpt( IN OUT IR ** ir_list, SimpCtx const& sc) { bool change = false; for (IR * ir = *ir_list; ir != NULL;) { if (transformToDoWhile(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (ir->is_if() && transformIf1(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (ir->is_if() && transformIf2(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (ir->is_if() && transformIf3(ir_list, ir)) { change = true; ir = *ir_list; continue; } switch (ir->get_code()) { case IR_IF: if (hoistIf(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (CfsOpt(&IF_truebody(ir), sc)) { change = true; ir = *ir_list; continue; } if (CfsOpt(&IF_falsebody(ir), sc)) { change = true; ir = *ir_list; continue; } break; case IR_DO_WHILE: case IR_WHILE_DO: case IR_DO_LOOP: if (hoistLoop(ir_list, ir)) { change = true; ir = *ir_list; continue; } if (CfsOpt(&LOOP_body(ir), sc)) { change = true; ir = *ir_list; continue; } break; case IR_SWITCH: if (CfsOpt(&SWITCH_body(ir), sc)) { change = true; ir = *ir_list; continue; } break; default:; } //end switch ir = ir->get_next(); } 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; }