/* 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/.
 *
 * File:   context.cpp
 * Author: pgess <v.melnychenko@xreate.org>
 *
 * Created on 25/05/2020
 */

#include "query/contextalloc.h"
#include "compilation/context.h"
#include "llvmlayer.h"
#include "llvm/IR/GlobalVariable.h"

namespace xreate { namespace compilation{

AllocContext*
ContextManager::getContext(const std::string& id){
  if(__contexts.count(id)) return __contexts.at(id);

  AllocContext* context = new AllocContext(id, this, nullptr);
  __contexts.emplace(id, context);
  return context;
}

void
AllocContext::set(const ASTSite& varS, llvm::Value* varRaw){
  LLVMLayer* llvm = __man->__pass->man->llvm;
  GlobalContextTable* tableGlobal = __man->__pass->getGlobalContextTable();

  llvm::Value* varStorage = tableGlobal->getVariable(varS);
  llvm->irBuilder.CreateStore(varRaw, varStorage);
}

llvm::Value*
AllocContext::get(const ASTSite& varS){
  LLVMLayer* llvm = __man->__pass->man->llvm;
  GlobalContextTable* tableGlobal = __man->__pass->getGlobalContextTable();

  llvm::Value* varStorage = tableGlobal->getVariable(varS);
  return llvm->irBuilder.CreateLoad(varStorage);
}

void
GlobalContextTable::compile(){
  LLVMLayer* llvm = __pass->man->llvm;
  TranscendLayer* transcend = __pass->man->transcend;
  ContextAllocQuery* query = dynamic_cast<ContextAllocQuery*>(transcend->getQuery(QueryId::ContextAllocQuery));
  llvm::Type* int8PT = llvm::PointerType::getInt8PtrTy(llvm->llvmContext);

  ContextAllocQuery::Model model = query->getModel();
  for(const auto& entry: model){
    llvm::GlobalVariable* varRaw = new llvm::GlobalVariable(
      *(llvm->module.get()), int8PT, false,
      llvm::GlobalValue::PrivateLinkage,
      llvm::UndefValue::get(int8PT)
    );

    __table.emplace(entry.second, varRaw);
  }
}

}} // xreate::compilation