<commit_before>//=======================================================================
// Copyright <NAME> 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 "PerfsTimer.hpp"
#include "logging.hpp"
#include "FunctionContext.hpp"
#include "GlobalContext.hpp"
#include "Type.hpp"

#include "mtac/GlobalOptimizations.hpp"

#include "ltac/register_allocator.hpp"
#include "ltac/LiveRegistersProblem.hpp"
#include "ltac/interference_graph.hpp"
#include "ltac/Printer.hpp"

using namespace eddic;

namespace {

bool is_store(ltac::Statement& statement, ltac::PseudoRegister reg);
void replace_register(ltac::Statement& statement, ltac::PseudoRegister source, ltac::PseudoRegister target);

//1. Renumber

typedef std::unordered_map<std::shared_ptr<mtac::BasicBlock>, std::unordered_set<ltac::PseudoRegister>> local_reg;

template<typename Opt>
void find_reg_addr(Opt& reg, std::unordered_set<ltac::PseudoRegister>& registers){
    if(reg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&*reg)){
            registers.insert(*ptr);
        }
    }
}

template<typename Opt>
void find_reg(Opt& arg, std::unordered_set<ltac::PseudoRegister>& registers){
    if(arg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&*arg)){
            registers.insert(*ptr);
        } else if(auto* ptr = boost::get<ltac::Address>(&*arg)){
            find_reg_addr(ptr->base_register, registers);
            find_reg_addr(ptr->scaled_register, registers);
        }
    }
}

void find_local_registers(mtac::function_p function, local_reg& local_pseudo_registers){
    local_reg pseudo_registers;

    for(auto& bb : function){
        for(auto& statement : bb->l_statements){
            if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                find_reg((*ptr)->arg1, pseudo_registers[bb]);
                find_reg((*ptr)->arg2, pseudo_registers[bb]);
                find_reg((*ptr)->arg3, pseudo_registers[bb]);

                for(auto reg : (*ptr)->uses){
                    pseudo_registers[bb].insert(reg);
                }
            } else if(auto* ptr = boost::get<std::shared_ptr<ltac::Jump>>(&statement)){
                for(auto reg : (*ptr)->uses){
                    pseudo_registers[bb].insert(reg);
                }
            }
        }
    }

    //TODO Find a more efficient way to prune the results...

    for(auto& bb : function){
        for(auto& reg : pseudo_registers[bb]){
            bool found = false;

            for(auto& bb2 : function){
                if(bb != bb2 && pseudo_registers[bb2].count(reg)){
                    found = true;
                    break;
                }
            }

            if(!found){
                local_pseudo_registers[bb].insert(reg);
            }
        }
    }
}

void renumber(mtac::function_p function){
    local_reg local_pseudo_registers;
    find_local_registers(function, local_pseudo_registers);

    auto current_reg = function->pseudo_registers();

    for(auto& bb :function){
        for(auto& reg : local_pseudo_registers[bb]){
            //No need to renumber bound registers
            if(reg.bound){
                continue;
            }

            ltac::PseudoRegister target;

            for(auto& statement : bb->l_statements){
                if(is_store(statement, reg)){
                    target = ltac::PseudoRegister(++current_reg);

                    //Make sure to replace only the first argument
                    auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);
                    instruction->arg1 = target;
                } else {
                    replace_register(statement, reg, target);
                }
            }
        }
    }
}

//2. Build

template<typename Opt>
void gather_reg(Opt& reg, ltac::interference_graph& graph){
    if(reg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&*reg)){<commit_msg>Do not forget to set the number of pseudo registers in the function<commit_after>//=======================================================================
// Copyright <NAME> 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 "PerfsTimer.hpp"
#include "logging.hpp"
#include "FunctionContext.hpp"
#include "GlobalContext.hpp"
#include "Type.hpp"

#include "mtac/GlobalOptimizations.hpp"

#include "ltac/register_allocator.hpp"
#include "ltac/LiveRegistersProblem.hpp"
#include "ltac/interference_graph.hpp"
#include "ltac/Printer.hpp"

using namespace eddic;

namespace {

bool is_store(ltac::Statement& statement, ltac::PseudoRegister reg);
void replace_register(ltac::Statement& statement, ltac::PseudoRegister source, ltac::PseudoRegister target);

//1. Renumber

typedef std::unordered_map<std::shared_ptr<mtac::BasicBlock>, std::unordered_set<ltac::PseudoRegister>> local_reg;

template<typename Opt>
void find_reg_addr(Opt& reg, std::unordered_set<ltac::PseudoRegister>& registers){
    if(reg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&*reg)){
            registers.insert(*ptr);
        }
    }
}

template<typename Opt>
void find_reg(Opt& arg, std::unordered_set<ltac::PseudoRegister>& registers){
    if(arg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&*arg)){
            registers.insert(*ptr);
        } else if(auto* ptr = boost::get<ltac::Address>(&*arg)){
            find_reg_addr(ptr->base_register, registers);
            find_reg_addr(ptr->scaled_register, registers);
        }
    }
}

void find_local_registers(mtac::function_p function, local_reg& local_pseudo_registers){
    local_reg pseudo_registers;

    for(auto& bb : function){
        for(auto& statement : bb->l_statements){
            if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                find_reg((*ptr)->arg1, pseudo_registers[bb]);
                find_reg((*ptr)->arg2, pseudo_registers[bb]);
                find_reg((*ptr)->arg3, pseudo_registers[bb]);

                for(auto reg : (*ptr)->uses){
                    pseudo_registers[bb].insert(reg);
                }
            } else if(auto* ptr = boost::get<std::shared_ptr<ltac::Jump>>(&statement)){
                for(auto reg : (*ptr)->uses){
                    pseudo_registers[bb].insert(reg);
                }
            }
        }
    }

    //TODO Find a more efficient way to prune the results...

    for(auto& bb : function){
        for(auto& reg : pseudo_registers[bb]){
            bool found = false;

            for(auto& bb2 : function){
                if(bb != bb2 && pseudo_registers[bb2].count(reg)){
                    found = true;
                    break;
                }
            }

            if(!found){
                local_pseudo_registers[bb].insert(reg);
            }
        }
    }
}

void renumber(mtac::function_p function){
    local_reg local_pseudo_registers;
    find_local_registers(function, local_pseudo_registers);

    auto current_reg = function->pseudo_registers();

    for(auto& bb :function){
        for(auto& reg : local_pseudo_registers[bb]){
            //No need to renumber bound registers
            if(reg.bound){
                continue;
            }

            ltac::PseudoRegister target;

            for(auto& statement : bb->l_statements){
                if(is_store(statement, reg)){
                    target = ltac::PseudoRegister(++current_reg);

                    //Make sure to replace only the first argument
                    auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);
                    instruction->arg1 = target;
                } else {
                    replace_register(statement, reg, target);
                }
            }
        }
    }

    function->set_pseudo_registers(current_reg);
}

//2. Build

template<typename Opt>
void gather_reg(Opt& reg, ltac::interference_graph& graph){
    if(reg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&*reg)){
{'fraction_non_alphanumeric': 0.16179640718562874, 'fraction_numerical': 0.004550898203592815, 'mean_word_length': 2.5933734939759034, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 64, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3928897', 'n_tokens_mistral': 2534, 'n_tokens_neox': 2410, 'n_words': 454}