<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 <string>

#include "IntermediateCompiler.hpp"

#include "MainDeclaration.hpp"
#include "Methods.hpp"
#include "StringPool.hpp"
#include "VisitorUtils.hpp"

#include "Context.hpp"
#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "Variable.hpp"
#include "SemanticalException.hpp"
#include "IsImmediateVisitor.hpp"
#include "IsConstantVisitor.hpp"
#include "GetConstantValue.hpp"

#include "mangling.hpp"

#include "il/IntermediateProgram.hpp"
#include "il/Operands.hpp"
#include "il/Labels.hpp"
#include "il/Math.hpp"

#include "ast/Program.hpp"

using namespace eddic;

inline bool isImmediate(ast::Value& value){
   return boost::apply_visitor(IsImmediateVisitor(), value); 
}

inline Operation toOperation(char op){
    switch(op){
        case '+':
            return Operation::ADD;
        case '-':
            return Operation::SUB;
        case '/':
            return Operation::DIV;
        case '*':
            return Operation::MUL;
        case '%':
            return Operation::MOD;
        default:
            assert(false);
    }
}

void executeCall(ast::FunctionCall& functionCall, IntermediateProgram& program);
inline void putInRegister(ast::Value& value, std::shared_ptr<Operand> operand, IntermediateProgram& program);

void computeAddressOfElement(std::shared_ptr<Variable> array, int index, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    int offset = -1 * ((index * size(array->type().base())) + size(BaseType::INT));
    
    //We have to go upper to point to the string
    if(array->type().base() == BaseType::STRING){
        offset -= 4;
    }
    
    auto position = array->position();
    if(position.isGlobal()){
        offset += size(array->type().base()) * array->type().size();

        program.addInstruction(program.factory().createMove(createImmediateOperand("VA" + position.name()), operand));
    } else if(position.isStack()){
        offset -= position.offset();

        program.addInstruction(program.factory().createMove(program.registers(EBP), operand));
    } else if(position.isParameter()){
        program.addInstruction(program.factory().createMove(createBaseStackOperand(position.offset()), operand));
    }
        
    program.addInstruction(program.factory().createMath(Operation::ADD, createImmediateOperand(offset), operand));
}

void computeAddressOfElement(std::shared_ptr<Variable> array, std::shared_ptr<Operand> indexOperand, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    int offset = -size(BaseType::INT);

    //We have to go upper to point to the string
    if(array->type().base() == BaseType::STRING){
        offset -= 4;
    }
    
    auto position = array->position();
    if(position.isGlobal()){
        offset += size(array->type().base()) * array->type().size();

        program.addInstruction(program.factory().createMove(createImmediateOperand("VA" + position.name()), operand));
    } else if(position.isStack()){
        offset -= position.offset();

        program.addInstruction(program.factory().createMove(program.registers(EBP), operand));
    } else if(position.isParameter()){
        program.addInstruction(program.factory().createMove(createBaseStackOperand(position.offset()), operand));
    }
    
    program.addInstruction(program.factory().createMath(Operation::MUL, createImmediateOperand(-1 * size(array->type().base())), indexOperand));
    program.addInstruction(program.factory().createMath(Operation::ADD, createImmediateOperand(offset), indexOperand));
   
    program.addInstruction(program.factory().createMath(Operation::ADD, indexOperand, operand));
}

void computeAddressOfElement(std::shared_ptr<Variable> array, ast::Value indexValue, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    assert(operand->isRegister());

    if(boost::apply_visitor(IsConstantVisitor(), indexValue)){
        int index = boost::get<int>(boost::apply_visitor(GetConstantValue(), indexValue));

        computeAddressOfElement(array, index, program, operand);
    } else {
        auto registerA = program.registers(EAX);

        putInRegister(indexValue, registerA, program);
        computeAddressOfElement(array, registerA, program, operand);
    }
}

void computeAddressOfElement(std::shared_ptr<Variable> array, std::shared_ptr<Variable> indexVar, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    assert(operand->isRegister());

    auto registerA = program.registers(EAX);

    program.addInstruction(program.factory().createMove(indexVar->toIntegerOperand(), registerA));
    computeAddressOfElement(array, registerA, program, operand);
}

