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; }