KSeExpr  4.0.4.0
Evaluator.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2019 Disney Enterprises, Inc.
2 // SPDX-License-Identifier: LicenseRef-Apache-2.0
3 // SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 
6 #include <cstdint>
7 
8 #include "ExprConfig.h"
9 #include "ExprLLVMAll.h"
10 #include "ExprNode.h"
11 #include "VarBlock.h"
12 
13 extern "C" void KSeExprLLVMEvalFPVarRef(KSeExpr::ExprVarRef *seVR, double *result);
14 extern "C" void KSeExprLLVMEvalStrVarRef(KSeExpr::ExprVarRef *seVR, double *result);
15 extern "C" void KSeExprLLVMEvalCustomFunction(int *opDataArg, double *fpArg, char **strArg, void **funcdata, const KSeExpr::ExprFuncNode *node);
16 
17 namespace KSeExpr
18 {
19 #if defined(SEEXPR_ENABLE_LLVM)
20 
21 LLVM_VALUE promoteToDim(LLVM_VALUE val, unsigned dim, llvm::IRBuilder<> &Builder);
22 
23 class LLVMEvaluator
24 {
25  // TODO: this seems needlessly complex, let's fix it
26  // TODO: let the dev code allocate memory?
27  // FP is the native function for this expression.
28  template<class T> class LLVMEvaluationContext
29  {
30  private:
31  using FunctionPtr = void (*)(T *, char **, uint32_t);
32  using FunctionPtrMultiple = void (*)(char **, uint32_t, uint32_t, uint32_t);
33  FunctionPtr functionPtr{nullptr};
34  FunctionPtrMultiple functionPtrMultiple{nullptr};
35  T *resultData{nullptr};
36 
37  public:
38  LLVMEvaluationContext(const LLVMEvaluationContext &) = delete;
39  LLVMEvaluationContext &operator=(const LLVMEvaluationContext &) = delete;
40  LLVMEvaluationContext(LLVMEvaluationContext &&) noexcept = default;
41  LLVMEvaluationContext& operator=(LLVMEvaluationContext &&) noexcept = default;
42  ~LLVMEvaluationContext()
43  {
44  delete[] resultData;
45  }
46  LLVMEvaluationContext() = default;
47 
48  void init(void *fp, void *fpLoop, int dim)
49  {
50  reset();
51  functionPtr = reinterpret_cast<FunctionPtr>(fp);
52  functionPtrMultiple = reinterpret_cast<FunctionPtrMultiple>(fpLoop);
53  resultData = new T[dim];
54  }
55  void reset()
56  {
57  delete[] resultData;
58  resultData = nullptr;
59  functionPtr = nullptr;
60  resultData = nullptr;
61  }
62  const T *operator()(VarBlock *varBlock)
63  {
64  assert(functionPtr && resultData);
65  functionPtr(resultData, varBlock ? varBlock->data() : nullptr, varBlock ? varBlock->indirectIndex : 0);
66  return resultData;
67  }
68  void operator()(VarBlock *varBlock, size_t outputVarBlockOffset, size_t rangeStart, size_t rangeEnd)
69  {
70  assert(functionPtr && resultData);
71  functionPtrMultiple(varBlock ? varBlock->data() : nullptr, outputVarBlockOffset, rangeStart, rangeEnd);
72  }
73  };
74  std::unique_ptr<LLVMEvaluationContext<double>> _llvmEvalFP;
75  std::unique_ptr<LLVMEvaluationContext<char *>> _llvmEvalStr;
76 
77  std::unique_ptr<llvm::LLVMContext> _llvmContext;
78  std::unique_ptr<llvm::ExecutionEngine> TheExecutionEngine;
79 
80 public:
81  LLVMEvaluator() = default;
82 
83  const char *evalStr(VarBlock *varBlock)
84  {
85  return *(*_llvmEvalStr)(varBlock);
86  }
87  const double *evalFP(VarBlock *varBlock)
88  {
89  return (*_llvmEvalFP)(varBlock);
90  }
91 
92  void evalMultiple(VarBlock *varBlock, uint32_t outputVarBlockOffset, uint32_t rangeStart, uint32_t rangeEnd)
93  {
94  return (*_llvmEvalFP)(varBlock, outputVarBlockOffset, rangeStart, rangeEnd);
95  }
96 
97  void debugPrint()
98  {
99  // TheModule->print(llvm::errs(), nullptr);
100  }
101 
102  bool prepLLVM(ExprNode *parseTree, const ExprType &desiredReturnType)
103  {
104  using namespace llvm;
105  InitializeNativeTarget();
106  InitializeNativeTargetAsmPrinter();
107  InitializeNativeTargetAsmParser();
108 
109  std::string uniqueName = getUniqueName();
110 
111  // create Module
112  _llvmContext = std::make_unique<LLVMContext>();
113 
114  std::unique_ptr<Module> TheModule(new Module(uniqueName + "_module", *_llvmContext));
115 
116  // create all needed types
117  Type *i8PtrTy = Type::getInt8PtrTy(*_llvmContext); // char *
118  PointerType *i8PtrPtrTy = PointerType::getUnqual(i8PtrTy); // char **
119  PointerType *i8PtrPtrPtrTy = PointerType::getUnqual(i8PtrPtrTy); // char ***
120  Type *i32Ty = Type::getInt32Ty(*_llvmContext); // int
121  Type *i32PtrTy = Type::getInt32PtrTy(*_llvmContext); // int *
122  Type *i64Ty = Type::getInt64Ty(*_llvmContext); // int64 *
123  Type *doublePtrTy = Type::getDoublePtrTy(*_llvmContext); // double *
124  PointerType *doublePtrPtrTy = PointerType::getUnqual(doublePtrTy); // double **
125  Type *voidTy = Type::getVoidTy(*_llvmContext); // void
126 
127  // create bindings to helper functions for variables and fucntions
128  Function *KSeExprLLVMEvalCustomFunctionFunc = nullptr;
129  Function *KSeExprLLVMEvalFPVarRefFunc = nullptr;
130  Function *KSeExprLLVMEvalStrVarRefFunc = nullptr;
131  Function *KSeExprLLVMEvalstrlenFunc = nullptr;
132  Function *KSeExprLLVMEvalmallocFunc = nullptr;
133  Function *KSeExprLLVMEvalfreeFunc = nullptr;
134  Function *KSeExprLLVMEvalmemsetFunc = nullptr;
135  Function *KSeExprLLVMEvalstrcatFunc = nullptr;
136  Function *KSeExprLLVMEvalstrcmpFunc = nullptr;
137  {
138  {
139  FunctionType *FT = FunctionType::get(voidTy, {i32PtrTy, doublePtrTy, i8PtrPtrTy, i8PtrPtrTy, i64Ty}, false);
140  KSeExprLLVMEvalCustomFunctionFunc = Function::Create(FT, GlobalValue::ExternalLinkage, "KSeExprLLVMEvalCustomFunction", TheModule.get());
141  }
142  {
143  FunctionType *FT = FunctionType::get(voidTy, {i8PtrTy, doublePtrTy}, false);
144  KSeExprLLVMEvalFPVarRefFunc = Function::Create(FT, GlobalValue::ExternalLinkage, "KSeExprLLVMEvalFPVarRef", TheModule.get());
145  }
146  {
147  FunctionType *FT = FunctionType::get(voidTy, {i8PtrTy, i8PtrPtrTy}, false);
148  KSeExprLLVMEvalStrVarRefFunc = Function::Create(FT, GlobalValue::ExternalLinkage, "KSeExprLLVMEvalStrVarRef", TheModule.get());
149  }
150  {
151  FunctionType *FT = FunctionType::get(i32Ty, {i8PtrTy}, false);
152  KSeExprLLVMEvalstrlenFunc = Function::Create(FT, Function::ExternalLinkage, "strlen", TheModule.get());
153  }
154  {
155  FunctionType *FT = FunctionType::get(i8PtrTy, {i32Ty}, false);
156  KSeExprLLVMEvalmallocFunc = Function::Create(FT, Function::ExternalLinkage, "malloc", TheModule.get());
157  }
158  {
159  FunctionType *FT = FunctionType::get(voidTy, {i8PtrTy}, false);
160  KSeExprLLVMEvalfreeFunc = Function::Create(FT, Function::ExternalLinkage, "free", TheModule.get());
161  }
162  {
163  FunctionType *FT = FunctionType::get(voidTy, {i8PtrTy, i32Ty, i32Ty}, false);
164  KSeExprLLVMEvalmemsetFunc = Function::Create(FT, Function::ExternalLinkage, "memset", TheModule.get());
165  }
166  {
167  FunctionType *FT = FunctionType::get(i8PtrTy, {i8PtrTy, i8PtrTy}, false);
168  KSeExprLLVMEvalstrcatFunc = Function::Create(FT, Function::ExternalLinkage, "strcat", TheModule.get());
169  }
170  {
171  FunctionType *FT = FunctionType::get(i32Ty, {i8PtrTy, i8PtrTy}, false);
172  KSeExprLLVMEvalstrcmpFunc = Function::Create(FT, Function::ExternalLinkage, "strcmp", TheModule.get());
173  }
174  }
175 
176  // create function and entry BB
177  bool desireFP = desiredReturnType.isFP();
178  std::array<Type *, 3> ParamTys = {desireFP ? doublePtrTy : i8PtrPtrTy, doublePtrPtrTy, i32Ty};
179  FunctionType *FT = FunctionType::get(voidTy, ParamTys, false);
180  Function *F = Function::Create(FT, Function::ExternalLinkage, uniqueName + "_func", TheModule.get());
181 #if LLVM_VERSION_MAJOR > 4
182  F->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::AlwaysInline);
183 #else
184  F->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::AlwaysInline);
185 #endif
186  {
187  // label the function with names
188  std::array<const char *, 3> names = {"outputPointer", "dataBlock", "indirectIndex"};
189  int idx = 0;
190  for (auto &arg : F->args())
191  arg.setName(names[idx++]);
192  }
193 
194  auto dimDesired = desiredReturnType.dim();
195  auto dimGenerated = parseTree->type().dim();
196  {
197  BasicBlock *BB = BasicBlock::Create(*_llvmContext, "entry", F);
198  IRBuilder<> Builder(BB);
199 
200  // codegen
201  Value *lastVal = parseTree->codegen(Builder);
202 
203  // return values through parameter.
204  Value *firstArg = &*F->arg_begin();
205  if (desireFP) {
206  Value *newLastVal = promoteToDim(lastVal, dimDesired, Builder);
207  if (newLastVal->getType()->isVectorTy()) {
208  // Output is vector - copy values (if possible)
209 
210  assert(dimDesired >= 1 && "error. dim of FP is less than 1.");
211 
212  assert(dimGenerated >= 1 && "error. dim of FP is less than 1.");
213 
214  assert(dimGenerated == 1 || dimGenerated >= dimDesired && "error: unable to match between FP of differing dimensions");
215 
216  auto *VT = llvm::cast<llvm::VectorType>(newLastVal->getType());
217 #if LLVM_VERSION_MAJOR >= 13
218  if (VT && VT->getElementCount().getKnownMinValue() >= dimDesired) {
219 #else
220  if (VT && VT->getNumElements() >= dimDesired) {
221 #endif
222  for (unsigned i = 0; i < dimDesired; ++i) {
223  Value *idx = ConstantInt::get(Type::getInt64Ty(*_llvmContext), i);
224  Value *val = Builder.CreateExtractElement(newLastVal, idx);
225  Value *ptr = IN_BOUNDS_GEP(Builder, firstArg, idx);
226  Builder.CreateStore(val, ptr);
227  }
228  } else {
229  for (unsigned i = 0; i < dimDesired; ++i) {
230  Value *idx = ConstantInt::get(Type::getInt64Ty(*_llvmContext), i);
231  Value *original_idx = ConstantInt::get(Type::getInt64Ty(*_llvmContext), 0);
232  Value *val = Builder.CreateExtractElement(newLastVal, original_idx);
233  Value *ptr = IN_BOUNDS_GEP(Builder, firstArg, idx);
234  Builder.CreateStore(val, ptr);
235  }
236  }
237  } else {
238  if (dimGenerated > 1) {
239  Value *newLastVal = promoteToDim(lastVal, dimDesired, Builder);
240 #ifndef NDEBUG
241  auto *VT = llvm::cast<llvm::VectorType>(newLastVal->getType());
242 #if LLVM_VERSION_MAJOR >= 13
243  assert(VT && VT->getElementCount().getKnownMinValue() >= dimDesired);
244 #else
245  assert(VT && VT->getNumElements() >= dimDesired);
246 #endif
247 #endif
248  for (unsigned i = 0; i < dimDesired; ++i) {
249  Value *idx = ConstantInt::get(Type::getInt64Ty(*_llvmContext), i);
250  Value *val = Builder.CreateExtractElement(newLastVal, idx);
251  Value *ptr = IN_BOUNDS_GEP(Builder, firstArg, idx);
252  Builder.CreateStore(val, ptr);
253  }
254  } else if (dimGenerated == 1) {
255  for (unsigned i = 0; i < dimDesired; ++i) {
256  Value *ptr = Builder.CreateConstInBoundsGEP1_32(nullptr, firstArg, i);
257  Builder.CreateStore(lastVal, ptr);
258  }
259  } else {
260  assert(false && "error. dim of FP is less than 1.");
261  }
262  }
263  } else {
264  Builder.CreateStore(lastVal, firstArg);
265  }
266 
267  Builder.CreateRetVoid();
268  }
269 
270  // write a new function
271  FunctionType *FTLOOP = FunctionType::get(voidTy, {i8PtrTy, i32Ty, i32Ty, i32Ty}, false);
272  Function *FLOOP = Function::Create(FTLOOP, Function::ExternalLinkage, uniqueName + "_loopfunc", TheModule.get());
273  {
274  // label the function with names
275  std::array<const char *, 4> names = {"dataBlock", "outputVarBlockOffset", "rangeStart", "rangeEnd"};
276  int idx = 0;
277  for (auto &arg : FLOOP->args()) {
278  arg.setName(names[idx++]);
279  }
280  }
281  {
282  // Local variables
283  Value *dimValue = ConstantInt::get(i32Ty, dimDesired);
284  Value *oneValue = ConstantInt::get(i32Ty, 1);
285 
286  // Basic blocks
287  BasicBlock *entryBlock = BasicBlock::Create(*_llvmContext, "entry", FLOOP);
288  BasicBlock *loopCmpBlock = BasicBlock::Create(*_llvmContext, "loopCmp", FLOOP);
289  BasicBlock *loopRepeatBlock = BasicBlock::Create(*_llvmContext, "loopRepeat", FLOOP);
290  BasicBlock *loopIncBlock = BasicBlock::Create(*_llvmContext, "loopInc", FLOOP);
291  BasicBlock *loopEndBlock = BasicBlock::Create(*_llvmContext, "loopEnd", FLOOP);
292  IRBuilder<> Builder(entryBlock);
293  Builder.SetInsertPoint(entryBlock);
294 
295  // Get arguments
296  Function::arg_iterator argIterator = FLOOP->arg_begin();
297  Value *varBlockCharPtrPtrArg = &*argIterator;
298  ++argIterator;
299  Value *outputVarBlockOffsetArg = &*argIterator;
300  ++argIterator;
301  Value *rangeStartArg = &*argIterator;
302  ++argIterator;
303  Value *rangeEndArg = &*argIterator;
304  ++argIterator;
305 
306  // Allocate Variables
307  Value *rangeStartVar = Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue, "rangeStartVar");
308  Value *rangeEndVar = Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue, "rangeEndVar");
309  Value *indexVar = Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue, "indexVar");
310  Value *outputVarBlockOffsetVar = Builder.CreateAlloca(Type::getInt32Ty(*_llvmContext), oneValue, "outputVarBlockOffsetVar");
311  Value *varBlockDoublePtrPtrVar = Builder.CreateAlloca(doublePtrPtrTy, oneValue, "varBlockDoublePtrPtrVar");
312  Value *varBlockTPtrPtrVar = Builder.CreateAlloca(desireFP == true ? doublePtrPtrTy : i8PtrPtrPtrTy, oneValue, "varBlockTPtrPtrVar");
313 
314  // Copy variables from args
315  Builder.CreateStore(Builder.CreatePointerCast(varBlockCharPtrPtrArg, doublePtrPtrTy, "varBlockAsDoublePtrPtr"), varBlockDoublePtrPtrVar);
316  Builder.CreateStore(Builder.CreatePointerCast(varBlockCharPtrPtrArg, desireFP ? doublePtrPtrTy : i8PtrPtrPtrTy, "varBlockAsTPtrPtr"), varBlockTPtrPtrVar);
317  Builder.CreateStore(rangeStartArg, rangeStartVar);
318  Builder.CreateStore(rangeEndArg, rangeEndVar);
319  Builder.CreateStore(outputVarBlockOffsetArg, outputVarBlockOffsetVar);
320 
321  // Set output pointer
322  Value *outputBasePtrPtr = Builder.CreateGEP(nullptr, CREATE_LOAD(Builder, varBlockTPtrPtrVar), outputVarBlockOffsetArg, "outputBasePtrPtr");
323  Value *outputBasePtr = CREATE_LOAD_WITH_ID(Builder, outputBasePtrPtr, "outputBasePtr");
324  Builder.CreateStore(CREATE_LOAD(Builder, rangeStartVar), indexVar);
325 
326  Builder.CreateBr(loopCmpBlock);
327  Builder.SetInsertPoint(loopCmpBlock);
328  Value *cond = Builder.CreateICmpULT(CREATE_LOAD(Builder, indexVar), CREATE_LOAD(Builder, rangeEndVar));
329  Builder.CreateCondBr(cond, loopRepeatBlock, loopEndBlock);
330 
331  Builder.SetInsertPoint(loopRepeatBlock);
332  Value *myOutputPtr = Builder.CreateGEP(nullptr, outputBasePtr, Builder.CreateMul(dimValue, CREATE_LOAD(Builder, indexVar)));
333  Builder.CreateCall(F, {myOutputPtr, CREATE_LOAD(Builder, varBlockDoublePtrPtrVar), CREATE_LOAD(Builder, indexVar)});
334 
335  Builder.CreateBr(loopIncBlock);
336 
337  Builder.SetInsertPoint(loopIncBlock);
338  Builder.CreateStore(Builder.CreateAdd(CREATE_LOAD(Builder, indexVar), oneValue), indexVar);
339  Builder.CreateBr(loopCmpBlock);
340 
341  Builder.SetInsertPoint(loopEndBlock);
342  Builder.CreateRetVoid();
343  }
344 
345  if (Expression::debugging) {
346 #ifdef DEBUG
347  std::cerr << "Pre verified LLVM byte code " << std::endl;
348  TheModule->print(llvm::errs(), nullptr);
349 #endif
350  }
351 
352  // TODO: Find out if there is a new way to veirfy
353  // if (verifyModule(*TheModule)) {
354  // std::cerr << "Logic error in code generation of LLVM alert developers" << std::endl;
355  // TheModule->print(llvm::errs(), nullptr);
356  // }
357  Module *altModule = TheModule.get();
358  std::string ErrStr;
359  TheExecutionEngine.reset(EngineBuilder(std::move(TheModule))
360  .setErrorStr(&ErrStr)
361  // .setUseMCJIT(true)
362  .setOptLevel(CodeGenOpt::Aggressive)
363  .create());
364 
365  altModule->setDataLayout(TheExecutionEngine->getDataLayout());
366 
367  // Add bindings to C linkage helper functions
368  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalFPVarRefFunc,
369  reinterpret_cast<void *>(KSeExprLLVMEvalFPVarRef));
370  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalStrVarRefFunc,
371  reinterpret_cast<void *>(KSeExprLLVMEvalStrVarRef));
372  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalCustomFunctionFunc,
373  reinterpret_cast<void *>(KSeExprLLVMEvalCustomFunction));
374  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalstrlenFunc,
375  reinterpret_cast<void *>(strlen));
376  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalstrcatFunc,
377  reinterpret_cast<void *>(strcat));
378  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalstrcmpFunc,
379  reinterpret_cast<void *>(strcmp));
380  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalmemsetFunc,
381  reinterpret_cast<void *>(memset));
382  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalmallocFunc,
383  reinterpret_cast<void *>(malloc));
384  TheExecutionEngine->addGlobalMapping(KSeExprLLVMEvalfreeFunc,
385  reinterpret_cast<void *>(free));
386 
387  // [verify]
388  std::string errorStr;
389  llvm::raw_string_ostream raw(errorStr);
390  if (llvm::verifyModule(*altModule, &raw)) {
391  parseTree->addError(ErrorCode::Unknown, {errorStr});
392  return false;
393  }
394 
395  // Setup optimization
396  llvm::PassManagerBuilder builder;
397  std::unique_ptr<llvm::legacy::PassManager> pm(new llvm::legacy::PassManager);
398  std::unique_ptr<llvm::legacy::FunctionPassManager> fpm(new llvm::legacy::FunctionPassManager(altModule));
399  builder.OptLevel = 3;
400 #if (LLVM_VERSION_MAJOR >= 4)
401  builder.Inliner = llvm::createAlwaysInlinerLegacyPass();
402 #else
403  builder.Inliner = llvm::createAlwaysInlinerPass();
404 #endif
405  builder.populateModulePassManager(*pm);
406  // fpm->add(new llvm::DataLayoutPass());
407  builder.populateFunctionPassManager(*fpm);
408  fpm->run(*F);
409  fpm->run(*FLOOP);
410  pm->run(*altModule);
411 
412  // Create the JIT. This takes ownership of the module.
413 
414  if (!TheExecutionEngine) {
415  std::cerr << "Could not create ExecutionEngine: " << ErrStr << std::endl;
416  exit(1);
417  }
418 
419  TheExecutionEngine->finalizeObject();
420  void *fp = TheExecutionEngine->getPointerToFunction(F);
421  void *fpLoop = TheExecutionEngine->getPointerToFunction(FLOOP);
422  if (desireFP) {
423  _llvmEvalFP = std::make_unique<LLVMEvaluationContext<double>>();
424  _llvmEvalFP->init(fp, fpLoop, dimDesired);
425  } else {
426  _llvmEvalStr = std::make_unique<LLVMEvaluationContext<char *>>();
427  _llvmEvalStr->init(fp, fpLoop, dimDesired);
428  }
429 
430  if (Expression::debugging) {
431 #ifdef DEBUG
432  std::cerr << "Pre verified LLVM byte code " << std::endl;
433  altModule->print(llvm::errs(), nullptr);
434 #endif
435  }
436 
437  return true;
438  }
439 
440  std::string getUniqueName() const
441  {
442  std::ostringstream o;
443  o << std::setbase(16) << reinterpret_cast<uintptr_t>(this);
444  return ("_" + o.str());
445  }
446 };
447 
448 #else // no LLVM support
450 {
451 public:
452  static void unsupported()
453  {
454  assert(false && "LLVM is not enabled in build");
455  }
456  static const char *evalStr(VarBlock *)
457  {
458  unsupported();
459  return nullptr;
460  }
461  static const double *evalFP(VarBlock *)
462  {
463  unsupported();
464  return nullptr;
465  }
466  static bool prepLLVM(ExprNode *, ExprType)
467  {
468  unsupported();
469  return false;
470  }
471  static void evalMultiple(VarBlock *, int, size_t, size_t)
472  {
473  unsupported();
474  }
475  void debugPrint()
476  {
477  }
478 };
479 #endif
480 
481 } // end namespace KSeExpr
void KSeExprLLVMEvalFPVarRef(KSeExpr::ExprVarRef *seVR, double *result)
void KSeExprLLVMEvalStrVarRef(KSeExpr::ExprVarRef *seVR, double *result)
void KSeExprLLVMEvalCustomFunction(int *opDataArg, double *fpArg, char **strArg, void **funcdata, const KSeExpr::ExprFuncNode *node)
Definition: ExprFuncX.cpp:100
double LLVM_VALUE
Definition: ExprLLVM.h:25
Node that calls a function.
Definition: ExprNode.h:654
abstract class for implementing variable references
Definition: Expression.h:36
static bool debugging
Whether to debug expressions.
Definition: Expression.h:77
static bool prepLLVM(ExprNode *, ExprType)
Definition: Evaluator.h:466
static const char * evalStr(VarBlock *)
Definition: Evaluator.h:456
static const double * evalFP(VarBlock *)
Definition: Evaluator.h:461
static void evalMultiple(VarBlock *, int, size_t, size_t)
Definition: Evaluator.h:471
static void unsupported()
Definition: Evaluator.h:452
A thread local evaluation context. Just allocate and fill in with data.
Definition: VarBlock.h:22
@ Unknown
Unknown error (message = %1)
Definition: ErrorCode.h:64