Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}