Example #1
0
bool mtac::inline_functions::operator()(mtac::Program& program){
    bool optimized = false;
    auto global_context = program.context;

    auto& call_graph = program.call_graph;

    auto order = call_graph.topological_order();
    call_graph.compute_reachable();

    typedef std::reference_wrapper<eddic::Function> func_ref;

    for(auto& function_ref : order){
        auto& function = function_ref.get();

        //Consider only reachable functions
        if(call_graph.is_reachable(function)){
            //Standard function are assembly functions, cannot be inlined
            if(!function.standard()){
                auto cg_node = call_graph.node(function);

                //Collect the callers of the functions

                std::vector<func_ref> callers;
                for(auto& in_edge : cg_node->in_edges){
                    if(in_edge->count > 0){
                        callers.push_back(in_edge->source->function);
                    }
                }

                //Sort them to inline the edges in the order of the topological sort

                std::sort(callers.begin(), callers.end(), 
                        [&order](const func_ref& lhs, const func_ref& rhs){ return std::find(order.begin(), order.end(), lhs) < std::find(order.begin(),order.end(), rhs); });

                auto& source_function = program.mtac_function(function);

                for(auto& caller : callers){
                    if(call_graph.is_reachable(caller.get())){
                        auto& dest_function = program.mtac_function(caller.get());

                        bool local = false;
                        do {
                            local = call_site_inlining(dest_function, source_function, program);
                            optimized |= local;
                        } while(local);
                    }
                }
            }
        }
    }

    call_graph.release_reachable();

    return optimized;
}
bool mtac::parameter_propagation::operator()(mtac::Program& program){
    bool optimized = false;

    auto global_context = program.context;

    auto arguments = collect_arguments(program);

    for(auto& function_map : arguments){
        auto& function_name = function_map.first;
        auto& function = global_context->getFunction(function_name);
        auto& function_arguments = function_map.second;

        std::vector<std::pair<std::size_t, int>> constant_parameters;

        for(std::size_t i = 0; i < function.parameters().size(); ++i){
            bool found = false;
            int constant_value = 0;

            for(auto& arguments : function_arguments){
                auto& arg = arguments[i];

                if(auto* ptr = boost::get<int>(&arg)){
                    if(found){
                        if(*ptr != constant_value){
                            found = false;
                            break;
                        }
                    } else {
                        found = true;
                        constant_value = *ptr;
                    }
                } else {
                    found = false;
                    break;
                }
            }

            if(found){
                constant_parameters.emplace_back(i, constant_value);
            }
        }

        if(!constant_parameters.empty()){
            std::sort(constant_parameters.begin(), constant_parameters.end(), 
                    [](const std::pair<int, int>& p1, const std::pair<int, int>& p2){ return p1.first > p2.first; });

            //Replace the parameter by the constant in each use of the parameter
            auto& mtac_function = program.mtac_function(function);
            mtac::VariableClones clones;

            for(auto& parameter : constant_parameters){
                auto param = mtac_function.context->getVariable(function.parameter(parameter.first).name());

                log::emit<Debug>("Optimizer") << "Propagate " << param->name() << " by " << parameter.second  << " in function " << function.name() << log::endl;
                mtac_function.context->global()->stats().inc_counter("propagated_parameter");

                clones[param] = parameter.second;
            }

            VariableReplace replacer(clones);
            for(auto& block : mtac_function){
                for(auto& quadruple : block){
                    replacer.replace(quadruple);
                }
            }
            
            for(auto& parameter : constant_parameters){
                auto param = function.context()->getVariable(function.parameter(parameter.first).name());
                function.context()->removeVariable(param); 
            }

            for(auto& parameter : constant_parameters){
                //Remove the parameter passing for each call to the function
                for(auto& mtac_function : program.functions){
                    for(auto& block : mtac_function){
                        for(auto& quadruple : block){
                            if(quadruple.op == mtac::Operator::CALL){
                                auto& param_function = quadruple.function();

                                if(param_function == function){
                                    mtac::basic_block_p param_block;
                                    mtac::basic_block::reverse_iterator it;
                                    mtac::basic_block::reverse_iterator end;

                                    if(block->statements.front() == quadruple){
                                        param_block = block->prev;
                                        it = block->prev->statements.rbegin();
                                        end = block->prev->statements.rend();
                                    } else {
                                        param_block = block;
                                        it = block->statements.rbegin();
                                        end = block->statements.rend();

                                        while(*it != quadruple){
                                            ++it;
                                        }
                                    }

                                    std::size_t discovered = 0;

                                    while(it != end && discovered < function.parameters().size()){
                                        auto& param_quadruple = *it;

                                        if(param_quadruple.op == mtac::Operator::PARAM || param_quadruple.op == mtac::Operator::PPARAM){
                                            if(discovered == parameter.first){
                                                mtac::transform_to_nop(param_quadruple);
                                                optimized = true;
                                            }

                                            ++discovered;
                                        }

                                        ++it;
                                    }
                                }
                            }
                        }
                    }
                }

                //Remove the parameter from the function definition
                function.parameters().erase(function.parameters().begin() + parameter.first);
            }
        }
    }

    return optimized;
}