<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>

#include "boost_cfg.hpp"
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>

#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"
#include "mtac/TemporaryAllocator.hpp"

//The custom optimizations
#include "mtac/VariableOptimizations.hpp"
#include "mtac/FunctionOptimizations.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/ConcatReduction.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_optimizations.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/RemoveAssign.hpp"
#include "mtac/RemoveMultipleAssign.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

using namespace eddic;

namespace {

const unsigned int MAX_THREADS = 2;

template<typename Visitor>
bool apply_to_all(std::shared_ptr<mtac::Function> function){
    Visitor visitor;

    mtac::visit_all_statements(visitor, function);

    return visitor.optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks_two_pass(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visitor.pass = mtac::Pass::DATA_MINING;

        visit_each(visitor, block->statements);

        visitor.pass = mtac::Pass::OPTIMIZE;

        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Problem, typename... Args>
bool data_flow_optimization(std::shared_ptr<mtac::Function> function, Args... args){
    bool optimized = false;

    Problem problem(args...);

    auto results = mtac::data_flow(function, problem);

    //Once the data-flow problem is fixed, statements can be optimized
    for(auto& block : function->getBasicBlocks()){
        for(auto& statement : block->statements){
            optimized |= problem.optimize(statement, results);
        }
    }

    return optimized;
}

bool debug(const std::string& name, bool b, std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        if(b){
            log::emit<Debug>("Optimizer") << name << " returned true" << log::endl;

            //Print the function
            print(function);
        } else {
            log::emit<Debug>("Optimizer") << name << " returned false" << log::endl;
        }
    }

    return b;
}

template<typename Functor, typename... Args>
bool debug(const std::string& name, Functor functor, std::shared_ptr<mtac::Function> function, Args... args){
    bool b;
    {
        PerfsTimer timer(name);

        b = functor(function, args...);
    }

    return debug(name, b, function);
}

void remove_nop(std::shared_ptr<mtac::Function> function){
    for(auto& block : function->getBasicBlocks()){
        auto it = iterate(block->statements);

        while(it.has_next()){
            if(unlikely(boost::get<std::shared_ptr<mtac::NoOp>>(&*it))){
                it.erase();
                continue;
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&*it)){
                if((*ptr)->op == mtac::Operator::NOP){
                    it.erase();
                    continue;
                }
            }

            ++it;
        }
    }
}

//TODO Find a more elegant way than using pointers

typedef boost::mpl::vector<mtac::ArithmeticIdentities*, mtac::ReduceInStrength*, mtac::ConstantFolding*> passes;

struct pass_runner {
    bool optimized = false;

    template<typename Pass>
    inline void operator()(Pass* pass){
        if(mtac::pass_traits<Pass>::type == mtac::pass_type::LOCAL){
            std::cout << pass << std::endl;
        } else {
            ASSERT_PATH_NOT_TAKEN("Invalid pass type");
        }
    }
};

void run_all_passes() {
    pass_runner runner;

    do{
        boost::mpl::for_each<passes>(runner);
    } while(runner.optimized);
}

void optimize_function(std::shared_ptr<mtac::Function> function, std::shared_ptr<StringPool> pool, Platform platform){
    run_all_passes();

    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start optimizations on " << function->getName() << log::endl;

        print(function);
    }

    bool optimized;
    do {
        optimized = false;

        optimized |= debug("Aritmetic Identities", &apply_to_all<mtac::ArithmeticIdentities>, function);
        optimized |= debug("Reduce in Strength", &apply_to_all<mtac::ReduceInStrength>, function);
        optimized |= debug("Constant folding", &apply_to_all<mtac::ConstantFolding>, function);

        optimized |= debug("Constant propagation", &data_flow_optimization<mtac::ConstantPropagationProblem>, function);
        optimized |= debug("Offset Constant Propagation", &data_flow_optimization<mtac::OffsetConstantPropagationProblem, std::shared_ptr<StringPool>, Platform>, function, pool, platform);

        optimized |= debug("Common Subexpression Elimination", &data_flow_optimization<mtac::CommonSubexpressionElimination>, function);

        optimized |= debug("Pointer Propagation", &apply_to_basic_blocks<mtac::PointerPropagation>, function);
        optimized |= debug("Math Propagation", &apply_to_basic_blocks_two_pass<mtac::MathPropagation>, function);

        optimized |= debug("Optimize Branches", &mtac::optimize_branches, function);
        optimized |= debug("Optimize Concat", &mtac::optimize_concat, function, pool);
        optimized |= debug("Remove dead basic block", &mtac::remove_dead_basic_blocks, function);
        optimized |= debug("Merge basic block", &mtac::merge_basic_blocks, function);

        remove_nop(function);
        optimized |= debug("Dead-Code Elimination", &mtac::dead_code_elimination, function);

        optimized |= debug("Remove aliases", &mtac::remove_aliases, function);

        optimized |= debug("Loop Invariant Code Motion", &mtac::loop_invariant_code_motion, function);
        optimized |= debug("Loop Induction Variables Optimization", &mtac::loop_induction_variables_optimization, function);
        optimized |= debug("Remove empty loops", &mtac::remove_empty_loops, function);

        //Remove variables that are not used after optimizations
        clean_variables(function);
    } while (optimized);
}

void basic_optimize_function(std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start basic optimizations on " << function->getName() << log::endl;

        print(function);
    }

    debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);
}

void optimize_all_functions(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration){
    PerfsTimer timer("Whole optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("single-threaded")){
        for(auto& function : functions){
            optimize_function(function, string_pool, platform);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &string_pool, platform, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    optimize_function(functions[i], string_pool, platform);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}

} //end of anonymous namespace

void mtac::Optimizer::optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);

    if(configuration->option_defined("fglobal-optimization")){
        bool optimized = false;
        do{
            mtac::remove_unused_functions(program);

            optimize_all_functions(program, string_pool, platform, configuration);

            optimized = mtac::remove_empty_functions(program);
            optimized = mtac::inline_functions(program, configuration);
        } while(optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        basic_optimize(program, string_pool, configuration);
    }

    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);
}

void mtac::Optimizer::basic_optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> /*string_pool*/, std::shared_ptr<Configuration> configuration) const {
    PerfsTimer timer("Whole basic optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("single-threaded")){
        for(auto& function : functions){
            basic_optimize_function(function);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    basic_optimize_function(functions[i]);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}
<commit_msg>Run local passes<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>

#include "boost_cfg.hpp"
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>

#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"
#include "mtac/TemporaryAllocator.hpp"

//The custom optimizations
#include "mtac/VariableOptimizations.hpp"
#include "mtac/FunctionOptimizations.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/ConcatReduction.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_optimizations.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/RemoveAssign.hpp"
#include "mtac/RemoveMultipleAssign.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

using namespace eddic;

namespace {

const unsigned int MAX_THREADS = 2;

template<typename Visitor>
bool apply_to_all(std::shared_ptr<mtac::Function> function){
    Visitor visitor;

    mtac::visit_all_statements(visitor, function);

    return visitor.optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks_two_pass(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visitor.pass = mtac::Pass::DATA_MINING;

        visit_each(visitor, block->statements);

        visitor.pass = mtac::Pass::OPTIMIZE;

        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Problem, typename... Args>
bool data_flow_optimization(std::shared_ptr<mtac::Function> function, Args... args){
    bool optimized = false;

    Problem problem(args...);

    auto results = mtac::data_flow(function, problem);

    //Once the data-flow problem is fixed, statements can be optimized
    for(auto& block : function->getBasicBlocks()){
        for(auto& statement : block->statements){
            optimized |= problem.optimize(statement, results);
        }
    }

    return optimized;
}

bool debug(const std::string& name, bool b, std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        if(b){
            log::emit<Debug>("Optimizer") << name << " returned true" << log::endl;

            //Print the function
            print(function);
        } else {
            log::emit<Debug>("Optimizer") << name << " returned false" << log::endl;
        }
    }

    return b;
}

template<typename Functor, typename... Args>
bool debug(const std::string& name, Functor functor, std::shared_ptr<mtac::Function> function, Args... args){
    bool b;
    {
        PerfsTimer timer(name);

        b = functor(function, args...);
    }

    return debug(name, b, function);
}

void remove_nop(std::shared_ptr<mtac::Function> function){
    for(auto& block : function->getBasicBlocks()){
        auto it = iterate(block->statements);

        while(it.has_next()){
            if(unlikely(boost::get<std::shared_ptr<mtac::NoOp>>(&*it))){
                it.erase();
                continue;
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&*it)){
                if((*ptr)->op == mtac::Operator::NOP){
                    it.erase();
                    continue;
                }
            }

            ++it;
        }
    }
}

//TODO Find a more elegant way than using pointers

typedef boost::mpl::vector<mtac::ArithmeticIdentities*, mtac::ReduceInStrength*, mtac::ConstantFolding*> passes;

struct pass_runner {
    bool optimized = false;
    std::shared_ptr<mtac::Function> function;

    pass_runner(std::shared_ptr<mtac::Function> function) : function(function) {};

    template<typename Pass>
    inline void operator()(Pass*){
        bool local = false;

        if(mtac::pass_traits<Pass>::type == mtac::pass_type::LOCAL){
            local = apply_to_all<Pass>(function);
        }

        if(local){

        }

        optimized = local;
    }
};

void run_all_passes(std::shared_ptr<mtac::Function> function) {
    pass_runner runner(function);

    do{
        boost::mpl::for_each<passes>(runner);
    } while(runner.optimized);
}

void optimize_function(std::shared_ptr<mtac::Function> function, std::shared_ptr<StringPool> pool, Platform platform){
    run_all_passes(function);

    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start optimizations on " << function->getName() << log::endl;

        print(function);
    }

    bool optimized;
    do {
        optimized = false;

        optimized |= debug("Aritmetic Identities", &apply_to_all<mtac::ArithmeticIdentities>, function);
        optimized |= debug("Reduce in Strength", &apply_to_all<mtac::ReduceInStrength>, function);
        optimized |= debug("Constant folding", &apply_to_all<mtac::ConstantFolding>, function);

        optimized |= debug("Constant propagation", &data_flow_optimization<mtac::ConstantPropagationProblem>, function);
        optimized |= debug("Offset Constant Propagation", &data_flow_optimization<mtac::OffsetConstantPropagationProblem, std::shared_ptr<StringPool>, Platform>, function, pool, platform);

        optimized |= debug("Common Subexpression Elimination", &data_flow_optimization<mtac::CommonSubexpressionElimination>, function);

        optimized |= debug("Pointer Propagation", &apply_to_basic_blocks<mtac::PointerPropagation>, function);
        optimized |= debug("Math Propagation", &apply_to_basic_blocks_two_pass<mtac::MathPropagation>, function);

        optimized |= debug("Optimize Branches", &mtac::optimize_branches, function);
        optimized |= debug("Optimize Concat", &mtac::optimize_concat, function, pool);
        optimized |= debug("Remove dead basic block", &mtac::remove_dead_basic_blocks, function);
        optimized |= debug("Merge basic block", &mtac::merge_basic_blocks, function);

        remove_nop(function);
        optimized |= debug("Dead-Code Elimination", &mtac::dead_code_elimination, function);

        optimized |= debug("Remove aliases", &mtac::remove_aliases, function);

        optimized |= debug("Loop Invariant Code Motion", &mtac::loop_invariant_code_motion, function);
        optimized |= debug("Loop Induction Variables Optimization", &mtac::loop_induction_variables_optimization, function);
        optimized |= debug("Remove empty loops", &mtac::remove_empty_loops, function);

        //Remove variables that are not used after optimizations
        clean_variables(function);
    } while (optimized);
}

void basic_optimize_function(std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start basic optimizations on " << function->getName() << log::endl;

        print(function);
    }

    debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);
}

