<commit_before>//=======================================================================
// Copyright <NAME> 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)
//=======================================================================

#define BOOST_NO_RTTI
#define BOOST_NO_TYPEID
#include <boost/range/adaptors.hpp>

#include "Type.hpp"
#include "FunctionContext.hpp"
#include "GlobalContext.hpp"
#include "Variable.hpp"

#include "mtac/DeadCodeElimination.hpp"
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/LiveVariableAnalysisProblem.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Offset.hpp"
#include "mtac/Quadruple.hpp"

using namespace eddic;

bool mtac::dead_code_elimination::operator()(mtac::Function& function){
    bool optimized = false;

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

    std::vector<std::size_t> to_delete;

    for(auto& block : function){
        auto& out = results->OUT[block];

        for(auto& quadruple : boost::adaptors::reverse(block->statements)){
            if(quadruple.result && mtac::erase_result(quadruple.op)){
                if(out.top() || out.values().find(quadruple.result) == out.values().end()){
                    to_delete.push_back(quadruple.uid());
                }
            }

            problem.transfer(block, quadruple, out);
        }
    }

    if(!to_delete.empty()){
        optimized = true;

        for(auto& block : function){
            block->statements.erase(
                    remove_if(block->statements.begin(), block->statements.end(), 
                        [&to_delete](const mtac::Quadruple& q){return std::find(to_delete.begin(), to_delete.end(), q.uid()) != to_delete.end();}), 
                    block->statements.end());
        }
    }

    //TODO Review or remove this optimization, this is quite unsafe

    std::unordered_set<Offset, mtac::OffsetHash> used_offsets;
    std::unordered_set<std::shared_ptr<Variable>> invalidated_offsets;

    for(auto& block : function){
        for(auto& quadruple : block->statements){
            if(quadruple.op == mtac::Operator::DOT || quadruple.op == mtac::Operator::FDOT || quadruple.op == mtac::Operator::PDOT){
                if(auto* var_ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg1)){
                    if(auto* offset_ptr = boost::get<int>(&*quadruple.arg2)){
                        mtac::Offset offset(*var_ptr, *offset_ptr);
                        used_offsets.insert(offset);
                    } else {
                        invalidated_offsets.insert(*var_ptr);
                    }
                }
            }
        }<commit_msg>Remove variables contributing only to themselves<commit_after>//=======================================================================
// Copyright <NAME> 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)
//=======================================================================

#define BOOST_NO_RTTI
#define BOOST_NO_TYPEID
#include <boost/range/adaptors.hpp>

#include "Type.hpp"
#include "FunctionContext.hpp"
#include "GlobalContext.hpp"
#include "Variable.hpp"

#include "mtac/DeadCodeElimination.hpp"
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/LiveVariableAnalysisProblem.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Offset.hpp"
#include "mtac/Quadruple.hpp"

using namespace eddic;

bool mtac::dead_code_elimination::operator()(mtac::Function& function){
    bool optimized = false;

    std::vector<std::size_t> to_delete;

    //1. DCE based on data-flow analysis

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

    for(auto& block : function){
        auto& out = results->OUT[block];

        for(auto& quadruple : boost::adaptors::reverse(block->statements)){
            if(quadruple.result && mtac::erase_result(quadruple.op)){
                if(out.top() || out.values().find(quadruple.result) == out.values().end()){
                    to_delete.push_back(quadruple.uid());
                }
            }

            problem.transfer(block, quadruple, out);
        }
    }

    //2. Remove variables that contribute only to themselves
    //TODO This could probably be done directly in the data-flow DCE

    std::unordered_set<std::shared_ptr<Variable>> candidates;

    for(auto& block : function){
        for(auto& quadruple : block->statements){
            if(quadruple.result && mtac::erase_result(quadruple.op)){
                if(quadruple.arg1){
                    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg1)){
                        if(*ptr == quadruple.result){
                            candidates.insert(quadruple.result);
                        }
                    }
                }

                if(quadruple.arg2){
                    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg2)){
                        if(*ptr == quadruple.result){
                            candidates.insert(quadruple.result);
                        }
                    }
                }
            }
        }
    }
    
    for(auto& block : function){
        for(auto& quadruple : block->statements){
            if(quadruple.result && mtac::erase_result(quadruple.op)){
                if(quadruple.arg1){
                    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg1)){
                        if(*ptr != quadruple.result){
                            candidates.erase(*ptr);
                        }
                    }
                }

                if(quadruple.arg2){
                    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg2)){
                        if(*ptr != quadruple.result){
                            candidates.erase(*ptr);
                        }
                    }
                }
            } else {
                candidates.erase(quadruple.result);

                if(quadruple.arg1){
                    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg1)){
                        candidates.erase(*ptr);
                    }
                }

                if(quadruple.arg2){
                    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg2)){
                        candidates.erase(*ptr);
                    }
                }
            }
        }
    }

    if(!candidates.empty()){
        for(auto& block : function){
            for(auto& quadruple : block->statements){
                if(quadruple.result && mtac::erase_result(quadruple.op) && candidates.find(quadruple.result) != candidates.end()){
                    to_delete.push_back(quadruple.uid());
                } 
            }
        }
    }

    //Delete what has been found on previous steps

    if(!to_delete.empty()){
        optimized = true;

        for(auto& block : function){
            block->statements.erase(
                    remove_if(block->statements.begin(), block->statements.end(), 
                        [&to_delete](const mtac::Quadruple& q){return std::find(to_delete.begin(), to_delete.end(), q.uid()) != to_delete.end();}), 
                    block->statements.end());
        }
    }

    //TODO Review or remove this optimization, this is quite unsafe

    std::unordered_set<Offset, mtac::OffsetHash> used_offsets;
    std::unordered_set<std::shared_ptr<Variable>> invalidated_offsets;

    for(auto& block : function){
        for(auto& quadruple : block->statements){
            if(quadruple.op == mtac::Operator::DOT || quadruple.op == mtac::Operator::FDOT || quadruple.op == mtac::Operator::PDOT){
                if(auto* var_ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple.arg1)){
                    if(auto* offset_ptr = boost::get<int>(&*quadruple.arg2)){
                        mtac::Offset offset(*var_ptr, *offset_ptr);
                        used_offsets.insert(offset);
                    } else {
                        invalidated_offsets.insert(*var_ptr);
                    }
                }
            }
        }
{'fraction_non_alphanumeric': 0.16521635475026822, 'fraction_numerical': 0.005483371081177733, 'mean_word_length': 2.083425211319368, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 52, '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': '2993059', 'n_tokens_mistral': 2475, 'n_tokens_neox': 2308, 'n_words': 382}