void computeLenghtOfArray(std::shared_ptr<Variable> array, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    assert(operand->isRegister());
    
    auto position = array->position();
    if(position.isGlobal()){
        program.addInstruction(program.factory().createMove(createImmediateOperand(array->type().size()), operand));
    } else if(position.isStack()){
        program.addInstruction(program.factory().createMove(createImmediateOperand(array->type().size()), operand));
    } else if(position.isParameter()){
        auto reg = program.registers(EDI);
        program.addInstruction(program.factory().createMove(createBaseStackOperand(position.offset()), reg));
        program.addInstruction(program.factory().createMove(reg->valueOf(), operand));
    }
}

inline std::shared_ptr<Operand> performIntOperation(ast::ComposedValue& value, IntermediateProgram& program){
    assert(value.Content->operations.size() > 0); //This has been enforced by previous phases

    auto registerA = program.registers(ECX);
    auto registerB = program.registers(EBX);

    putInRegister(value.Content->first, registerA, program);

    //Apply all the operations in chain
    for(auto& operation : value.Content->operations){
        if(isImmediate(operation.get<1>())){
            putInRegister(operation.get<1>(), registerB, program);

            //Perform the operation 
            program.addInstruction(program.factory().createMath(toOperation(operation.get<0>()), registerA, registerB));
        } else { //The right value is composed
            program.addInstruction(program.factory().createPush(registerA)); //To be sure that the right operation does not override our register 
            
            putInRegister(operation.get<1>(), registerB, program);

            //TODO Use a popl instead
            program.addInstruction(program.factory().createMove(createStackOperand(0), registerA));
            program.addInstruction(program.factory().createMath(Operation::ADD, createImmediateOperand(4), program.registers(ESP)));
            
            program.addInstruction(program.factory().createMath(toOperation(operation.get<0>()), registerA, registerB));
        }
    }

    return registerB;
}

inline std::pair<std::shared_ptr<Operand>, std::shared_ptr<Operand>> performStringOperation(ast::ComposedValue& value, IntermediateProgram& program);

