//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; }
/* 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; }
//The followed forms // if (cond) { // // } else { // IR-list // } // //is replaced by // // if (!cond) { // IR-list // } bool IR_CFS_OPT::transformIf2(IR ** head, IR * ir) { ASSERT(head && *head, ("invalid parameter")); if (ir == NULL || !ir->is_if()) { return false; } //Check true part if (IF_truebody(ir) == NULL) { if (IF_falsebody(ir) == NULL) { xcom::remove(head, ir); m_ru->freeIRTree(ir); return true; } m_ru->invertCondition(&IF_det(ir)); IF_truebody(ir) = IF_falsebody(ir); IF_falsebody(ir) = NULL; return true; } return false; }
/* 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; }
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 // 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::transformIf3(IR ** head, IR * ir) { ASSERT(head && *head, ("invalid parameter")); if (ir == NULL || !ir->is_if()) { return false; } IR * det = IF_det(ir); if (det->is_gt()) { IR * opnd0 = BIN_opnd0(det); IR * opnd1 = BIN_opnd1(det); if (opnd0->is_ld() && opnd0->is_int() && opnd1->is_const() && opnd1->is_int() && m_ru->getIntegerInDataTypeValueRange(opnd1) == m_ru->getMaxInteger(m_tm->get_dtype_bitsize( TY_dtype(opnd1->get_type())), opnd1->is_signed())) { //e.g: //x is unsigned, if(x>0xFFFFFFFF) {a=1} else {b=1} => b=1 //x is signed, if(x>0x7FFFFFFF) {a=1} else {b=1} => b=1 IR * allocIR = NULL; if (IF_falsebody(ir) != NULL) { allocIR = m_ru->dupIRTree(IF_falsebody(ir)); } xcom::replace(head, ir, allocIR); if (allocIR != NULL) { IR_parent(allocIR) = IR_parent(ir); } m_ru->freeIRTree(ir); return true; } } else if (det->is_lt()) { IR * opnd0 = BIN_opnd0(det); IR * opnd1 = BIN_opnd1(det); if (opnd0->is_ld() && opnd0->is_int() && opnd1->is_const() && opnd1->is_int() && m_ru->getIntegerInDataTypeValueRange(opnd1) == m_ru->getMinInteger(m_tm->get_dtype_bitsize( TY_dtype(opnd1->get_type())), opnd1->is_signed())) { //x is signed, IF(x < 0x80000000) {a=1} ELSE {b=1} => b=1 IR * allocIR = NULL; if (IF_falsebody(ir) != NULL) { allocIR = m_ru->dupIRTree(IF_falsebody(ir)); } xcom::replace(head, ir, allocIR); if (allocIR != NULL) { IR_parent(allocIR) = IR_parent(ir); } m_ru->freeIRTree(ir); return true; } else if (opnd0->is_ld() && opnd1->is_const() && opnd0->is_uint() && CONST_int_val(opnd1) == 0) { //x is unsigned, if(x<0) {a=1} else {b=1} => b=1 IR * allocIR = NULL; if (IF_falsebody(ir) != NULL) { allocIR = m_ru->dupIRTree(IF_falsebody(ir)); } xcom::replace(head, ir, allocIR); if (allocIR != NULL) { IR_parent(allocIR) = IR_parent(ir); } m_ru->freeIRTree(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; }
/* 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; }