18 #include "ExprConfig.h"
30 #ifdef SEEXPR_ENABLE_LLVM
39 class LLVMEvaluationContext {
41 typedef void (*FunctionPtr)(T *,
char **, uint32_t);
42 typedef void (*FunctionPtrMultiple)(
char **, uint32_t, uint32_t, uint32_t);
43 FunctionPtr functionPtr;
44 FunctionPtrMultiple functionPtrMultiple;
48 LLVMEvaluationContext(
const LLVMEvaluationContext &) =
delete;
49 LLVMEvaluationContext &operator=(
const LLVMEvaluationContext &) =
delete;
50 ~LLVMEvaluationContext() {
delete [] resultData;}
51 LLVMEvaluationContext() : functionPtr(nullptr), resultData(nullptr) {}
52 void init(
void *fp,
void *fpLoop,
int dim) {
54 functionPtr =
reinterpret_cast<FunctionPtr
>(fp);
55 functionPtrMultiple =
reinterpret_cast<FunctionPtrMultiple
>(fpLoop);
56 resultData =
new T[dim];
59 if (resultData)
delete[] resultData;
60 functionPtr =
nullptr;
63 const T *operator()(VarBlock *varBlock) {
64 assert(functionPtr && resultData);
65 functionPtr(resultData, varBlock ? varBlock->data() :
nullptr, varBlock ? varBlock->indirectIndex : 0);
68 void operator()(VarBlock *varBlock,
size_t outputVarBlockOffset,
size_t rangeStart,
size_t rangeEnd) {
69 assert(functionPtr && resultData);
70 functionPtrMultiple(varBlock ? varBlock->data() :
nullptr, outputVarBlockOffset, rangeStart, rangeEnd);
73 std::unique_ptr<LLVMEvaluationContext<double>> _llvmEvalFP;
74 std::unique_ptr<LLVMEvaluationContext<char *>> _llvmEvalStr;
76 std::unique_ptr<llvm::LLVMContext> _llvmContext;
77 std::unique_ptr<llvm::ExecutionEngine> TheExecutionEngine;
82 const char *
evalStr(VarBlock *varBlock) {
return *(*_llvmEvalStr)(varBlock); }
84 const double *
evalFP(VarBlock *varBlock) {
return (*_llvmEvalFP)(varBlock); }
85 void evalMultiple(VarBlock *varBlock, uint32_t outputVarBlockOffset, uint32_t rangeStart, uint32_t rangeEnd) {
86 return (*_llvmEvalFP)(varBlock, outputVarBlockOffset, rangeStart, rangeEnd);
93 bool prepLLVM(ExprNode *parseTree, ExprType desiredReturnType) {
95 InitializeNativeTarget();
96 InitializeNativeTargetAsmPrinter();
97 InitializeNativeTargetAsmParser();
99 std::string uniqueName = getUniqueName();
102 _llvmContext.reset(
new LLVMContext());
104 std::unique_ptr<Module> TheModule(
new Module(uniqueName +
"_module", *_llvmContext));
108 Function *SeExpr2LLVMEvalCustomFunctionFunc=
nullptr,*SeExpr2LLVMEvalVarRefFunc=
nullptr;
110 Type *i8PtrTy = Type::getInt8PtrTy(*_llvmContext);
111 Type *i32PtrTy = Type::getInt32PtrTy(*_llvmContext);
112 Type *i64Ty = Type::getInt64Ty(*_llvmContext);
113 Type *doublePtrTy = Type::getDoublePtrTy(*_llvmContext);
114 PointerType *i8PtrPtr = PointerType::getUnqual(i8PtrTy);
115 Type *ParamTys[] = {i32PtrTy, doublePtrTy, i8PtrPtr, i8PtrPtr, i64Ty};
117 FunctionType *FT = FunctionType::get(Type::getVoidTy(*_llvmContext), ParamTys,
false);
118 SeExpr2LLVMEvalCustomFunctionFunc=Function::Create(FT, GlobalValue::ExternalLinkage,
"SeExpr2LLVMEvalCustomFunction", TheModule.get());
120 Type *ParamTys[2] = {i8PtrTy, doublePtrTy};
121 FunctionType *FT = FunctionType::get(Type::getVoidTy(*_llvmContext), ParamTys,
false);
122 SeExpr2LLVMEvalVarRefFunc=Function::Create(FT, GlobalValue::ExternalLinkage,
"SeExpr2LLVMEvalVarRef", TheModule.get());
127 bool desireFP = desiredReturnType.isFP();
128 Type *ParamTys[] = {desireFP ? Type::getDoublePtrTy(*_llvmContext)
129 : PointerType::getUnqual(Type::getInt8PtrTy(*_llvmContext)),
130 PointerType::get(Type::getDoublePtrTy(*_llvmContext),0), Type::getInt32Ty(*_llvmContext), };
131 FunctionType *FT = FunctionType::get(Type::getVoidTy(*_llvmContext), ParamTys,
false);
132 Function *F = Function::Create(FT, Function::ExternalLinkage, uniqueName +
"_func", TheModule.get());
133 F->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::AlwaysInline);
136 const char *names[] = {
"outputPointer",
"dataBlock",
"indirectIndex"};
138 for (
auto &arg : F->args()) arg.setName(names[idx++]);
141 unsigned int dimDesired = (unsigned)desiredReturnType.dim();
142 unsigned int dimGenerated = parseTree->type().dim();
144 BasicBlock *BB = BasicBlock::Create(*_llvmContext,
"entry", F);
145 IRBuilder<> Builder(BB);
148 Value *lastVal = parseTree->codegen(Builder);
151 Value *firstArg = &*F->arg_begin();
153 if (dimGenerated > 1) {
154 Value *newLastVal = promoteToDim(lastVal, dimDesired, Builder);
155 assert(newLastVal->getType()->getVectorNumElements() >= dimDesired);
156 for (
unsigned i = 0; i < dimDesired; ++i) {
157 Value *idx = ConstantInt::get(Type::getInt64Ty(*_llvmContext), i);
158 Value *val = Builder.CreateExtractElement(newLastVal, idx);
159 Value *ptr = Builder.CreateInBoundsGEP(firstArg, idx);
160 Builder.CreateStore(val, ptr);
162 }
else if (dimGenerated == 1) {
163 for (
unsigned i = 0; i < dimDesired; ++i) {
164 Value *ptr = Builder.CreateConstInBoundsGEP1_32(
nullptr, firstArg, i);
165 Builder.CreateStore(lastVal, ptr);
168 assert(
false &&
"error. dim of FP is less than 1.");
171 Builder.CreateStore(lastVal, firstArg);
173 Builder.CreateRetVoid();
177 Type *LOOPParamTys[] = {Type::getInt8PtrTy(*_llvmContext), Type::getInt32Ty(*_llvmContext),
178 Type::getInt32Ty(*_llvmContext), Type::getInt32Ty(*_llvmContext), };
179 FunctionType *FTLOOP = FunctionType::get(Type::getVoidTy(*_llvmContext), LOOPParamTys,
false);
182 Function::Create(FTLOOP, Function::ExternalLinkage, uniqueName +
"_loopfunc", TheModule.get());
185 const char *names[] = {
"dataBlock",
"outputVarBlockOffset",
"rangeStart",
"rangeEnd"};
187 for (
auto &arg : FLOOP->args()) {
188 arg.setName(names[idx++]);
193 Value *dimValue = ConstantInt::get(Type::getInt32Ty(*_llvmContext), dimDesired);
194 Value *oneValue = ConstantInt::get(Type::getInt32Ty(*_llvmContext), 1);
197 BasicBlock *entryBlock = BasicBlock::Create(*_llvmContext,
"entry", FLOOP);
198 BasicBlock *loopCmpBlock = BasicBlock::Create(*_llvmContext,
"loopCmp", FLOOP);
199 BasicBlock *loopRepeatBlock = BasicBlock::Create(*_llvmContext,
"loopRepeat", FLOOP);
200 BasicBlock *loopIncBlock = BasicBlock::Create(*_llvmContext,
"loopInc", FLOOP);
201 BasicBlock *loopEndBlock = BasicBlock::Create(*_llvmContext,
"loopEnd", FLOOP);
202 IRBuilder<> Builder(entryBlock);
203 Builder.SetInsertPoint(entryBlock);
204 Function::arg_iterator argIterator = FLOOP->arg_begin();
206 Value *varBlockCharPtrPtrArg = &*argIterator;
208 Value *outputVarBlockOffsetArg = &*argIterator;
210 Value *rangeStartArg = &*argIterator;
212 Value *rangeEndArg = &*argIterator;
216 Value *rangeStartVar = Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue,
"rangeStartVar");
217 Value *rangeEndVar = Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue,
"rangeEndVar");
218 Value *indexVar = Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue,
"indexVar");
219 Value *outputVarBlockOffsetVar =
220 Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue,
"outputVarBlockOffsetVar");
221 Type *doublePtrPtrTy = llvm::PointerType::get(Type::getDoublePtrTy(*_llvmContext), 0);
222 Value *varBlockDoublePtrPtrVar = Builder.CreateAlloca(doublePtrPtrTy, oneValue,
"varBlockDoublePtrPtrVar");
226 Value *varBlockDoublePtrPtr =
227 Builder.CreatePointerCast(varBlockCharPtrPtrArg, doublePtrPtrTy,
"varBlockAsDoublePtrPtr");
228 Builder.CreateStore(varBlockDoublePtrPtr, varBlockDoublePtrPtrVar);
229 Builder.CreateStore(rangeStartArg, rangeStartVar);
230 Builder.CreateStore(rangeEndArg, rangeEndVar);
231 Builder.CreateStore(outputVarBlockOffsetArg, outputVarBlockOffsetVar);
234 Value *outputBasePtrPtr = Builder.CreateGEP(
235 nullptr, Builder.CreateLoad(varBlockDoublePtrPtrVar), outputVarBlockOffsetArg,
"outputBasePtrPtr");
236 Value *outputBasePtr = Builder.CreateLoad(outputBasePtrPtr,
"outputBasePtr");
240 Builder.CreateStore(Builder.CreateLoad(rangeStartVar), indexVar);
242 Builder.CreateBr(loopCmpBlock);
244 Builder.SetInsertPoint(loopCmpBlock);
245 Value *cond = Builder.CreateICmpULT(Builder.CreateLoad(indexVar), Builder.CreateLoad(rangeEndVar));
246 Builder.CreateCondBr(cond, loopRepeatBlock, loopEndBlock);
248 Builder.SetInsertPoint(loopRepeatBlock);
250 Builder.CreateGEP(
nullptr, outputBasePtr, Builder.CreateMul(dimValue, Builder.CreateLoad(indexVar)));
252 F, {myOutputPtr, Builder.CreateLoad(varBlockDoublePtrPtrVar), Builder.CreateLoad(indexVar)});
256 Builder.CreateBr(loopIncBlock);
258 Builder.SetInsertPoint(loopIncBlock);
259 Builder.CreateStore(Builder.CreateAdd(Builder.CreateLoad(indexVar), oneValue), indexVar);
262 Builder.CreateBr(loopCmpBlock);
264 Builder.SetInsertPoint(loopEndBlock);
265 Builder.CreateRetVoid();
269 std::cerr <<
"Pre verified LLVM byte code " << std::endl;
278 Module *altModule = TheModule.get();
280 TheExecutionEngine.reset(EngineBuilder(std::move(TheModule))
281 .setErrorStr(&ErrStr)
283 .setOptLevel(CodeGenOpt::Aggressive)
286 altModule->setDataLayout(TheExecutionEngine->getDataLayout());
294 std::string errorStr;
295 llvm::raw_string_ostream raw(errorStr);
296 if(llvm::verifyModule(*altModule,&raw)){
297 parseTree->addError(raw.str());
302 llvm::PassManagerBuilder builder;
303 std::unique_ptr<llvm::legacy::PassManager> pm(
new llvm::legacy::PassManager);
304 std::unique_ptr<llvm::legacy::FunctionPassManager> fpm(
new llvm::legacy::FunctionPassManager(altModule));
305 builder.OptLevel = 3;
306 builder.Inliner = llvm::createAlwaysInlinerPass();
307 builder.populateModulePassManager(*pm);
309 builder.populateFunctionPassManager(*fpm);
316 if (!TheExecutionEngine) {
317 fprintf(stderr,
"Could not create ExecutionEngine: %s\n", ErrStr.c_str());
321 TheExecutionEngine->finalizeObject();
322 void *fp = TheExecutionEngine->getPointerToFunction(F);
323 void *fpLoop = TheExecutionEngine->getPointerToFunction(FLOOP);
325 _llvmEvalFP.reset(
new LLVMEvaluationContext<double>);
326 _llvmEvalFP->init(fp, fpLoop, dimDesired);
328 _llvmEvalStr.reset(
new LLVMEvaluationContext<char *>);
329 _llvmEvalStr->init(fp, fpLoop, dimDesired);
333 std::cerr <<
"Pre verified LLVM byte code " << std::endl;
340 std::string getUniqueName()
const {
341 std::ostringstream o;
342 o << std::setbase(16) << (uint64_t)(
this);
343 return (
"_" + o.str());
347 #else // no LLVM support
350 void unsupported() {
throw std::runtime_error(
"LLVM is not enabled in build"); }
A thread local evaluation context. Just allocate and fill in with data.
void SeExpr2LLVMEvalCustomFunction(int *opDataArg, double *fpArg, char **strArg, void **funcdata, const SeExpr2::ExprFuncNode *node)
void evalMultiple(VarBlock *varBlock, int outputVarBlockOffset, size_t rangeStart, size_t rangeEnd)
Node that calls a function.
static bool debugging
Whether to debug expressions.
bool prepLLVM(ExprNode *parseTree, ExprType desiredReturnType)
const char * evalStr(VarBlock *varBlock)
void SeExpr2LLVMEvalVarRef(SeExpr2::ExprVarRef *seVR, double *result)
const double * evalFP(VarBlock *varBlock)
abstract class for implementing variable references