class PushValue : public boost::static_visitor<> {<commit_msg>Use popl to restore the state of the eax register after a composed operation<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 <string>

#include "IntermediateCompiler.hpp"

#include "MainDeclaration.hpp"
#include "Methods.hpp"
#include "StringPool.hpp"
#include "VisitorUtils.hpp"

#include "Context.hpp"
#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "Variable.hpp"
#include "SemanticalException.hpp"
#include "IsImmediateVisitor.hpp"
#include "IsConstantVisitor.hpp"
#include "GetConstantValue.hpp"

#include "mangling.hpp"

#include "il/IntermediateProgram.hpp"
#include "il/Operands.hpp"
#include "il/Labels.hpp"
#include "il/Math.hpp"

#include "ast/Program.hpp"

using namespace eddic;

inline bool isImmediate(ast::Value& value){
   return boost::apply_visitor(IsImmediateVisitor(), value); 
}

inline Operation toOperation(char op){
    switch(op){
        case '+':
            return Operation::ADD;
        case '-':
            return Operation::SUB;
        case '/':
            return Operation::DIV;
        case '*':
            return Operation::MUL;
        case '%':
            return Operation::MOD;
        default:
            assert(false);
    }
}

void executeCall(ast::FunctionCall& functionCall, IntermediateProgram& program);
inline void putInRegister(ast::Value& value, std::shared_ptr<Operand> operand, IntermediateProgram& program);

void computeAddressOfElement(std::shared_ptr<Variable> array, int index, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    int offset = -1 * ((index * size(array->type().base())) + size(BaseType::INT));
    
    //We have to go upper to point to the string
    if(array->type().base() == BaseType::STRING){
        offset -= 4;
    }
    
    auto position = array->position();
    if(position.isGlobal()){
        offset += size(array->type().base()) * array->type().size();

        program.addInstruction(program.factory().createMove(createImmediateOperand("VA" + position.name()), operand));
    } else if(position.isStack()){
        offset -= position.offset();

        program.addInstruction(program.factory().createMove(program.registers(EBP), operand));
    } else if(position.isParameter()){
        program.addInstruction(program.factory().createMove(createBaseStackOperand(position.offset()), operand));
    }
        
    program.addInstruction(program.factory().createMath(Operation::ADD, createImmediateOperand(offset), operand));
}

void computeAddressOfElement(std::shared_ptr<Variable> array, std::shared_ptr<Operand> indexOperand, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    int offset = -size(BaseType::INT);

    //We have to go upper to point to the string
    if(array->type().base() == BaseType::STRING){
        offset -= 4;
    }
    
    auto position = array->position();
    if(position.isGlobal()){
        offset += size(array->type().base()) * array->type().size();

        program.addInstruction(program.factory().createMove(createImmediateOperand("VA" + position.name()), operand));
    } else if(position.isStack()){
        offset -= position.offset();

        program.addInstruction(program.factory().createMove(program.registers(EBP), operand));
    } else if(position.isParameter()){
        program.addInstruction(program.factory().createMove(createBaseStackOperand(position.offset()), operand));
    }
    
    program.addInstruction(program.factory().createMath(Operation::MUL, createImmediateOperand(-1 * size(array->type().base())), indexOperand));
    program.addInstruction(program.factory().createMath(Operation::ADD, createImmediateOperand(offset), indexOperand));
   
    program.addInstruction(program.factory().createMath(Operation::ADD, indexOperand, operand));
}

void computeAddressOfElement(std::shared_ptr<Variable> array, ast::Value indexValue, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    assert(operand->isRegister());

    if(boost::apply_visitor(IsConstantVisitor(), indexValue)){
        int index = boost::get<int>(boost::apply_visitor(GetConstantValue(), indexValue));

        computeAddressOfElement(array, index, program, operand);
    } else {
        auto registerA = program.registers(EAX);

        putInRegister(indexValue, registerA, program);
        computeAddressOfElement(array, registerA, program, operand);
    }
}

void computeAddressOfElement(std::shared_ptr<Variable> array, std::shared_ptr<Variable> indexVar, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    assert(operand->isRegister());

    auto registerA = program.registers(EAX);

    program.addInstruction(program.factory().createMove(indexVar->toIntegerOperand(), registerA));
    computeAddressOfElement(array, registerA, program, operand);
}

void computeLenghtOfArray(std::shared_ptr<Variable> array, IntermediateProgram& program, std::shared_ptr<Operand> operand){
    assert(operand->isRegister());
    
    auto position = array->position();
    if(position.isGlobal()){
        program.addInstruction(program.factory().createMove(createImmediateOperand(array->type().size()), operand));
    } else if(position.isStack()){
        program.addInstruction(program.factory().createMove(createImmediateOperand(array->type().size()), operand));
    } else if(position.isParameter()){
        auto reg = program.registers(EDI);
        program.addInstruction(program.factory().createMove(createBaseStackOperand(position.offset()), reg));
        program.addInstruction(program.factory().createMove(reg->valueOf(), operand));
    }
}

inline std::shared_ptr<Operand> performIntOperation(ast::ComposedValue& value, IntermediateProgram& program){
    assert(value.Content->operations.size() > 0); //This has been enforced by previous phases

    auto registerA = program.registers(ECX);
    auto registerB = program.registers(EBX);

    putInRegister(value.Content->first, registerA, program);

    //Apply all the operations in chain
    for(auto& operation : value.Content->operations){
        if(isImmediate(operation.get<1>())){
            putInRegister(operation.get<1>(), registerB, program);

            //Perform the operation 
            program.addInstruction(program.factory().createMath(toOperation(operation.get<0>()), registerA, registerB));
        } else { //The right value is composed
            program.addInstruction(program.factory().createPush(registerA)); //To be sure that the right operation does not override our register 
            
            putInRegister(operation.get<1>(), registerB, program);

            program.addInstruction(program.factory().createPop(registerA));

            program.addInstruction(program.factory().createMath(toOperation(operation.get<0>()), registerA, registerB));
        }
    }

    return registerB;
}

inline std::pair<std::shared_ptr<Operand>, std::shared_ptr<Operand>> performStringOperation(ast::ComposedValue& value, IntermediateProgram& program);

class PushValue : public boost::static_visitor<> {
{'fraction_non_alphanumeric': 0.1584373304395008, 'fraction_numerical': 0.0028486163863266412, 'mean_word_length': 4.4916201117318435, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 99, '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': '7363941', 'n_tokens_mistral': 4010, 'n_tokens_neox': 4058, 'n_words': 766}