bool mtac::loop_unrolling::operator()(mtac::Function& function){ if(function.loops().empty()){ return false; } bool optimized = false; for(auto& loop : function.loops()){ if(loop.has_estimate() && loop.blocks().size() == 1){ auto it = loop.estimate(); if(it > 100){ auto bb = *loop.begin(); //Do not increase too much the size of the body if(bb->statements.size() < 20){ unsigned int factor = 0; if((it % 8) == 0){ factor = 8; } else if((it % 4) == 0){ factor = 4; } else if((it % 2) == 0){ factor = 2; } if(factor == 0){ continue; } LOG<Trace>("loops") << "Unroll the loop with a factor " << factor << log::endl; function.context->global()->stats().inc_counter("loop_unrolled"); optimized = true; auto& statements = bb->statements; //The comparison is not necessary here anymore auto comparison = statements.back(); statements.pop_back(); int limit = statements.size(); //There are perhaps new references to functions for(auto& statement : statements){ if(statement.op == mtac::Operator::CALL){ program.call_graph.edge(function.definition(), statement.function())->count += (factor - 1); } } //Save enough space for the new statements statements.reserve(limit * factor + 1); //Start at 1 because there is already the original body for(unsigned int i = 1; i < factor; ++i){ for(int j = 0; j < limit; ++j){ statements.push_back(statements[j]); } } //Put the comparison again at the end statements.push_back(comparison); } } } } return optimized; }
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; }
bool mtac::remove_empty_loops::operator()(mtac::Function& function){ if(function.loops().empty()){ return false; } bool optimized = false; auto lit = iterate(function.loops()); while(lit.has_next()){ auto loop = *lit; if(loop.has_estimate() && loop.blocks().size() == 1){ auto it = loop.estimate(); auto bb = *loop.begin(); if(bb->size_no_nop() == 2){ std::shared_ptr<Variable> result; for(auto& statement : bb->statements){ if(statement.op != mtac::Operator::NOP){ result = statement.result; break; } } auto& basic_induction_variables = loop.basic_induction_variables(); if(basic_induction_variables.find(result) != basic_induction_variables.end()){ auto linear_equation = basic_induction_variables.begin()->second; auto initial_value = loop.initial_value(); bool loop_removed = false; //The loop does not iterate if(it == 0){ bb->statements.clear(); loop_removed = true; } else if(it > 0){ bb->statements.clear(); loop_removed = true; bb->emplace_back(result, static_cast<int>(initial_value + it * linear_equation.d), mtac::Operator::ASSIGN); } if(loop_removed){ function.context->global()->stats().inc_counter("empty_loop_removed"); //It is not a loop anymore mtac::remove_edge(bb, bb); lit.erase(); optimized = true; continue; } } } } ++lit; } return optimized; }