void optimize_all_functions(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration){
    PerfsTimer timer("Whole optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("single-threaded")){
        for(auto& function : functions){
            optimize_function(function, string_pool, platform);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &string_pool, platform, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    optimize_function(functions[i], string_pool, platform);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}

} //end of anonymous namespace

void mtac::Optimizer::optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);

    if(configuration->option_defined("fglobal-optimization")){
        bool optimized = false;
        do{
            mtac::remove_unused_functions(program);

            optimize_all_functions(program, string_pool, platform, configuration);

            optimized = mtac::remove_empty_functions(program);
            optimized = mtac::inline_functions(program, configuration);
        } while(optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        basic_optimize(program, string_pool, configuration);
    }

    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);
}

void mtac::Optimizer::basic_optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> /*string_pool*/, std::shared_ptr<Configuration> configuration) const {
    PerfsTimer timer("Whole basic optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("single-threaded")){
        for(auto& function : functions){
            basic_optimize_function(function);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    basic_optimize_function(functions[i]);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>
#include <type_traits>

#include "boost_cfg.hpp"
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>

#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"
#include "timing.hpp"
#include "GlobalContext.hpp"

#include "ltac/Statement.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/ControlFlowGraph.hpp"
#include "mtac/Quadruple.hpp"

//The custom optimizations
#include "mtac/conditional_propagation.hpp"
#include "mtac/remove_aliases.hpp"
#include "mtac/clean_variables.hpp"
#include "mtac/remove_unused_functions.hpp"
#include "mtac/remove_empty_functions.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/merge_basic_blocks.hpp"
#include "mtac/remove_dead_basic_blocks.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_analysis.hpp"
#include "mtac/induction_variable_optimizations.hpp"
#include "mtac/loop_unrolling.hpp"
#include "mtac/complete_loop_peeling.hpp"
#include "mtac/remove_empty_loops.hpp"
#include "mtac/loop_invariant_code_motion.hpp"
#include "mtac/parameter_propagation.hpp"
#include "mtac/pure_analysis.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

#include "ltac/Register.hpp"
#include "ltac/FloatRegister.hpp"
#include "ltac/PseudoRegister.hpp"
#include "ltac/PseudoFloatRegister.hpp"
#include "ltac/Address.hpp"

using namespace eddic;

namespace eddic {
namespace mtac {

typedef boost::mpl::vector<
        mtac::ConstantFolding*
    > basic_passes;

struct all_basic_optimizations {};

template<>
struct pass_traits<all_basic_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_basic_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef basic_passes sub_passes;
};

typedef boost::mpl::vector<
        mtac::ArithmeticIdentities*,
        mtac::ReduceInStrength*,
        mtac::ConstantFolding*,
        mtac::conditional_propagation*,
        mtac::ConstantPropagationProblem*,
        mtac::OffsetConstantPropagationProblem*,
        mtac::CommonSubexpressionElimination*,
        mtac::PointerPropagation*,
        mtac::MathPropagation*,
        mtac::optimize_branches*,
        mtac::remove_dead_basic_blocks*,
        mtac::merge_basic_blocks*,
        mtac::dead_code_elimination*,
        mtac::remove_aliases*,
        mtac::loop_analysis*,
        mtac::loop_invariant_code_motion*,
        mtac::loop_induction_variables_optimization*,
        mtac::remove_empty_loops*,
        mtac::complete_loop_peeling*,
        mtac::loop_unrolling*,
        mtac::clean_variables*
    > passes;

struct all_optimizations {};

template<>
struct pass_traits<all_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef passes sub_passes;
};

}
}

namespace {

template<typename T, typename Sign>
struct has_gate {
    typedef char yes[1];
    typedef char no [2];
    template <typename U, U> struct type_check;
    template <typename _1> static yes &chk(type_check<Sign, &_1::gate> *);
    template <typename   > static no  &chk(...);
    static bool const value = sizeof(chk<T>(0)) == sizeof(yes);
};

typedef boost::mpl::vector<
        mtac::remove_unused_functions*,
        mtac::all_basic_optimizations*
    > ipa_basic_passes;

typedef boost::mpl::vector<
        mtac::remove_unused_functions*,
        mtac::pure_analysis*,
        mtac::all_optimizations*,
        mtac::remove_empty_functions*,
        mtac::remove_unused_functions*,
        mtac::inline_functions*,
        mtac::parameter_propagation*
    > ipa_passes;

template<typename Pass>
struct need_pool {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_POOL;
};

template<typename Pass>
struct need_platform {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_PLATFORM;
};

template<typename Pass>
struct need_configuration {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_CONFIGURATION;
};

template<typename Pass>
struct need_program {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_PROGRAM;
};

template <bool B, typename T = void>
struct disable_if {
    typedef T type;
};

template <typename T>
struct disable_if<true,T> {
    //SFINAE
};

struct pass_runner {
    bool optimized = false;

    mtac::Program& program;
    mtac::Function* function;

    std::shared_ptr<StringPool> pool;
    std::shared_ptr<Configuration> configuration;
    Platform platform;
    timing_system& system;

    pass_runner(mtac::Program& program, std::shared_ptr<StringPool> pool, std::shared_ptr<Configuration> configuration, Platform platform, timing_system& system) :
            program(program), pool(pool), configuration(configuration), platform(platform), system(system) {};

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP, void>::type remove_nop(){
        for(auto& block : *function){
            auto it = iterate(block->statements);

            while(it.has_next()){
                if(it->op == mtac::Operator::NOP){
                    it.erase();
                    continue;
                }

                ++it;
            }
        }
    }

    template<typename Pass>
    inline typename std::enable_if<!(mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP), void>::type remove_nop(){
        //NOP
    }

    template<typename Pass>
    inline void apply_todo(){
        remove_nop<Pass>();
    }

    template<typename Pass>
    inline typename std::enable_if<need_pool<Pass>::value, void>::type set_pool(Pass& pass){
        pass.set_pool(pool);
    }

    template<typename Pass>
    inline typename disable_if<need_pool<Pass>::value, void>::type set_pool(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_platform<Pass>::value, void>::type set_platform(Pass& pass){
        pass.set_platform(platform);
    }

    template<typename Pass>
    inline typename disable_if<need_platform<Pass>::value, void>::type set_platform(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass& pass){
        pass.set_configuration(configuration);
    }

    template<typename Pass>
    inline typename disable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_program<Pass>::value, Pass>::type construct(){
        return Pass(program);
    }

    template<typename Pass>
    inline typename disable_if<need_program<Pass>::value, Pass>::type construct(){
        return Pass();
    }

    template<typename Pass>
    Pass make_pass(){
        auto pass = construct<Pass>();

        set_pool(pass);
        set_platform(pass);
        set_configuration(pass);

        return pass;
    }

    template<typename Pass>
    inline typename std::enable_if<has_gate<Pass, bool(Pass::*)(std::shared_ptr<Configuration>)>::value, bool>::type has_to_be_run(Pass& pass){
        return pass.gate(configuration);
    }

    template<typename Pass>
    inline typename disable_if<has_gate<Pass, bool(Pass::*)(std::shared_ptr<Configuration>)>::value, bool>::type has_to_be_run(Pass&){
        return true;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, bool>::type apply(Pass& pass){
        return pass(program);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB, bool>::type apply(Pass&){
        for(auto& function : program.functions){
            this->function = &function;

            if(log::enabled<Debug>()){
                LOG<Debug>("Optimizer") << "Start optimizations on " << function.get_name() << log::endl;

                std::cout << function << std::endl;
            }

            boost::mpl::for_each<typename mtac::pass_traits<Pass>::sub_passes>(boost::ref(*this));
        }

        return false;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::CUSTOM, bool>::type apply(Pass& pass){
        return pass(*function);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::LOCAL, bool>::type apply(Pass& visitor){
        for(auto& block : *function){
            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }
        }

        return visitor.optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::DATA_FLOW, bool>::type apply(Pass& problem){
        auto results = mtac::data_flow(*function, problem);

        //Once the data-flow problem is fixed, statements can be optimized
        return problem.optimize(*function, results);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB, bool>::type apply(Pass& visitor){
        bool optimized = false;

        for(auto& block : *function){
            visitor.clear();

            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB_TWO_PASS, bool>::type apply(Pass& visitor){
        bool optimized = false;

        for(auto& block : *function){
            visitor.clear();

            visitor.pass = mtac::Pass::DATA_MINING;
            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }

            visitor.pass = mtac::Pass::OPTIMIZE;
            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_or<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned " << local << log::endl;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_and<mtac::pass_traits<Pass>::type != mtac::pass_type::IPA, mtac::pass_traits<Pass>::type != mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        if(log::enabled<Debug>()){
            if(local){
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned true" << log::endl;

                //Print the function
                std::cout << *function << std::endl;
            } else {
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned false" << log::endl;
            }
        }
    }

    template<typename Pass>
    inline void operator()(Pass*){
        auto pass = make_pass<Pass>();

        if(has_to_be_run(pass)){
            bool local = false;
            {
                PerfsTimer perfs_timer(mtac::pass_traits<Pass>::name());
                timing_timer timer(system, mtac::pass_traits<Pass>::name());

                local = apply<Pass>(pass);
            }

            if(local){
                program.context->stats().inc_counter(std::string(mtac::pass_traits<Pass>::name()) + "_true");
                apply_todo<Pass>();
            }

            debug_local<Pass>(local);

            optimized |= local;
        }
    }
};

} //end of anonymous namespace

void mtac::Optimizer::optimize(mtac::Program& program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    timing_timer timer(program.context->timing(), "whole_optimizations");

    //Build the CFG of each functions (also needed for register allocation)
    for(auto& function : program.functions){
        mtac::build_control_flow_graph(function);
    }

    if(configuration->option_defined("fglobal-optimization")){
        //Apply Interprocedural Optimizations
        pass_runner runner(program, string_pool, configuration, platform, program.context->timing());
        do{
            runner.optimized = false;
            boost::mpl::for_each<ipa_passes>(boost::ref(runner));
        } while(runner.optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        pass_runner runner(program, string_pool, configuration, platform, program.context->timing());
        boost::mpl::for_each<ipa_basic_passes>(boost::ref(runner));
    }
}
<commit_msg>Time the construction of the CFGs<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>
#include <type_traits>

#include "boost_cfg.hpp"
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>

#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"
#include "timing.hpp"
#include "GlobalContext.hpp"

#include "ltac/Statement.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/ControlFlowGraph.hpp"
#include "mtac/Quadruple.hpp"

//The custom optimizations
#include "mtac/conditional_propagation.hpp"
#include "mtac/remove_aliases.hpp"
#include "mtac/clean_variables.hpp"
#include "mtac/remove_unused_functions.hpp"
#include "mtac/remove_empty_functions.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/merge_basic_blocks.hpp"
#include "mtac/remove_dead_basic_blocks.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_analysis.hpp"
#include "mtac/induction_variable_optimizations.hpp"
#include "mtac/loop_unrolling.hpp"
#include "mtac/complete_loop_peeling.hpp"
#include "mtac/remove_empty_loops.hpp"
#include "mtac/loop_invariant_code_motion.hpp"
#include "mtac/parameter_propagation.hpp"
#include "mtac/pure_analysis.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

#include "ltac/Register.hpp"
#include "ltac/FloatRegister.hpp"
#include "ltac/PseudoRegister.hpp"
#include "ltac/PseudoFloatRegister.hpp"
#include "ltac/Address.hpp"

using namespace eddic;

namespace eddic {
namespace mtac {

typedef boost::mpl::vector<
        mtac::ConstantFolding*
    > basic_passes;

struct all_basic_optimizations {};

template<>
struct pass_traits<all_basic_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_basic_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef basic_passes sub_passes;
};

typedef boost::mpl::vector<
        mtac::ArithmeticIdentities*,
        mtac::ReduceInStrength*,
        mtac::ConstantFolding*,
        mtac::conditional_propagation*,
        mtac::ConstantPropagationProblem*,
        mtac::OffsetConstantPropagationProblem*,
        mtac::CommonSubexpressionElimination*,
        mtac::PointerPropagation*,
        mtac::MathPropagation*,
        mtac::optimize_branches*,
        mtac::remove_dead_basic_blocks*,
        mtac::merge_basic_blocks*,
        mtac::dead_code_elimination*,
        mtac::remove_aliases*,
        mtac::loop_analysis*,
        mtac::loop_invariant_code_motion*,
        mtac::loop_induction_variables_optimization*,
        mtac::remove_empty_loops*,
        mtac::complete_loop_peeling*,
        mtac::loop_unrolling*,
        mtac::clean_variables*
    > passes;

struct all_optimizations {};

template<>
struct pass_traits<all_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef passes sub_passes;
};

}
}

namespace {

template<typename T, typename Sign>
struct has_gate {
    typedef char yes[1];
    typedef char no [2];
    template <typename U, U> struct type_check;
    template <typename _1> static yes &chk(type_check<Sign, &_1::gate> *);
    template <typename   > static no  &chk(...);
    static bool const value = sizeof(chk<T>(0)) == sizeof(yes);
};

typedef boost::mpl::vector<
        mtac::remove_unused_functions*,
        mtac::all_basic_optimizations*
    > ipa_basic_passes;

typedef boost::mpl::vector<
        mtac::remove_unused_functions*,
        mtac::pure_analysis*,
        mtac::all_optimizations*,
        mtac::remove_empty_functions*,
        mtac::remove_unused_functions*,
        mtac::inline_functions*,
        mtac::parameter_propagation*
    > ipa_passes;

template<typename Pass>
struct need_pool {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_POOL;
};

template<typename Pass>
struct need_platform {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_PLATFORM;
};

template<typename Pass>
struct need_configuration {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_CONFIGURATION;
};

template<typename Pass>
struct need_program {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_PROGRAM;
};

template <bool B, typename T = void>
struct disable_if {
    typedef T type;
};

template <typename T>
struct disable_if<true,T> {
    //SFINAE
};

struct pass_runner {
    bool optimized = false;

    mtac::Program& program;
    mtac::Function* function;

    std::shared_ptr<StringPool> pool;
    std::shared_ptr<Configuration> configuration;
    Platform platform;
    timing_system& system;

    pass_runner(mtac::Program& program, std::shared_ptr<StringPool> pool, std::shared_ptr<Configuration> configuration, Platform platform, timing_system& system) :
            program(program), pool(pool), configuration(configuration), platform(platform), system(system) {};

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP, void>::type remove_nop(){
        for(auto& block : *function){
            auto it = iterate(block->statements);

            while(it.has_next()){
                if(it->op == mtac::Operator::NOP){
                    it.erase();
                    continue;
                }

                ++it;
            }
        }
    }

    template<typename Pass>
    inline typename std::enable_if<!(mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP), void>::type remove_nop(){
        //NOP
    }

    template<typename Pass>
    inline void apply_todo(){
        remove_nop<Pass>();
    }

    template<typename Pass>
    inline typename std::enable_if<need_pool<Pass>::value, void>::type set_pool(Pass& pass){
        pass.set_pool(pool);
    }

    template<typename Pass>
    inline typename disable_if<need_pool<Pass>::value, void>::type set_pool(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_platform<Pass>::value, void>::type set_platform(Pass& pass){
        pass.set_platform(platform);
    }

    template<typename Pass>
    inline typename disable_if<need_platform<Pass>::value, void>::type set_platform(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass& pass){
        pass.set_configuration(configuration);
    }

    template<typename Pass>
    inline typename disable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_program<Pass>::value, Pass>::type construct(){
        return Pass(program);
    }

    template<typename Pass>
    inline typename disable_if<need_program<Pass>::value, Pass>::type construct(){
        return Pass();
    }

    template<typename Pass>
    Pass make_pass(){
        auto pass = construct<Pass>();

        set_pool(pass);
        set_platform(pass);
        set_configuration(pass);

        return pass;
    }

    template<typename Pass>
    inline typename std::enable_if<has_gate<Pass, bool(Pass::*)(std::shared_ptr<Configuration>)>::value, bool>::type has_to_be_run(Pass& pass){
        return pass.gate(configuration);
    }

    template<typename Pass>
    inline typename disable_if<has_gate<Pass, bool(Pass::*)(std::shared_ptr<Configuration>)>::value, bool>::type has_to_be_run(Pass&){
        return true;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, bool>::type apply(Pass& pass){
        return pass(program);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB, bool>::type apply(Pass&){
        for(auto& function : program.functions){
            this->function = &function;

            if(log::enabled<Debug>()){
                LOG<Debug>("Optimizer") << "Start optimizations on " << function.get_name() << log::endl;

                std::cout << function << std::endl;
            }

            boost::mpl::for_each<typename mtac::pass_traits<Pass>::sub_passes>(boost::ref(*this));
        }

        return false;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::CUSTOM, bool>::type apply(Pass& pass){
        return pass(*function);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::LOCAL, bool>::type apply(Pass& visitor){
        for(auto& block : *function){
            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }
        }

        return visitor.optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::DATA_FLOW, bool>::type apply(Pass& problem){
        auto results = mtac::data_flow(*function, problem);

        //Once the data-flow problem is fixed, statements can be optimized
        return problem.optimize(*function, results);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB, bool>::type apply(Pass& visitor){
        bool optimized = false;

        for(auto& block : *function){
            visitor.clear();

            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB_TWO_PASS, bool>::type apply(Pass& visitor){
        bool optimized = false;

        for(auto& block : *function){
            visitor.clear();

            visitor.pass = mtac::Pass::DATA_MINING;
            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }

            visitor.pass = mtac::Pass::OPTIMIZE;
            for(auto& quadruple : block->statements){
                visitor(quadruple);
            }

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_or<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned " << local << log::endl;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_and<mtac::pass_traits<Pass>::type != mtac::pass_type::IPA, mtac::pass_traits<Pass>::type != mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        if(log::enabled<Debug>()){
            if(local){
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned true" << log::endl;

                //Print the function
                std::cout << *function << std::endl;
            } else {
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned false" << log::endl;
            }
        }
    }

    template<typename Pass>
    inline void operator()(Pass*){
        auto pass = make_pass<Pass>();

        if(has_to_be_run(pass)){
            bool local = false;
            {
                PerfsTimer perfs_timer(mtac::pass_traits<Pass>::name());
                timing_timer timer(system, mtac::pass_traits<Pass>::name());

                local = apply<Pass>(pass);
            }

            if(local){
                program.context->stats().inc_counter(std::string(mtac::pass_traits<Pass>::name()) + "_true");
                apply_todo<Pass>();
            }

            debug_local<Pass>(local);

            optimized |= local;
        }
    }
};

} //end of anonymous namespace

void mtac::Optimizer::optimize(mtac::Program& program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    timing_timer timer(program.context->timing(), "whole_optimizations");

    //Build the CFG of each functions (also needed for register allocation)
    for(auto& function : program.functions){
        timing_timer timer(program.context->timing(), "build_cfg");
        mtac::build_control_flow_graph(function);
    }

    if(configuration->option_defined("fglobal-optimization")){
        //Apply Interprocedural Optimizations
        pass_runner runner(program, string_pool, configuration, platform, program.context->timing());
        do{
            runner.optimized = false;
            boost::mpl::for_each<ipa_passes>(boost::ref(runner));
        } while(runner.optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        pass_runner runner(program, string_pool, configuration, platform, program.context->timing());
        boost::mpl::for_each<ipa_basic_passes>(boost::ref(runner));
    }
}
<|endoftext|>


<commit_before>#ifndef MUNCHAR_TOKENS
#define MUNCHAR_TOKENS

#include "munchar.hpp"
#include <cctype>

namespace Munchar {
  namespace Tokens {

    constexpr auto null          = CHR('\0');
    constexpr auto tab           = CHR('\t');
    constexpr auto newline       = CHR('\n');
    constexpr auto linefeed      = newline;
    constexpr auto cr            = CHR('\r');
    constexpr auto crlf          = STR("\r\n");

    constexpr auto space         = CHR(' ');
    constexpr auto exclamation   = CHR('!');
    constexpr auto double_quote  = CHR('"');
    constexpr auto quote         = double_quote;
    constexpr auto pound         = CHR('#');
    constexpr auto hash          = pound;
    constexpr auto octothorpe    = pound;
    constexpr auto dollar        = CHR('$');
    constexpr auto percent       = CHR('%');
    constexpr auto ampersand     = CHR('&');
    constexpr auto apostrophe    = CHR('\'');
    constexpr auto single_quote  = apostrophe;
    constexpr auto left_paren    = CHR('(');
    constexpr auto right_paren   = CHR(')');
    constexpr auto asterisk      = CHR('*');
    constexpr auto plus          = CHR('+');
    constexpr auto comma         = CHR(',');
    constexpr auto hyphen        = CHR('-');
    constexpr auto minus         = hyphen;
    constexpr auto period        = CHR('.');
    constexpr auto dot           = period;
    constexpr auto slash         = CHR('/');
    constexpr auto divide        = slash;
    constexpr auto colon         = CHR(':');
    constexpr auto semicolon     = CHR(';');
    constexpr auto less_than     = CHR('<');
    constexpr auto lt            = less_than;
    constexpr auto lte           = STR("<=");
    constexpr auto equals        = CHR('=');
    constexpr auto eq            = equals;
    constexpr auto greater_than  = CHR('>');
    constexpr auto gt            = greater_than;
    constexpr auto gte           = STR(">=");
    constexpr auto question      = CHR('?');
    constexpr auto at            = CHR('@');
    constexpr auto left_bracket  = CHR('[');
    constexpr auto backslash     = CHR('\\');
    constexpr auto right_bracket = CHR(']');
    constexpr auto caret         = CHR('^');
    constexpr auto circumflex    = caret;
    constexpr auto underscore    = CHR('_');
    constexpr auto backquote     = CHR('`');
    constexpr auto left_brace    = CHR('{');
    constexpr auto vertical_bar  = CHR('|');
    constexpr auto pipe          = vertical_bar;
    constexpr auto right_brace   = CHR('}');
    constexpr auto tilde         = CHR('~');

    constexpr auto _             = Any_Char { };
    constexpr auto letter        = MUNCHAR_STATIC_PREDICATE(::isalpha);
    constexpr auto alphanumeric  = MUNCHAR_STATIC_PREDICATE(::isalnum);
    constexpr auto digit         = MUNCHAR_STATIC_PREDICATE(::isdigit);
    constexpr auto hex_digit     = MUNCHAR_STATIC_PREDICATE(::isxdigit);
    constexpr auto ws_char       = MUNCHAR_STATIC_PREDICATE(::isspace);
    constexpr auto whitespace    = *ws_char;
    constexpr auto sign          = CLS("+-");
    constexpr auto id_start      = letter | underscore;
    constexpr auto id_body       = alphanumeric | underscore;
    constexpr auto identifier    = id_start^*id_body;
    constexpr auto integer       = ~sign ^ +digit;
    constexpr auto number_ne     = ~sign ^ ((*digit ^ dot ^ +digit) | +digit);
    constexpr auto number        = number_ne ^ ~(CLS("eE") ^ ~sign ^ +digit);
    constexpr auto escape_seq    = backslash ^ _;
    constexpr auto dq_string     = double_quote ^
                                   *(escape_seq | (!CLS("\"\\") ^ _)) ^
                                   double_quote;
    constexpr auto sq_string     = single_quote ^
                                   *(escape_seq | (!CLS("'\\") ^ _)) ^
                                   single_quote;
    constexpr auto string        = dq_string | sq_string;
    constexpr auto eol           = newline | crlf;
    constexpr auto cpp_comment   = STR("//") ^ *(!eol ^ _) ^ ~eol;
    constexpr auto c_comment     = STR("/*") ^ *(!STR("*/") ^ _) ^ STR("*/");
    constexpr auto sh_comment    = CHR('#') ^ *(!eol ^ _) ^ ~eol;

    constexpr auto ellipsis            = STR("...");
    constexpr auto right_arrow         = STR("->");
    constexpr auto lisp_true           = STR("#t") | STR("#T");
    constexpr auto lisp_false          = STR("#f") | STR("#F");
    constexpr auto boolean             = lisp_true | lisp_false;
    constexpr auto lisp_id_start       = letter | underscore | hyphen | exclamation | dollar | percent | ampersand | asterisk | slash | colon | less_than | eq | greater_than | question | caret | tilde;
    constexpr auto lisp_id_body        = alphanumeric | lisp_id_start | plus | minus | dot | at;
    constexpr auto peculiar_identifier = plus | minus | ellipsis | right_arrow^*lisp_id_body;
    constexpr auto lisp_identifier     = lisp_id_start^*lisp_id_body | peculiar_identifier;

  }
}

#endif<commit_msg>getting ready to take out some unnecessary munchar definitions<commit_after>#ifndef MUNCHAR_TOKENS
#define MUNCHAR_TOKENS

#include "munchar.hpp"
#include <cctype>

namespace Munchar {
  namespace Tokens {

    constexpr auto null          = CHR('\0');
    constexpr auto tab           = CHR('\t');
    constexpr auto newline       = CHR('\n');
    constexpr auto linefeed      = newline;
    constexpr auto cr            = CHR('\r');
    constexpr auto crlf          = STR("\r\n");

    constexpr auto space         = CHR(' ');
    constexpr auto exclamation   = CHR('!');
    constexpr auto double_quote  = CHR('"');
    constexpr auto quote         = double_quote;
    constexpr auto pound         = CHR('#');
    constexpr auto hash          = pound;
    constexpr auto octothorpe    = pound;
    constexpr auto dollar        = CHR('$');
    constexpr auto percent       = CHR('%');
    constexpr auto ampersand     = CHR('&');
    constexpr auto apostrophe    = CHR('\'');
    constexpr auto single_quote  = apostrophe;
    constexpr auto left_paren    = CHR('(');
    constexpr auto right_paren   = CHR(')');
    constexpr auto asterisk      = CHR('*');
    constexpr auto plus          = CHR('+');
    constexpr auto comma         = CHR(',');
    constexpr auto hyphen        = CHR('-');
    constexpr auto minus         = hyphen;
    constexpr auto period        = CHR('.');
    constexpr auto dot           = period;
    constexpr auto slash         = CHR('/');
    constexpr auto divide        = slash;
    constexpr auto colon         = CHR(':');
    constexpr auto semicolon     = CHR(';');
    constexpr auto less_than     = CHR('<');
    constexpr auto lt            = less_than;
    constexpr auto lte           = STR("<=");
    constexpr auto equals        = CHR('=');
    constexpr auto eq            = equals;
    constexpr auto greater_than  = CHR('>');
    constexpr auto gt            = greater_than;
    constexpr auto gte           = STR(">=");
    constexpr auto question      = CHR('?');
    constexpr auto at            = CHR('@');
    constexpr auto left_bracket  = CHR('[');
    constexpr auto backslash     = CHR('\\');
    constexpr auto right_bracket = CHR(']');
    constexpr auto caret         = CHR('^');
    constexpr auto circumflex    = caret;
    constexpr auto underscore    = CHR('_');
    constexpr auto backquote     = CHR('`');
    constexpr auto left_brace    = CHR('{');
    constexpr auto vertical_bar  = CHR('|');
    constexpr auto pipe          = vertical_bar;
    constexpr auto right_brace   = CHR('}');
    constexpr auto tilde         = CHR('~');

    constexpr auto _             = Any_Char { };
    constexpr auto letter        = MUNCHAR_STATIC_PREDICATE(::isalpha);
    constexpr auto alphanumeric  = MUNCHAR_STATIC_PREDICATE(::isalnum);
    constexpr auto digit         = MUNCHAR_STATIC_PREDICATE(::isdigit);
    constexpr auto hex_digit     = MUNCHAR_STATIC_PREDICATE(::isxdigit);
    constexpr auto ws_char       = MUNCHAR_STATIC_PREDICATE(::isspace);
    constexpr auto whitespace    = *ws_char;
    constexpr auto sign          = CLS("+-");
    constexpr auto id_start      = letter | underscore;
    constexpr auto id_body       = alphanumeric | underscore;
    constexpr auto identifier    = id_start^*id_body;
    constexpr auto integer       = ~sign ^ +digit;
    constexpr auto number_ne     = ~sign ^ ((*digit ^ dot ^ +digit) | +digit);
    constexpr auto number        = number_ne ^ ~(CLS("eE") ^ ~sign ^ +digit);
    constexpr auto escape_seq    = backslash ^ _;
    constexpr auto dq_string     = double_quote ^
                                   *(escape_seq | (!CLS("\"\\") ^ _)) ^
                                   double_quote;
    constexpr auto sq_string     = single_quote ^
                                   *(escape_seq | (!CLS("'\\") ^ _)) ^
                                   single_quote;
    constexpr auto string        = dq_string | sq_string;
    constexpr auto eol           = newline | crlf;
    constexpr auto cpp_comment   = STR("//") ^ *(!eol ^ _) ^ ~eol;
    constexpr auto c_comment     = STR("/*") ^ *(!STR("*/") ^ _) ^ STR("*/");
    constexpr auto sh_comment    = CHR('#') ^ *(!eol ^ _) ^ ~eol;

    constexpr auto ellipsis            = STR("...");
    constexpr auto right_arrow         = STR("->");
    constexpr auto lisp_true           = STR("#t") | STR("#T");
    constexpr auto lisp_false          = STR("#f") | STR("#F");
    constexpr auto boolean             = lisp_true | lisp_false;
    constexpr auto lisp_id_start       = letter | underscore | hyphen | exclamation | dollar | percent | ampersand | asterisk | slash | colon | less_than | eq | greater_than | question | caret | tilde;
    constexpr auto lisp_id_body        = alphanumeric | lisp_id_start | plus | minus | dot | at;
    constexpr auto peculiar_identifier = plus | minus | ellipsis | right_arrow^*lisp_id_body;
    constexpr auto lisp_identifier     = lisp_id_start^*lisp_id_body | peculiar_identifier;

    // constexpr auto lparen = CHR('(');
    // constexpr auto rparen = CHR(')');
    // constexpr auto hash = CHR('#');
    // constexpr auto quote = CHR('\'');
    // constexpr auto hash_t = hash ^ CLS("tT");
    // constexpr auto hash_f = hash ^ CLS("fF");
    // constexpr auto boolean = hash ^ CLS("tfTF");
    // constexpr auto string = double_quote ^
    //                         *(escape_seq | (!CLS("\"\\") ^ _)) ^
    //                         double_quote;

  }
}

#endif<|endoftext|>


<commit_before>#include "trainer.h"
#include "common/timer.h"
#include "common/logger.h"
#include "optimize/opt_gd.hpp"
#include "optimize/opt_cgd.hpp"
#include "optimize/opt_lbfgs.hpp"
#include "sampler.h"
#include "accumulator.h"

namespace ncv
{
        /////////////////////////////////////////////////////////////////////////////////////////

        trainer_state_t::trainer_state_t(size_t n_parameters)
                :       m_params(n_parameters),
                        m_tvalue(std::numeric_limits<scalar_t>::max()),
                        m_terror(std::numeric_limits<scalar_t>::max()),
                        m_vvalue(std::numeric_limits<scalar_t>::max()),
                        m_verror(std::numeric_limits<scalar_t>::max()),
                        m_lambda(std::numeric_limits<scalar_t>::max())
        {
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_state_t::update(const vector_t& params,
                    scalar_t tvalue, scalar_t terror,
                    scalar_t vvalue, scalar_t verror,
                    scalar_t lambda)
        {
                if (verror < m_verror)
                {
                        m_params = params;
                        m_tvalue = tvalue;
                        m_terror = terror;
                        m_vvalue = vvalue;
                        m_verror = verror;
                        m_lambda = lambda;
                        return true;
                }

                else
                {
                        return false;
                }
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_state_t::update(const trainer_state_t& state)
        {
                return update(state.m_params,
                              state.m_tvalue, state.m_terror, state.m_vvalue, state.m_verror,
                              state.m_lambda);
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_t::train(
                const task_t& task, const sampler_t& tsampler, const sampler_t& vsampler, size_t nthreads,
                const loss_t& loss, const string_t& optimizer, size_t iterations, scalar_t epsilon,
                const model_t& model, trainer_state_t& state)
        {
                // L2-norm regularization
                const scalars_t lambdas = { 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1.0 };
                for (scalar_t lambda : lambdas)
                {
                        accumulator_t ldata(model, accumulator_t::type::value, lambda);
                        accumulator_t gdata(model, accumulator_t::type::vgrad, lambda);

                        trainer_t::train(task, tsampler, vsampler, nthreads,
                                         loss, optimizer, iterations, epsilon,
                                         model.params(), ldata, gdata, state);
                }

                log_info() << "optimum [train = " << state.m_tvalue << "/" << state.m_terror
                           << ", valid = " << state.m_vvalue << "/" << state.m_verror
                           << ", lambda = " << state.m_lambda
                           << "].";

                // OK
                return true;
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_t::train(
                const task_t& task, const sampler_t& tsampler, const sampler_t& vsampler, size_t nthreads,
                const loss_t& loss, const string_t& optimizer, size_t iterations, scalar_t epsilon,
                const vector_t& x0, accumulator_t& ldata, accumulator_t& gdata, trainer_state_t& state)
        {
                samples_t utsamples = tsampler.get();
                samples_t uvsamples = vsampler.get();

                // construct the optimization problem
                const timer_t timer;

                auto fn_size = [&] ()
                {
                        return ldata.dimensions();
                };

                auto fn_fval = [&] (const vector_t& x)
                {
                        // training samples: loss value
                        ldata.reset(x);
                        ldata.update(task, utsamples, loss, nthreads);
                        const scalar_t tvalue = ldata.value();

                        return tvalue;
                };

                auto fn_fval_grad = [&] (const vector_t& x, vector_t& gx)
                {
                        // stochastic mode: resample training & validation samples
                        if (tsampler.is_random())
                        {
                                utsamples = tsampler.get();
                        }
                        if (vsampler.is_random())
                        {
                                uvsamples = vsampler.get();
                        }

                        // training samples: loss value & gradient
                        gdata.reset(x);
                        gdata.update(task, utsamples, loss, nthreads);
                        const scalar_t tvalue = gdata.value();
                        const scalar_t terror = gdata.error();
                        gx = gdata.vgrad();

                        // validation samples: loss value
                        ldata.reset(x);
                        ldata.update(task, uvsamples, loss, nthreads);
                        const scalar_t vvalue = ldata.value();
                        const scalar_t verror = ldata.error();

                        // update the optimum state
                        state.update(x, tvalue, terror, vvalue, verror, ldata.lambda());

                        log_info() << "[grad = " << gx.lpNorm<Eigen::Infinity>()
                                   << ", train = " << tvalue << "/" << terror
                                   << ", valid = " << vvalue << "/" << verror
                                   << ", lambda = " << ldata.lambda()
                                   << "] done in " << timer.elapsed() << ".";

                        return tvalue;
                };

                auto fn_wlog = [] (const string_t& message)
                {
                        log_warning() << message;
                };
                auto fn_elog = [] (const string_t& message)
                {
                        log_error() << message;
                };
//                auto fn_ulog = [&] (const opt_state_t& result, const timer_t& timer)
//                {
//                        log_info() << "[loss = " << result.f
//                                   << ", grad = " << result.g.lpNorm<Eigen::Infinity>()
//                                   << ", funs = " << result.n_fval_calls() << "/" << result.n_grad_calls()
//                                   << ", train* = " << state.m_tvalue << "/" << state.m_terror
//                                   << ", valid* = " << state.m_vvalue << "/" << state.m_verror
//                                   << ", lambda* = " << ldata.lambda() << "/" << state.m_lambda
//                                   << "] done in " << timer.elapsed() << ".";
//                };

                // assembly optimization problem & optimize the model
                const opt_problem_t problem(fn_size, fn_fval, fn_fval_grad);

//                const opt_opulog_t fn_ulog_ref = std::bind(fn_ulog, _1, std::ref(timer));

                if (text::iequals(optimizer, "lbfgs"))
                {
                        optimize::lbfgs(problem, x0, iterations, epsilon, fn_wlog, fn_elog/*, fn_ulog_ref*/);
                }
                else if (text::iequals(optimizer, "cgd"))
                {
                        optimize::cgd_hs(problem, x0, iterations, epsilon, fn_wlog, fn_elog/*, fn_ulog_ref*/);
                }
                else if (text::iequals(optimizer, "gd"))
                {
                        optimize::gd(problem, x0, iterations, epsilon, fn_wlog, fn_elog/*, fn_ulog_ref*/);
                }
                else
                {
                        log_error() << "trainer: invalid optimization method <" << optimizer << ">!";
                        return false;
                }

                // OK
                return true;
        }

        /////////////////////////////////////////////////////////////////////////////////////////
}

<commit_msg>optimization logging<commit_after>#include "trainer.h"
#include "common/timer.h"
#include "common/logger.h"
#include "optimize/opt_gd.hpp"
#include "optimize/opt_cgd.hpp"
#include "optimize/opt_lbfgs.hpp"
#include "sampler.h"
#include "accumulator.h"

namespace ncv
{
        /////////////////////////////////////////////////////////////////////////////////////////

        trainer_state_t::trainer_state_t(size_t n_parameters)
                :       m_params(n_parameters),
                        m_tvalue(std::numeric_limits<scalar_t>::max()),
                        m_terror(std::numeric_limits<scalar_t>::max()),
                        m_vvalue(std::numeric_limits<scalar_t>::max()),
                        m_verror(std::numeric_limits<scalar_t>::max()),
                        m_lambda(std::numeric_limits<scalar_t>::max())
        {
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_state_t::update(const vector_t& params,
                    scalar_t tvalue, scalar_t terror,
                    scalar_t vvalue, scalar_t verror,
                    scalar_t lambda)
        {
                if (verror < m_verror)
                {
                        m_params = params;
                        m_tvalue = tvalue;
                        m_terror = terror;
                        m_vvalue = vvalue;
                        m_verror = verror;
                        m_lambda = lambda;
                        return true;
                }

                else
                {
                        return false;
                }
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_state_t::update(const trainer_state_t& state)
        {
                return update(state.m_params,
                              state.m_tvalue, state.m_terror, state.m_vvalue, state.m_verror,
                              state.m_lambda);
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_t::train(
                const task_t& task, const sampler_t& tsampler, const sampler_t& vsampler, size_t nthreads,
                const loss_t& loss, const string_t& optimizer, size_t iterations, scalar_t epsilon,
                const model_t& model, trainer_state_t& state)
        {
                // L2-norm regularization
                const scalars_t lambdas = { 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1.0 };
                for (scalar_t lambda : lambdas)
                {
                        accumulator_t ldata(model, accumulator_t::type::value, lambda);
                        accumulator_t gdata(model, accumulator_t::type::vgrad, lambda);

                        trainer_t::train(task, tsampler, vsampler, nthreads,
                                         loss, optimizer, iterations, epsilon,
                                         model.params(), ldata, gdata, state);
                }

                log_info() << "optimum [train = " << state.m_tvalue << "/" << state.m_terror
                           << ", valid = " << state.m_vvalue << "/" << state.m_verror
                           << ", lambda = " << state.m_lambda
                           << "].";

                // OK
                return true;
        }

        /////////////////////////////////////////////////////////////////////////////////////////

        bool trainer_t::train(
                const task_t& task, const sampler_t& tsampler, const sampler_t& vsampler, size_t nthreads,
                const loss_t& loss, const string_t& optimizer, size_t iterations, scalar_t epsilon,
                const vector_t& x0, accumulator_t& ldata, accumulator_t& gdata, trainer_state_t& state)
        {
                samples_t utsamples = tsampler.get();
                samples_t uvsamples = vsampler.get();

                // construct the optimization problem
                const timer_t timer;

                auto fn_size = [&] ()
                {
                        return ldata.dimensions();
                };

                auto fn_fval = [&] (const vector_t& x)
                {
                        // training samples: loss value
                        ldata.reset(x);
                        ldata.update(task, utsamples, loss, nthreads);
                        const scalar_t tvalue = ldata.value();

                        return tvalue;
                };

                auto fn_fval_grad = [&] (const vector_t& x, vector_t& gx)
                {
                        // stochastic mode: resample training & validation samples
                        if (tsampler.is_random())
                        {
                                utsamples = tsampler.get();
                        }
                        if (vsampler.is_random())
                        {
                                uvsamples = vsampler.get();
                        }

                        // training samples: loss value & gradient
                        gdata.reset(x);
                        gdata.update(task, utsamples, loss, nthreads);
                        const scalar_t tvalue = gdata.value();
                        const scalar_t terror = gdata.error();
                        gx = gdata.vgrad();

                        // validation samples: loss value
                        ldata.reset(x);
                        ldata.update(task, uvsamples, loss, nthreads);
                        const scalar_t vvalue = ldata.value();
                        const scalar_t verror = ldata.error();

                        // update the optimum state
                        state.update(x, tvalue, terror, vvalue, verror, ldata.lambda());
                        return tvalue;
                };

                auto fn_wlog = [] (const string_t& message)
                {
                        log_warning() << message;
                };
                auto fn_elog = [] (const string_t& message)
                {
                        log_error() << message;
                };
                auto fn_ulog = [&] (const opt_state_t& result, const timer_t& timer)
                {
                        log_info() << "[loss = " << result.f
                                   << ", grad = " << result.g.lpNorm<Eigen::Infinity>()
                                   << ", funs = " << result.n_fval_calls() << "/" << result.n_grad_calls()
                                   << ", train* = " << state.m_tvalue << "/" << state.m_terror
                                   << ", valid* = " << state.m_vvalue << "/" << state.m_verror
                                   << ", lambda* = " << ldata.lambda() << "/" << state.m_lambda
                                   << "] done in " << timer.elapsed() << ".";
                };

                // assembly optimization problem & optimize the model
                const opt_problem_t problem(fn_size, fn_fval, fn_fval_grad);

                const opt_opulog_t fn_ulog_ref = std::bind(fn_ulog, _1, std::ref(timer));

                if (text::iequals(optimizer, "lbfgs"))
                {
                        optimize::lbfgs(problem, x0, iterations, epsilon, fn_wlog, fn_elog, fn_ulog_ref);
                }
                else if (text::iequals(optimizer, "cgd"))
                {
                        optimize::cgd_hs(problem, x0, iterations, epsilon, fn_wlog, fn_elog, fn_ulog_ref);
                }
                else if (text::iequals(optimizer, "gd"))
                {
                        optimize::gd(problem, x0, iterations, epsilon, fn_wlog, fn_elog, fn_ulog_ref);
                }
                else
                {
                        log_error() << "trainer: invalid optimization method <" << optimizer << ">!";
                        return false;
                }

                // OK
                return true;
        }

        /////////////////////////////////////////////////////////////////////////////////////////
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Incognito
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "../natives.h"

#include "../core.h"
#include "../utility.h"

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/unordered_map.hpp>

#include <Eigen/Core>

cell AMX_NATIVE_CALL Natives::CreateDynamicActor(AMX *amx, cell *params)
{
	CHECK_PARAMS(13, "CreateDynamicActor");
	if (core->getData()->getGlobalMaxItems(STREAMER_TYPE_ACTOR) == core->getData()->actors.size())
	{
		return 0;
	}
	int actorID = Item::Actor::identifier.get();
	Item::SharedActor actor(new Item::Actor);
	actor->amx = amx;
	actor->actorID = actorID;
	actor->inverseAreaChecking = false;
	actor->originalComparableStreamDistance = -1.0f;
	actor->modelID = static_cast<int>(params[1]);
	actor->position = Eigen::Vector3f(amx_ctof(params[2]), amx_ctof(params[3]), amx_ctof(params[4]));
	actor->rotation = amx_ctof(params[5]);
	actor->invulnerable = static_cast<int>(params[6]);
	actor->health = amx_ctof(params[7]);
	Utility::addToContainer(actor->worlds, static_cast<int>(params[8]));
	Utility::addToContainer(actor->interiors, static_cast<int>(params[9]));
	Utility::addToContainer(actor->players, static_cast<int>(params[10]));
	actor->comparableStreamDistance = amx_ctof(params[11]) < STREAMER_STATIC_DISTANCE_CUTOFF ? amx_ctof(params[11]) : amx_ctof(params[11]) * amx_ctof(params[11]);
	actor->streamDistance = amx_ctof(params[11]);
	Utility::addToContainer(actor->areas, static_cast<int>(params[12]));
	actor->priority = static_cast<int>(params[13]);
	core->getGrid()->addActor(actor);
	core->getData()->actors.insert(std::make_pair(actorID, actor));
	return static_cast<cell>(actorID);
}

cell AMX_NATIVE_CALL Natives::DestroyDynamicActor(AMX *amx, cell *params)
{
	CHECK_PARAMS(1, "DestroyDynamicActor");
	boost::unordered_map<int, Item::SharedActor>::iterator a = core->getData()->actors.find(static_cast<int>(params[1]));
	if (a != core->getData()->actors.end())
	{
		Utility::destroyActor(a);
		return 1;
	}
	return 0;
}

cell AMX_NATIVE_CALL Natives::IsValidDynamicActor(AMX *amx, cell *params)
{
	CHECK_PARAMS(1, "IsValidDynamicActor");
	boost::unordered_map<int, Item::SharedActor>::iterator a = core->getData()->actors.find(static_cast<int>(params[1]));
	if (a != core->getData()->actors.end())
	{
		return 1;
	}
	return 0;
}
<commit_msg>Fix compilation warning<commit_after>/*
 * Copyright (C) 2016 Incognito
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "../natives.h"

#include "../core.h"
#include "../utility.h"

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/unordered_map.hpp>

#include <Eigen/Core>

cell AMX_NATIVE_CALL Natives::CreateDynamicActor(AMX *amx, cell *params)
{
	CHECK_PARAMS(13, "CreateDynamicActor");
	if (core->getData()->getGlobalMaxItems(STREAMER_TYPE_ACTOR) == core->getData()->actors.size())
	{
		return 0;
	}
	int actorID = Item::Actor::identifier.get();
	Item::SharedActor actor(new Item::Actor);
	actor->amx = amx;
	actor->actorID = actorID;
	actor->inverseAreaChecking = false;
	actor->originalComparableStreamDistance = -1.0f;
	actor->modelID = static_cast<int>(params[1]);
	actor->position = Eigen::Vector3f(amx_ctof(params[2]), amx_ctof(params[3]), amx_ctof(params[4]));
	actor->rotation = amx_ctof(params[5]);
	actor->invulnerable = static_cast<int>(params[6]) != 0;
	actor->health = amx_ctof(params[7]);
	Utility::addToContainer(actor->worlds, static_cast<int>(params[8]));
	Utility::addToContainer(actor->interiors, static_cast<int>(params[9]));
	Utility::addToContainer(actor->players, static_cast<int>(params[10]));
	actor->comparableStreamDistance = amx_ctof(params[11]) < STREAMER_STATIC_DISTANCE_CUTOFF ? amx_ctof(params[11]) : amx_ctof(params[11]) * amx_ctof(params[11]);
	actor->streamDistance = amx_ctof(params[11]);
	Utility::addToContainer(actor->areas, static_cast<int>(params[12]));
	actor->priority = static_cast<int>(params[13]);
	core->getGrid()->addActor(actor);
	core->getData()->actors.insert(std::make_pair(actorID, actor));
	return static_cast<cell>(actorID);
}

cell AMX_NATIVE_CALL Natives::DestroyDynamicActor(AMX *amx, cell *params)
{
	CHECK_PARAMS(1, "DestroyDynamicActor");
	boost::unordered_map<int, Item::SharedActor>::iterator a = core->getData()->actors.find(static_cast<int>(params[1]));
	if (a != core->getData()->actors.end())
	{
		Utility::destroyActor(a);
		return 1;
	}
	return 0;
}

cell AMX_NATIVE_CALL Natives::IsValidDynamicActor(AMX *amx, cell *params)
{
	CHECK_PARAMS(1, "IsValidDynamicActor");
	boost::unordered_map<int, Item::SharedActor>::iterator a = core->getData()->actors.find(static_cast<int>(params[1]));
	if (a != core->getData()->actors.end())
	{
		return 1;
	}
	return 0;
}
<|endoftext|>


<commit_before>#include "tgbot/net/TgLongPoll.h"

#include "tgbot/Api.h"
#include "tgbot/Bot.h"
#include "tgbot/EventHandler.h"

#include <cstdint>
#include <memory>
#include <vector>
#include <utility>

namespace TgBot {

TgLongPoll::TgLongPoll(const Api* api, const EventHandler* eventHandler, std::int32_t limit, std::int32_t timeout, std::shared_ptr<std::vector<std::string>> allowUpdates)
    : _api(api), _eventHandler(eventHandler), _limit(limit), _timeout(timeout),
      _allowUpdates(std::move(allowUpdates)) {
}

TgLongPoll::TgLongPoll(const Bot& bot, std::int32_t limit, std::int32_t timeout, const std::shared_ptr<std::vector<std::string>>& allowUpdates) :
    TgLongPoll(&bot.getApi(), &bot.getEventHandler(), limit, timeout, allowUpdates) {
}

void TgLongPoll::start() {
    std::vector<Update::Ptr> updates = _api->getUpdates(_lastUpdateId, _limit, _timeout, _allowUpdates);
    for (Update::Ptr& item : updates) {
        if (item->updateId >= _lastUpdateId) {
            _lastUpdateId = item->updateId + 1;
        }
        _eventHandler->handleUpdate(item);
    }
}

}
<commit_msg>Confirm updates directly after handling them (#231)<commit_after>#include "tgbot/net/TgLongPoll.h"

#include "tgbot/Api.h"
#include "tgbot/Bot.h"
#include "tgbot/EventHandler.h"

#include <cstdint>
#include <memory>
#include <vector>
#include <utility>

namespace TgBot {

TgLongPoll::TgLongPoll(const Api* api, const EventHandler* eventHandler, std::int32_t limit, std::int32_t timeout, std::shared_ptr<std::vector<std::string>> allowUpdates)
    : _api(api), _eventHandler(eventHandler), _limit(limit), _timeout(timeout),
      _allowUpdates(std::move(allowUpdates)) {
}

TgLongPoll::TgLongPoll(const Bot& bot, std::int32_t limit, std::int32_t timeout, const std::shared_ptr<std::vector<std::string>>& allowUpdates) :
    TgLongPoll(&bot.getApi(), &bot.getEventHandler(), limit, timeout, allowUpdates) {
}

void TgLongPoll::start() {
    // get all unconfirmed updates
    std::vector<Update::Ptr> updates = _api->getUpdates(0, _limit, _timeout, _allowUpdates);

    // handle updates
    for (Update::Ptr& item : updates) {
        if (item->updateId >= _lastUpdateId) {
            _lastUpdateId = item->updateId + 1;
        }
        _eventHandler->handleUpdate(item);
    }

    // confirm handled updates
    _api->getUpdates(_lastUpdateId, _limit, _timeout, _allowUpdates);
}

}
<|endoftext|>


<commit_before>// This code is in the public domain -- icastano@gmail.com

#include "Fitting.h"

#include <nvcore/Algorithms.h> // max
#include <nvcore/Containers.h> // swap
#include <float.h> // FLT_MAX

using namespace nv;

Vector3 nv::ComputeCentroid(int n, const Vector3 * points, const float * weights, Vector3::Arg metric)
{
	Vector3 centroid(zero);
	float total = 0.0f;

	for (int i = 0; i < n; i++)
	{
		total += weights[i];
		centroid += weights[i]*points[i];
	}
	centroid /= total;

	return centroid;
}

void nv::ComputeCovariance(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, float * covariance)
{
	// compute the centroid
	Vector3 centroid = ComputeCentroid(n, points, weights, metric);

	// compute covariance matrix
	for (int i = 0; i < 6; i++)
	{
		covariance[i] = 0.0f;
	}

	for (int i = 0; i < n; i++)
	{
		Vector3 a = (points[i] - centroid) * metric;
		Vector3 b = weights[i]*a;

		covariance[0] += a.x()*b.x();
		covariance[1] += a.x()*b.y();
		covariance[2] += a.x()*b.z();
		covariance[3] += a.y()*b.y();
		covariance[4] += a.y()*b.z();
		covariance[5] += a.z()*b.z();
	}
}

Vector3 nv::ComputePrincipalComponent(int n, const Vector3 * points, const float * weights, Vector3::Arg metric)
{
	float matrix[6];
	ComputeCovariance(n, points, weights, metric, matrix);

	if (matrix[0] == 0 || matrix[3] == 0 || matrix[5] == 0)
	{
		return Vector3(zero);
	}

	const int NUM = 8;

	Vector3 v(1, 1, 1);
	for (int i = 0; i < NUM; i++)
	{
		float x = v.x() * matrix[0] + v.y() * matrix[1] + v.z() * matrix[2];
		float y = v.x() * matrix[1] + v.y() * matrix[3] + v.z() * matrix[4];
		float z = v.x() * matrix[2] + v.y() * matrix[4] + v.z() * matrix[5];

		float norm = max(max(x, y), z);

		v = Vector3(x, y, z) / norm;
	}

	return v;
}

int nv::Compute4Means(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, Vector3 * cluster)
{
	Vector3 centroid = ComputeCentroid(n, points, weights, metric);

	// Compute principal component.
	Vector3 principal = ComputePrincipalComponent(n, points, weights, metric);

	// Pick initial solution.
	int mini, maxi;
	mini = maxi = 0;

	float mindps, maxdps;
	mindps = maxdps = dot(points[0] - centroid, principal);

	for (int i = 1; i < n; ++i)
	{
		float dps = dot(points[i] - centroid, principal);

		if (dps < mindps) {
			mindps = dps;
			mini = i;
		}
		else {
			maxdps = dps;
			maxi = i;
		}
	}

	//cluster[0] = points[mini];
	//cluster[1] = points[maxi];
	cluster[0] = centroid + mindps * principal;
	cluster[1] = centroid + maxdps * principal;
	cluster[2] = (2 * cluster[0] + cluster[1]) / 3;
	cluster[3] = (2 * cluster[1] + cluster[0]) / 3;

	// Now we have to iteratively refine the clusters.
	while (true)
	{
		Vector3 newCluster[4] = { Vector3(zero), Vector3(zero), Vector3(zero), Vector3(zero) };
		float total[4] = {0, 0, 0, 0};

		for (int i = 0; i < n; ++i)
		{
			// Find nearest cluster.
			int nearest = 0;
			float mindist = FLT_MAX;
			for (int j = 0; j < 4; j++)
			{
				float dist = length_squared(cluster[j] - points[i]);
				if (dist < mindist)
				{
					mindist = dist;
					nearest = j;
				}
			}

			newCluster[nearest] += weights[i] * points[i];
			total[nearest] += weights[i];
		}

		for (int j = 0; j < 4; j++)
		{
			newCluster[j] /= total[j];
		}

		if ((equal(cluster[0], newCluster[0]) || total[0] == 0) &&
			(equal(cluster[1], newCluster[1]) || total[1] == 0) &&
			(equal(cluster[2], newCluster[2]) || total[2] == 0) &&
			(equal(cluster[3], newCluster[3]) || total[3] == 0))
		{
			return (total[0] != 0) + (total[1] != 0) + (total[2] != 0) + (total[3] != 0);
		}

		cluster[0] = newCluster[0];
		cluster[1] = newCluster[1];
		cluster[2] = newCluster[2];
		cluster[3] = newCluster[3];

		// Sort clusters by weight.
		for (int i = 0; i < 4; i++)
		{
			for (int j = i; j > 0 && total[j] > total[j - 1]; j--)
			{
				swap( total[j], total[j - 1] );
				swap( cluster[j], cluster[j - 1] );
			}
		}
	}
}

/*
int nv::Compute2Means(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, Vector3 * cluster)
{
	Vector3 centroid = ComputeCentroid(n, points, weights, metric);

	// Compute principal component.
	Vector3 principal = ComputePrincipalComponent(n, points, weights, metric);

	// Pick initial solution.
	int mini, maxi;
	mini = maxi = 0;

	float mindps, maxdps;
	mindps = maxdps = dot(points[0] - centroid, principal);

	for (int i = 1; i < n; ++i)
	{
		float dps = dot(points[i] - centroid, principal);

		if (dps < mindps) {
			mindps = dps;
			mini = i;
		}
		else {
			maxdps = dps;
			maxi = i;
		}
	}

	cluster[0] = points[mini];
	cluster[3] = points[maxi];
	//cluster[0] = centroid + mindps * principal;
	//cluster[1] = centroid + maxdps * principal;
	cluster[2] = (2 * cluster[0] + cluster[1]) / 3;
	cluster[3] = (2 * cluster[1] + cluster[0]) / 3;

	// Now we have to iteratively refine the clusters.
	while (true)
	{
		Vector3 newCluster[4] = { Vector3(zero), Vector3(zero), Vector3(zero), Vector3(zero) };
		float total[4] = {0, 0, 0, 0};

		for (int i = 0; i < n; ++i)
		{
			// Find nearest cluster.
			int nearest = 0;
			float mindist = FLT_MAX;
			for (int j = 0; j < 4; j++)
			{
				float dist = length_squared(cluster[j] - points[i]);
				if (dist < mindist)
				{
					mindist = dist;
					nearest = j;
				}
			}

			newCluster[nearest] += weights[i] * points[i];
			total[nearest] += weights[i];
		}

		for (int j = 0; j < 4; j++)
		{
			newCluster[j] /= total[j];
		}

		if ((equal(cluster[0], newCluster[0]) || total[0] == 0) &&
			(equal(cluster[1], newCluster[1]) || total[1] == 0) &&
			(equal(cluster[2], newCluster[2]) || total[2] == 0) &&
			(equal(cluster[3], newCluster[3]) || total[3] == 0))
		{
			return (total[0] != 0) + (total[1] != 0) + (total[2] != 0) + (total[3] != 0);
		}

		cluster[0] = newCluster[0];
		cluster[1] = newCluster[1];
		cluster[2] = newCluster[2];
		cluster[3] = newCluster[3];

		// Sort clusters by weight.
		for (int i = 0; i < 4; i++)
		{
			for (int j = i; j > 0 && total[j] > total[j - 1]; j--)
			{
				swap( total[j], total[j - 1] );
				swap( cluster[j], cluster[j - 1] );
			}
		}
	}
}
*/<commit_msg>Use metric to measure distance to clusters.<commit_after>// This code is in the public domain -- icastano@gmail.com

#include "Fitting.h"

#include <nvcore/Algorithms.h> // max
#include <nvcore/Containers.h> // swap
#include <float.h> // FLT_MAX

using namespace nv;

Vector3 nv::ComputeCentroid(int n, const Vector3 * points, const float * weights, Vector3::Arg metric)
{
	Vector3 centroid(zero);
	float total = 0.0f;

	for (int i = 0; i < n; i++)
	{
		total += weights[i];
		centroid += weights[i]*points[i];
	}
	centroid /= total;

	return centroid;
}

void nv::ComputeCovariance(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, float * covariance)
{
	// compute the centroid
	Vector3 centroid = ComputeCentroid(n, points, weights, metric);

	// compute covariance matrix
	for (int i = 0; i < 6; i++)
	{
		covariance[i] = 0.0f;
	}

	for (int i = 0; i < n; i++)
	{
		Vector3 a = (points[i] - centroid) * metric;
		Vector3 b = weights[i]*a;

		covariance[0] += a.x()*b.x();
		covariance[1] += a.x()*b.y();
		covariance[2] += a.x()*b.z();
		covariance[3] += a.y()*b.y();
		covariance[4] += a.y()*b.z();
		covariance[5] += a.z()*b.z();
	}
}

Vector3 nv::ComputePrincipalComponent(int n, const Vector3 * points, const float * weights, Vector3::Arg metric)
{
	float matrix[6];
	ComputeCovariance(n, points, weights, metric, matrix);

	if (matrix[0] == 0 || matrix[3] == 0 || matrix[5] == 0)
	{
		return Vector3(zero);
	}

	const int NUM = 8;

	Vector3 v(1, 1, 1);
	for (int i = 0; i < NUM; i++)
	{
		float x = v.x() * matrix[0] + v.y() * matrix[1] + v.z() * matrix[2];
		float y = v.x() * matrix[1] + v.y() * matrix[3] + v.z() * matrix[4];
		float z = v.x() * matrix[2] + v.y() * matrix[4] + v.z() * matrix[5];

		float norm = max(max(x, y), z);

		v = Vector3(x, y, z) / norm;
	}

	return v;
}

int nv::Compute4Means(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, Vector3 * cluster)
{
	Vector3 centroid = ComputeCentroid(n, points, weights, metric);

	// Compute principal component.
	Vector3 principal = ComputePrincipalComponent(n, points, weights, metric);

	// Pick initial solution.
	int mini, maxi;
	mini = maxi = 0;

	float mindps, maxdps;
	mindps = maxdps = dot(points[0] - centroid, principal);

	for (int i = 1; i < n; ++i)
	{
		float dps = dot(points[i] - centroid, principal);

		if (dps < mindps) {
			mindps = dps;
			mini = i;
		}
		else {
			maxdps = dps;
			maxi = i;
		}
	}

	//cluster[0] = points[mini];
	//cluster[1] = points[maxi];
	cluster[0] = centroid + mindps * principal;
	cluster[1] = centroid + maxdps * principal;
	cluster[2] = (2 * cluster[0] + cluster[1]) / 3;
	cluster[3] = (2 * cluster[1] + cluster[0]) / 3;

	// Now we have to iteratively refine the clusters.
	while (true)
	{
		Vector3 newCluster[4] = { Vector3(zero), Vector3(zero), Vector3(zero), Vector3(zero) };
		float total[4] = {0, 0, 0, 0};

		for (int i = 0; i < n; ++i)
		{
			// Find nearest cluster.
			int nearest = 0;
			float mindist = FLT_MAX;
			for (int j = 0; j < 4; j++)
			{
				float dist = length_squared((cluster[j] - points[i]) * metric);
				if (dist < mindist)
				{
					mindist = dist;
					nearest = j;
				}
			}

			newCluster[nearest] += weights[i] * points[i];
			total[nearest] += weights[i];
		}

		for (int j = 0; j < 4; j++)
		{
			newCluster[j] /= total[j];
		}

		if ((equal(cluster[0], newCluster[0]) || total[0] == 0) &&
			(equal(cluster[1], newCluster[1]) || total[1] == 0) &&
			(equal(cluster[2], newCluster[2]) || total[2] == 0) &&
			(equal(cluster[3], newCluster[3]) || total[3] == 0))
		{
			return (total[0] != 0) + (total[1] != 0) + (total[2] != 0) + (total[3] != 0);
		}

		cluster[0] = newCluster[0];
		cluster[1] = newCluster[1];
		cluster[2] = newCluster[2];
		cluster[3] = newCluster[3];

		// Sort clusters by weight.
		for (int i = 0; i < 4; i++)
		{
			for (int j = i; j > 0 && total[j] > total[j - 1]; j--)
			{
				swap( total[j], total[j - 1] );
				swap( cluster[j], cluster[j - 1] );
			}
		}
	}
}

<|endoftext|>