/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * 
 * transformersaturation.cpp
 *
 * Author: pgess <v.melnychenko@xreate.org>
 * Created on March 25, 2017, 10:06 PM
 */

#include "transformersaturation.h"
#include "llvmlayer.h"

using namespace llvm;

namespace xreate {    namespace compilation {

TransformerSaturation::TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager)
    :  man(manager), blockAllocation(allocationBlock){

    llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext());

    constTrue = llvm::ConstantInt::get(tyInt1, 1);
    constFalse = llvm::ConstantInt::get(tyInt1, 0);

    if (man->exists<TransformerSaturation>()){
        oldInstance = man->update(this);

    } else {
        man->registerTransformer("break", this);
    }
}

TransformerSaturation::~TransformerSaturation(){
    if (oldInstance) {
        man->update(oldInstance);

    } else {
        man->unregisterTransformer("break", this);
    }
}

llvm::Value*
TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){
    processBreak(ctx);

    return raw;
}


void
TransformerSaturation::processBreak(const Context& ctx){
    allocateFlag(ctx);

    //show the saturation flag
    llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder;
    builder.CreateStore(constTrue, flagSaturation, true);
}

void
TransformerSaturation::allocateFlag(const Context& ctx){
        //allocation of saturation flag
    llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext());
    IRBuilder<> builder(blockAllocation, blockAllocation->getFirstInsertionPt());

    flagSaturation = builder.CreateAlloca(tyInt1, constTrue, "flagSaturation");
    builder.CreateStore(constFalse, flagSaturation, true);
}

bool
TransformerSaturation::insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx){
    if (!flagSaturation) return false;

    llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder;
    builder.CreateCondBr(builder.CreateLoad(flagSaturation), blockExit, blockContinue);

    return true;
}

} }
