llvmlayer.cpp
No OneTemporary

File Metadata

Created
Tue, Jul 7, 10:51 AM

llvmlayer.cpp

/* 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/.
*
* llvmlayer.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
*/
/**
* \file llvmlayer.h
* \brief Bytecode generation
*/
#include "ast.h"
#include "llvmlayer.h"
#include "analysis/typehints.h"
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include <compilation/containers.h>
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/Support/TargetSelect.h"
#include <iostream>
#include <cmath>
using namespace llvm;
using namespace xreate;
using namespace xreate::typehints;
using namespace std;
LLVMLayer::LLVMLayer(AST *root)
: llvmContext(),
irBuilder(llvmContext),
ast(root),
module(new llvm::Module(root->getModuleName(), llvmContext)){
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::EngineBuilder builder;
TargetMachine *target = builder.selectTarget();
module->setDataLayout(target->createDataLayout());
#ifdef XREATE_ENABLE_EXTERN
layerExtern = new ExternLayer(this);
layerExtern->init(root);
#endif
}
void *
LLVMLayer::getFunctionPointer(llvm::Function *function){
uint64_t entryAddr = jit->getFunctionAddress(function->getName().str());
return (void *) entryAddr;
}
void
LLVMLayer::initJit(){
std::string ErrStr;
llvm::EngineBuilder builder(std::unique_ptr<llvm::Module>(module.release()));
jit.reset(builder
.setEngineKind(llvm::EngineKind::JIT)
.setTargetOptions(optsTarget)
.setOptLevel(optsLevel)
.setErrorStr(&ErrStr)
.setVerifyModules(true)
.create()
);
}
void
LLVMLayer::print(){
llvm::PassManager<llvm::Module> PM;
PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner"));
llvm::AnalysisManager<llvm::Module> aman;
PM.run(*module.get(), aman);
}
void
LLVMLayer::moveToGarbage(void *o){
__garbage.push_back(o);
}
llvm::Type*
LLVMLayer::toLLVMType(const ExpandedType &ty, const Expression& expr){
TypeAnnotation t = ty.get();
switch(t.__operator){
case TypeOperator::ARRAY:{
if (expr.tags.size() == 0) return nullptr; //TODO shouldn't be invalid
return containers::IContainersIR::getRawType(expr, ty, this);
}
case TypeOperator::RECORD:{
std::vector<llvm::Type *> packVec;
packVec.reserve(t.__operands.size());
std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(packVec, packVec.end()),
[this](const TypeAnnotation &t){
return toLLVMType(ExpandedType(TypeAnnotation(t)));
});
llvm::ArrayRef<llvm::Type *> packArr(packVec);
return llvm::StructType::get(llvmContext, packArr, false);
};
case TypeOperator::REF:{
TypeAnnotation tyRef = t.__operands.at(0);
assert(tyRef.__operator == TypeOperator::ALIAS);
llvm::StructType *tyOpaqRaw = llvm::StructType::create(llvmContext, tyRef.__valueCustom);
llvm::PointerType *tyRefRaw = llvm::PointerType::get(tyOpaqRaw, 0);
return tyRefRaw;
};
case TypeOperator::ALIAS:{
#ifdef XREATE_ENABLE_EXTERN
//Look in extern types
clang::QualType qt = layerExtern->lookupType(t.__valueCustom);
return layerExtern->toLLVMType(qt);
#else
assert(false);
#endif
};
//DEBT omit ID field in case of single variant.
case TypeOperator::VARIANT:{
/* Variant Type Layout:
* {
* id :: i8, Holds stored variant id
* storage:: type of biggest variant
* }
*/
uint64_t sizeStorage = 0;
llvm::Type *typStorageRaw = llvm::Type::getVoidTy(llvmContext);
for(const TypeAnnotation &subtype : t.__operands){
llvm::Type *subtypeRaw = toLLVMType(ExpandedType(subtype));
if(subtypeRaw->isVoidTy()) continue;
uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw);
if(sizeSubtype > sizeStorage){
sizeStorage = sizeSubtype;
typStorageRaw = subtypeRaw;
}
}
std::vector<llvm::Type *> layout;
layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id
const bool flagHoldsData = sizeStorage > 0;
if(flagHoldsData){
layout.push_back(typStorageRaw); //storage
}
return llvm::StructType::get(llvmContext, llvm::ArrayRef<llvm::Type *>(layout));
}
case TypeOperator::NONE:{
switch(t.__value){
case TypePrimitive::Bool:
return llvm::Type::getInt1Ty(llvmContext);
case TypePrimitive::I8:
return llvm::Type::getInt8Ty(llvmContext);
case TypePrimitive::I32:
return llvm::Type::getInt32Ty(llvmContext);
case TypePrimitive::I64:
return llvm::Type::getInt64Ty(llvmContext);
case TypePrimitive::Int: {
// IntBits hintSize;
// if (existsSize(hintSize)){
// return llvm::IntegerType::getIntNTy(llvmContext, hintSize.n);
// }
TypesHelper helper(this);
return helper.getPreferredIntTy();
}
case TypePrimitive::Float:
return llvm::Type::getDoubleTy(llvmContext);
case TypePrimitive::String:
return llvm::Type::getInt8PtrTy(llvmContext);
case TypePrimitive::Invalid:
return llvm::Type::getVoidTy(llvmContext);
default:
assert(false);
}
}
default:
assert(false);
}
assert(false);
return nullptr;
}
bool
TypesHelper::isRecordT(const ExpandedType &ty){
const TypeAnnotation &t = ty.get();
if(t.__operator == TypeOperator::RECORD){
return true;
}
if(t.__operator != TypeOperator::ALIAS){
return false;
}
#ifdef XREATE_ENABLE_EXTERN
clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom);
const clang::Type * raw = tqual.getTypePtr();
// TODO skip ALL the pointers until non-pointer type found
if (raw->isStructureType()) return true;
if (!raw->isAnyPointerType()) return false;
clang::QualType pointee = raw->getPointeeType();
return pointee->isStructureType();
#else
assert(false);
return false;
#endif
}
bool
TypesHelper::isArrayT(const Expanded<TypeAnnotation>& ty){
const TypeAnnotation &t = ty.get();
if(t.__operator == TypeOperator::ARRAY){
return true;
}
return false;
}
bool
TypesHelper::isPointerT(const ExpandedType &ty){
if(ty.get().__operator != TypeOperator::ALIAS) return false;
#ifdef XREATE_ENABLE_EXTERN
clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom);
return llvm->layerExtern->isPointer(qt);
#else
assert(false);
return false;
#endif
}
bool
TypesHelper::isIntegerT(const Expanded<TypeAnnotation>& ty){
return
(ty->__operator == TypeOperator::NONE) &&
((ty->__value == TypePrimitive::Bool) ||
(ty->__value == TypePrimitive::I8) ||
(ty->__value == TypePrimitive::I32) ||
(ty->__value == TypePrimitive::I64) ||
(ty->__value == TypePrimitive::Int));
}
std::vector<std::string>
TypesHelper::getRecordFields(const ExpandedType &t){
#ifdef XREATE_ENABLE_EXTERN
return (t.get().__operator == TypeOperator::RECORD)
? t.get().fields
: llvm->layerExtern->getStructFields(
llvm->layerExtern->lookupType(t.get().__valueCustom));
#else
assert(t.get().__operator == TypeOperator::RECORD);
return t.get().fields;
#endif
}
llvm::IntegerType *
TypesHelper::getPreferredIntTy() const{
unsigned sizePreferred = llvm->module->getDataLayout().getLargestLegalIntTypeSizeInBits();
return llvm::IntegerType::getIntNTy(llvm->llvmContext, sizePreferred);
}

Event Timeline