mtac::basic_block_p mtac::loop::find_safe_preheader(mtac::Function& function, bool create) const { auto first_bb = find_entry(); //Step 1: Try to find if there is already a preheader auto pred = find_preheader(); if(pred){ //It must be the only successor and a fall through edge if(pred->successors.size() == 1 && pred->next == first_bb){ LOG<Trace>("Control-Flow") << "Found " << *pred << " as safe preheader of " << *this << log::endl; return pred; } } if(!create){ return nullptr; } //Step 2: If not found, create a new preheader auto pre_header = function.new_bb(); //Redispatch all the predecessors auto predecessors = first_bb->predecessors; for(auto& pred : predecessors){ if(blocks().find(pred) == blocks().end()){ mtac::remove_edge(pred, first_bb); mtac::make_edge(pred, pre_header); auto& quadruple = pred->statements.back(); if(quadruple.block == first_bb){ quadruple.block = pre_header; } } } function.insert_before(function.at(first_bb), pre_header); //Create the fall through edge mtac::make_edge(pre_header, first_bb); LOG<Trace>("Control-Flow") << "Create " << *pre_header << " as safe preheader of " << *this << log::endl; return pre_header; }
bool mtac::loop_unswitching::operator()(mtac::Function& function){ if(function.loops().empty()){ return false; } bool optimized = false; for(auto& loop : function.loops()){ if(loop.single_exit()){ auto entry = loop.find_entry(); auto exit = loop.find_exit(); if(entry && exit && entry->size() == 1){ if(entry->successors.size() == 2 && exit->predecessors.size() == 2){ if(std::is_permutation(entry->successors.begin(), entry->successors.end(), exit->predecessors.begin())){ auto& condition = *entry->begin(); if(condition.is_if() || condition.is_if_false()){ auto usage = mtac::compute_write_usage(loop); if(condition.arg1){ if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*condition.arg1)){ if(usage.written[*ptr] > 0){ continue; } } } if(condition.arg2){ if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*condition.arg2)){ if(usage.written[*ptr] > 0){ continue; } } } auto loop_1_entry = entry->successors.front(); auto loop_2_entry = entry->successors.back(); if(loop_2_entry->next == loop_1_entry){ std::swap(loop_1_entry, loop_2_entry); } entry->predecessors.erase(std::remove(entry->predecessors.begin(), entry->predecessors.end(), entry), entry->predecessors.end()); auto exit_copy = mtac::clone(function, exit); entry->successors.erase(std::remove(entry->successors.begin(), entry->successors.end(), exit), entry->successors.end()); exit->successors.erase(std::remove(exit->successors.begin(), exit->successors.end(), entry), exit->successors.end()); exit->successors.push_back(loop_2_entry); exit_copy->successors.erase(std::remove(exit_copy->successors.begin(), exit_copy->successors.end(), entry), exit_copy->successors.end()); exit_copy->successors.push_back(loop_1_entry); exit_copy->predecessors.erase(std::remove(exit_copy->predecessors.begin(), exit_copy->predecessors.end(), loop_2_entry), exit_copy->predecessors.end()); exit_copy->predecessors.pop_back(); mtac::BBClones bb_clones; bb_clones[entry] = loop_1_entry; mtac::replace_bbs(bb_clones, exit_copy); bb_clones[entry] = loop_2_entry; mtac::replace_bbs(bb_clones, exit); loop_1_entry->statements.pop_back(); loop_1_entry->predecessors.push_back(exit_copy); auto after_exit = exit->next; mtac::Quadruple goto_(mtac::Operator::GOTO); goto_.block = after_exit; auto new_goto_bb = function.new_bb(); new_goto_bb->statements.push_back(std::move(goto_)); function.insert_after(function.at(loop_1_entry), exit_copy); function.insert_after(function.at(exit_copy), new_goto_bb); mtac::remove_edge(loop_1_entry, exit); mtac::make_edge(loop_1_entry, exit_copy); mtac::remove_edge(exit_copy, after_exit); mtac::make_edge(new_goto_bb, after_exit); mtac::make_edge(exit_copy, new_goto_bb); LOG<Trace>("loops") << "Unswitch loop" << log::endl; function.context->global()->stats().inc_counter("loop_unswitched"); optimized = true; } } } } } } return optimized; }