[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [analitza/aucahuasi/analitzajit] /: First approach to implement JIT compilation of vector-valued lam
From: Percy_Camilo_Triveño_Aucahuasi <percy.camilo.ta () gmail ! com>
Date: 2014-08-02 16:50:14
Message-ID: E1XDcVa-0000Pz-OO () scm ! kde ! org
[Download RAW message or body]
Git commit e32f9e2df99c3cdf2893d12c171bfd5717f776fd by Percy Camilo Triveño \
Aucahuasi. Committed on 02/08/2014 at 16:47.
Pushed by aucahuasi into branch 'aucahuasi/analitzajit'.
First approach to implement JIT compilation of vector-valued lambdas.
M +3 -1 analitzajit/CMakeLists.txt
M +43 -9 analitzajit/expressioncompiler.cpp
M +6 -1 analitzajit/expressioncompiler.h
M +58 -3 analitzajit/jitanalyzer.cpp
M +10 -2 analitzajit/jitanalyzer.h
M +29 -27 analitzajit/operationscompiler.cpp
M +50 -7 analitzajit/tests/analitzajittest.cpp
M +3 -0 analitzajit/tests/analitzajittest.h
M +25 -17 analitzajit/typecompiler.cpp
M +18 -4 analitzajit/typecompiler.h
M +8 -2 cmake/FindLLVM.cmake
http://commits.kde.org/analitza/e32f9e2df99c3cdf2893d12c171bfd5717f776fd
diff --git a/analitzajit/CMakeLists.txt b/analitzajit/CMakeLists.txt
index ab79712..469fb37 100644
--- a/analitzajit/CMakeLists.txt
+++ b/analitzajit/CMakeLists.txt
@@ -20,7 +20,9 @@ target_link_libraries ( AnalitzaJIT
Qt5::Gui
Analitza
- ${LLVM_MODULE_LIBS} ${LLVM_LFLAGS}
+ ${LLVM_SYSTEM_LIBS}
+ ${LLVM_MODULE_LIBS}
+ ${LLVM_LFLAGS}
)
set_target_properties(AnalitzaJIT PROPERTIES VERSION ${ANALITZA_VERSION_STRING} \
SOVERSION ${ANALITZA_SOVERSION} )
diff --git a/analitzajit/expressioncompiler.cpp b/analitzajit/expressioncompiler.cpp
index 0837594..2e4506d 100644
--- a/analitzajit/expressioncompiler.cpp
+++ b/analitzajit/expressioncompiler.cpp
@@ -18,7 +18,7 @@
#include "expressioncompiler.h"
-#include <llvm/Analysis/Verifier.h>
+#include <llvm/IR/Verifier.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/IRBuilder.h>
@@ -63,16 +63,20 @@ llvm::Value *ExpressionCompiler::compileExpression(const \
Analitza::Expression& e ExpressionTypeChecker check(m_vars);
check.initializeVars(bvartypes);
- ExpressionType rett = check.check(expression.lambdaBody());
- //TODO check if rett (return type) has error ret.Errors
+ m_retexptype = check.check(expression.lambdaBody());
+ //TODO check if m_retexptype (return type) has error ret.Errors
// qDebug() << "FUNT RET TYPE "<< rett.toString();
- m_rettype = TypeCompiler::compileType(rett);
+
+ //NOTE this is important: we need to return containers as pointer to contained
+ // type, so we set to true the param TypeCompiler::compileType::containerAsPointer
+ // this is because C++ functions doesn't return a vector, matrix, etc but
+ // it returns pointers to contained type instead
+ m_rettype = TypeCompiler::compileType(m_retexptype, true);
}
return expression.tree()->accept(this).value<llvm::Value*>();
}
-
QVariant ExpressionCompiler::visit(const Analitza::Ci* var)
{
//TODO generate values for intrinsic analitza constants like e, pi, etc
@@ -89,8 +93,29 @@ QVariant ExpressionCompiler::visit(const Analitza::Operator* op)
QVariant ExpressionCompiler::visit(const Analitza::Vector* vec)
{
- //TODO
- return QVariant();
+ const size_t n = (size_t)vec->size();
+ //TODO support othert ypes, not only doubles
+ Q_ASSERT(vec->at(0)->type() != Object::value); //remove this line when the support \
to other types (not only doubles) is done + llvm::Type *scalar_t = \
llvm::Type::getDoubleTy(llvm::getGlobalContext()); + llvm::ArrayType *array_t = \
llvm::ArrayType::get (scalar_t, n); +
+ //NOTE always we get first an undef instance, this is necessary in order to \
populate the array with non constant values using CreateInsertValue + llvm::Value \
*array = llvm::UndefValue::get (array_t); +
+ //fill the array ith elements
+ for (size_t idx = 0; idx < n; ++idx)
+ {
+ llvm::Value *elemval = vec->at(idx)->accept(this).value<llvm::Value*>();
+ array = buildr.CreateInsertValue (array, elemval, idx);
+ }
+
+ //NOTE this would be the equivalent of "new array(N)" ...
+ llvm::Value *array_mem = buildr.CreateAlloca (array_t);
+ buildr.CreateStore (array, array_mem);
+
+ //NOTE we need a typecast to pointer of scalar type this since C++ does not
+ // return arrays directally, it returns pointers to the scalar type
+ return QVariant::fromValue<llvm::Value*>(buildr.CreateBitCast (array_mem, \
scalar_t->getPointerTo ())); }
QVariant ExpressionCompiler::visit(const Analitza::Matrix* m)
@@ -206,6 +231,8 @@ QVariant ExpressionCompiler::visit(const Analitza::Container* c)
}
}
+ //TODO we need to find out a way to create a value based not only on
+ // 'double' but based on list, matrx, etc
llvm::Value *elseif = llvm::ConstantFP::get(llvm::getGlobalContext(), \
llvm::APFloat(0.0));
//NOTE this is key: we start with a false and we will apply OR operator over all
@@ -293,7 +320,11 @@ QVariant ExpressionCompiler::visit(const Analitza::Container* c)
}
//END otherwise
- ret = elseif;
+// if (((llvm::ConstantFP*)elseif)->isNaN()) {
+// //TODO error: Could not find a proper choice for a condition statement.
+// } else {
+ ret = elseif;
+// }
// TheFunction->dump();
@@ -346,7 +377,10 @@ QVariant ExpressionCompiler::visit(const Analitza::Container* c)
// QVariant al = QVariant::fromValue<llvm::Value*>(F);
// BB->dump();
- llvm::verifyFunction(*F);
+ if (!llvm::verifyFunction(*F))
+ {
+// qDebug() << "TODO OK";
+ }
ret = F;
} break;
diff --git a/analitzajit/expressioncompiler.h b/analitzajit/expressioncompiler.h
index 5b3847c..417f0bc 100644
--- a/analitzajit/expressioncompiler.h
+++ b/analitzajit/expressioncompiler.h
@@ -59,6 +59,8 @@ class ExpressionCompiler : public \
Analitza::AbstractExpressionVisitor /** Convenience method that applies \
compileExpression over the @p expression object. */ llvm::Value \
*compileExpression(Analitza::Object *expression, const QMap< QString, \
Analitza::ExpressionType >& bvartypes = QMap< QString, Analitza::ExpressionType >()); \
+ QPair<llvm::Type *, Analitza::ExpressionType> compiledType() const { return \
qMakePair(m_rettype, m_retexptype); } +
llvm::Module *module() const { return m_module; }
Analitza::Variables *variables() const { return m_vars; }
@@ -81,7 +83,10 @@ class ExpressionCompiler : public \
Analitza::AbstractExpressionVisitor //TODO manage error messages that comes from \
llvm QMap<QString, llvm::Type*> m_bvartypes;
llvm::Module *m_module;
- llvm::Type* m_rettype;
+ llvm::Type* m_rettype; //used after the user call compileExpression
+ Analitza::ExpressionType m_retexptype; //used after the user call \
compileExpression +
+
};
}
diff --git a/analitzajit/jitanalyzer.cpp b/analitzajit/jitanalyzer.cpp
index d6c5f2b..81b6c88 100644
--- a/analitzajit/jitanalyzer.cpp
+++ b/analitzajit/jitanalyzer.cpp
@@ -25,6 +25,7 @@
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
+#include <llvm-3.5/llvm/IR/InstrTypes.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/ExecutionEngine/JIT.h>
@@ -39,6 +40,8 @@ JITAnalyzer::JITAnalyzer()
m_module = new llvm::Module("mumod", llvm::getGlobalContext());
m_jitengine = llvm::EngineBuilder(m_module).create();
+// std::string ErrStr;
+// m_jitengine = llvm::EngineBuilder(m_module).setErrorStr(&ErrStr).setMCPU("amd64").create();
}
JITAnalyzer::~JITAnalyzer()
@@ -77,7 +80,15 @@ bool JITAnalyzer::setExpression(const Expression& \
lambdaExpression, const QMap< ExpressionCompiler v(m_module, variables());
//cache
- m_jitfnscache[m_currentfnkey] = v.compileExpression(expression(), bvartypes);
+ function_info fn;
+ //TODO support expression too, not only lambda expression
+ fn.ir_function = llvm::cast<llvm::Function>(v.compileExpression(expression(), \
bvartypes)); + fn.ir_retty = v.compiledType().first;
+ fn.native_retty = v.compiledType().second;
+
+ m_jitfnscache[m_currentfnkey] = fn;
+
+// m_jitfnscache[m_currentfnkey]->dump();
return true;
}
@@ -117,7 +128,7 @@ bool JITAnalyzer::calculateLambda(double &result)
// Look up the name in the global module table.
- llvm::Function *CalleeF = (llvm::Function*)m_jitfnscache[m_currentfnkey];
+ llvm::Function *CalleeF = m_jitfnscache[m_currentfnkey].ir_function;
// llvm::CallInst *retcall = Builder.CreateCall(CalleeF, ArgsV, "tmpvarfromcall");
std::vector<llvm::GenericValue> abc;
@@ -161,7 +172,7 @@ bool JITAnalyzer::calculateLambda(bool &result)
// Look up the name in the global module table.
- llvm::Function *CalleeF = (llvm::Function*)m_jitfnscache[m_currentfnkey];
+ llvm::Function *CalleeF = m_jitfnscache[m_currentfnkey].ir_function;
// llvm::CallInst *retcall = Builder.CreateCall(CalleeF, ArgsV, "tmpvarfromcall");
std::vector<llvm::GenericValue> abc;
@@ -193,3 +204,47 @@ bool JITAnalyzer::calculateLambda(bool &result)
return true;
}
+
+bool JITAnalyzer::calculateLambda(QVarLengthArray< double >& result)
+{
+ Q_ASSERT(!m_jitfnscache.isEmpty());
+
+ if (m_jitfnscache.contains(m_currentfnkey)) {
+ //TODO check for non empty m_jitfnscache
+
+ // Look up the name in the global module table.
+ llvm::Function *CalleeF = m_jitfnscache[m_currentfnkey].ir_function;
+
+ std::vector<llvm::GenericValue> abc;
+
+ for (int i = 0; i < this->expression().bvarList().size(); ++i) {
+ llvm::GenericValue a;
+ a.DoubleVal = ((Cn*)(runStack().at(i)))->value();
+ abc.push_back(a);
+ }
+
+// CalleeF->dump();
+
+ void *FPtr = m_jitengine->getPointerToFunction(CalleeF);
+ typedef double* (*FTY)(double);
+ FTY FP = reinterpret_cast<FTY>((intptr_t)FPtr);
+ qDebug() << "YEEEEEEE " << FP(9)[4];// << FP(9)[0] << FP(9)[1];
+
+ switch (m_jitfnscache[m_currentfnkey].native_retty.type()) {
+ case ExpressionType::Vector: {
+ //TODO check size of result eq to size of genvalue
+// for (int i = 0; i < m_jitfnscache[m_currentfnkey].native_retty.size(); ++i) {
+// // result[i] = *(reinterpret_cast<double>(rr.PointerVal));
+// qDebug() << "CURRENT ELEMENT : " << result[i];
+// }
+ return true;
+ } break;
+ default: return false;
+ }
+ } else {
+ //TODO add error
+ return false;
+ }
+
+ return true;
+}
diff --git a/analitzajit/jitanalyzer.h b/analitzajit/jitanalyzer.h
index 1806ac9..12338a9 100644
--- a/analitzajit/jitanalyzer.h
+++ b/analitzajit/jitanalyzer.h
@@ -26,6 +26,8 @@ namespace llvm {
class Value;
class Module;
class ExecutionEngine;
+ class Type;
+ class Function;
};
namespace Analitza
@@ -91,11 +93,11 @@ class ANALITZAJIT_EXPORT JITAnalyzer : public Analitza::Analyzer
*/
bool calculateLambda(double &result);
bool calculateLambda(bool &result);
+ bool calculateLambda(QVarLengthArray<double> &result);
//TODO
//bool calculateLambda(int &result);
//bool calculateLambda(complex &result);
- //bool calculateLambda(vector &result);
//bool calculateLambda(matrix &result);
//bool calculateLambda(list &result);
@@ -106,7 +108,13 @@ class ANALITZAJIT_EXPORT JITAnalyzer : public Analitza::Analyzer
llvm::ExecutionEngine *m_jitengine;
//TODO better cache structure
- QMap<QString, llvm::Value*> m_jitfnscache;
+ struct function_info {
+ llvm::Function *ir_function;
+ void *jit_function;
+ llvm::Type *ir_retty;
+ Analitza::ExpressionType native_retty;
+ };
+ QMap<QString, function_info> m_jitfnscache;
QString m_currentfnkey;
};
diff --git a/analitzajit/operationscompiler.cpp b/analitzajit/operationscompiler.cpp
index c4c3db6..e287904 100644
--- a/analitzajit/operationscompiler.cpp
+++ b/analitzajit/operationscompiler.cpp
@@ -33,7 +33,8 @@
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/IRBuilder.h>
-static llvm::IRBuilder<> buildr(llvm::getGlobalContext());
+static llvm::LLVMContext &llvmcontext = llvm::getGlobalContext();
+static llvm::IRBuilder<> irbuilder(llvmcontext);
using namespace std;
using namespace Analitza;
@@ -43,13 +44,14 @@ llvm::Value * compileRealReal(llvm::BasicBlock* currentBlock, \
Operator::Operator llvm::Value *ret = 0;
switch(op) {
- case Operator::plus: ret = buildr.CreateFAdd(val1, val2); break;
- case Operator::minus: ret = buildr.CreateFSub(val1, val2); break;
- case Operator::times: ret = buildr.CreateFMul(val1, val2); break;
- case Operator::divide: ret = buildr.CreateFDiv(val1, val2); break;//TODO handle \
x/0 send some error + case Operator::plus: ret = irbuilder.CreateFAdd(val1, val2); \
break; + case Operator::minus: ret = irbuilder.CreateFSub(val1, val2); break;
+// case Operator::times: ret = llvm::ConstantExpr::getFMul((llvm::Constant*)val1, \
(llvm::Constant*)val2); break; + case Operator::times: ret = \
irbuilder.CreateFMul(val1, val2); break; + case Operator::divide: ret = \
irbuilder.CreateFDiv(val1, val2); break;//TODO handle x/0 send some error case \
Operator::power: {
- llvm::Function *powfnptr = \
llvm::Intrinsic::getDeclaration(currentBlock->getParent()->getParent(), \
llvm::Intrinsic::pow, \
llvm::Type::getDoubleTy(llvm::getGlobalContext()));
- ret = buildr.CreateCall2(powfnptr, val1, val2);
+ llvm::Function *powfnptr = \
llvm::Intrinsic::getDeclaration(currentBlock->getParent()->getParent(), \
llvm::Intrinsic::pow, llvm::Type::getDoubleTy(llvmcontext)); + ret = \
irbuilder.CreateCall2(powfnptr, val1, val2); } break;
// case Operator::rem:
// if(Q_LIKELY(floor(b)!=0.))
@@ -74,9 +76,9 @@ llvm::Value * compileRealReal(llvm::BasicBlock* currentBlock, \
Operator::Operator case Operator::min: {
//NOTE the idea here is to avoid use 'if', so we have this: (val1<val2)*val1 + \
(val1>=val2)*val2 llvm::Value *lessthan = compileRealReal(currentBlock, \
Operator::lt, val1, val2, error);
- llvm::Value *neglessthan = buildr.CreateNot(lessthan);
- llvm::Value *flessthan = buildr.CreateUIToFP(lessthan, \
llvm::Type::getDoubleTy(llvm::getGlobalContext()));
- llvm::Value *fneglessthan = buildr.CreateUIToFP(neglessthan, \
llvm::Type::getDoubleTy(llvm::getGlobalContext())); + llvm::Value *neglessthan = \
irbuilder.CreateNot(lessthan); + llvm::Value *flessthan = \
irbuilder.CreateUIToFP(lessthan, llvm::Type::getDoubleTy(llvmcontext)); \
+ llvm::Value *fneglessthan = irbuilder.CreateUIToFP(neglessthan, \
llvm::Type::getDoubleTy(llvmcontext)); llvm::Value *a = \
compileRealReal(currentBlock, Operator::times, flessthan, val1, error); llvm::Value \
*b = compileRealReal(currentBlock, Operator::times, fneglessthan, val2, error); ret \
= compileRealReal(currentBlock, Operator::plus, a, b, error); @@ -84,9 +86,9 @@ \
llvm::Value * compileRealReal(llvm::BasicBlock* currentBlock, Operator::Operator \
case Operator::max: { //NOTE the idea here is to avoid use 'if', so we have this: \
(val1>val2)*val1 + (val1<=val2)*val2 llvm::Value *grethan = \
compileRealReal(currentBlock, Operator::gt, val1, val2, error);
- llvm::Value *neggrethan = buildr.CreateNot(grethan);
- llvm::Value *fgrethan = buildr.CreateUIToFP(grethan, \
llvm::Type::getDoubleTy(llvm::getGlobalContext()));
- llvm::Value *fneggrethan = buildr.CreateUIToFP(neggrethan, \
llvm::Type::getDoubleTy(llvm::getGlobalContext())); + llvm::Value *neggrethan = \
irbuilder.CreateNot(grethan); + llvm::Value *fgrethan = \
irbuilder.CreateUIToFP(grethan, llvm::Type::getDoubleTy(llvmcontext)); \
+ llvm::Value *fneggrethan = irbuilder.CreateUIToFP(neggrethan, \
llvm::Type::getDoubleTy(llvmcontext)); llvm::Value *a = \
compileRealReal(currentBlock, Operator::times, fgrethan, val1, error); llvm::Value \
*b = compileRealReal(currentBlock, Operator::times, fneggrethan, val2, error); ret = \
compileRealReal(currentBlock, Operator::plus, a, b, error); @@ -94,12 +96,12 @@ \
llvm::Value * compileRealReal(llvm::BasicBlock* currentBlock, Operator::Operator // \
case Operator::approx: // oper->setValue(fabs(a-b)<0.001);
// break;
- case Operator::gt: ret = buildr.CreateFCmp(llvm::CmpInst::FCMP_UGT, val1, val2); \
break;
- case Operator::lt: ret = buildr.CreateFCmp(llvm::CmpInst::FCMP_ULT, val1, val2); \
break;
- case Operator::eq: ret = buildr.CreateFCmp(llvm::CmpInst::FCMP_UEQ, val1, val2); \
break;
- case Operator::neq: ret = buildr.CreateFCmp(llvm::CmpInst::FCMP_UNE, val1, val2); \
break;
- case Operator::geq: ret = buildr.CreateFCmp(llvm::CmpInst::FCMP_UGE, val1, val2); \
break;
- case Operator::leq: ret = buildr.CreateFCmp(llvm::CmpInst::FCMP_ULE, val1, val2); \
break; + case Operator::gt: ret = irbuilder.CreateFCmp(llvm::CmpInst::FCMP_UGT, \
val1, val2); break; + case Operator::lt: ret = \
irbuilder.CreateFCmp(llvm::CmpInst::FCMP_ULT, val1, val2); break; + case \
Operator::eq: ret = irbuilder.CreateFCmp(llvm::CmpInst::FCMP_UEQ, val1, val2); break; \
+ case Operator::neq: ret = irbuilder.CreateFCmp(llvm::CmpInst::FCMP_UNE, val1, \
val2); break; + case Operator::geq: ret = \
irbuilder.CreateFCmp(llvm::CmpInst::FCMP_UGE, val1, val2); break; + case \
Operator::leq: ret = irbuilder.CreateFCmp(llvm::CmpInst::FCMP_ULE, val1, val2); \
break; // case Operator::_and:
// oper->setValue(a && b);
// break;
@@ -141,7 +143,7 @@ llvm::Value * compileRealReal(llvm::BasicBlock* currentBlock, \
Operator::Operator // }
// break;
case Operator::root: {
- llvm::Value *invval2 = compileRealReal(currentBlock, Operator::divide, \
llvm::ConstantFP::get(llvm::getGlobalContext(), llvm::APFloat(1.0)), val2, error); \
+ llvm::Value *invval2 = compileRealReal(currentBlock, Operator::divide, \
llvm::ConstantFP::get(llvmcontext, llvm::APFloat(1.0)), val2, error); ret = \
compileRealReal(currentBlock, Operator::power, val1, invval2, error); } break;
default:
@@ -343,7 +345,7 @@ llvm::Value * compileUnaryReal(llvm::BasicBlock *currentBlock, \
Operator::Operato llvm::Value *ret = 0;
switch(op) {
- case Operator::minus: ret = buildr.CreateFNeg(val); break;
+ case Operator::minus: ret = irbuilder.CreateFNeg(val); break;
// case Operator::factorial: {
// //Use gamma from math.h?
// uint res=1;
@@ -353,12 +355,12 @@ llvm::Value * compileUnaryReal(llvm::BasicBlock *currentBlock, \
Operator::Operato // oper->setValue(res);
// } break;
case Operator::sin: {
- llvm::Function *sinfnptr = \
llvm::Intrinsic::getDeclaration(currentBlock->getParent()->getParent(), \
llvm::Intrinsic::sin, \
llvm::Type::getDoubleTy(llvm::getGlobalContext()));
- ret = buildr.CreateCall(sinfnptr, val);
+ llvm::Function *sinfnptr = \
llvm::Intrinsic::getDeclaration(currentBlock->getParent()->getParent(), \
llvm::Intrinsic::sin, llvm::Type::getDoubleTy(llvmcontext)); + ret = \
irbuilder.CreateCall(sinfnptr, val); } break;
case Operator::cos: {
- llvm::Function *cosfnptr = \
llvm::Intrinsic::getDeclaration(currentBlock->getParent()->getParent(), \
llvm::Intrinsic::cos, \
llvm::Type::getDoubleTy(llvm::getGlobalContext()));
- ret = buildr.CreateCall(cosfnptr, val);
+ llvm::Function *cosfnptr = \
llvm::Intrinsic::getDeclaration(currentBlock->getParent()->getParent(), \
llvm::Intrinsic::cos, llvm::Type::getDoubleTy(llvmcontext)); + ret = \
irbuilder.CreateCall(cosfnptr, val); } break;
case Operator::tan: {
llvm::Value *sinv = compileUnaryReal(currentBlock, Operator::sin, val, correct);
@@ -978,7 +980,7 @@ llvm::Value * \
OperationsCompiler::compileBinaryOperation(llvm::BasicBlock* curre BinaryOp \
f=opsBinary[finaltype1][finaltype2]; Q_ASSERT(f && "using compile (for binary \
operator) in a wrong way");
- buildr.SetInsertPoint(currentBlock);
+ irbuilder.SetInsertPoint(currentBlock);
return f(currentBlock ,op, val1, val2, error);
}
@@ -1013,7 +1015,7 @@ llvm::Value * \
OperationsCompiler::compileUnaryOperation(llvm::BasicBlock* curren UnaryOp \
f=opsUnary[finaltype]; Q_ASSERT(f && "using compileUnary in a wrong way");
- buildr.SetInsertPoint(currentBlock);
+ irbuilder.SetInsertPoint(currentBlock);
return f(currentBlock, op, val, error);
}
diff --git a/analitzajit/tests/analitzajittest.cpp \
b/analitzajit/tests/analitzajittest.cpp index 0aa61db..a8a8b93 100644
--- a/analitzajit/tests/analitzajittest.cpp
+++ b/analitzajit/tests/analitzajittest.cpp
@@ -19,15 +19,29 @@
#include "analitzajittest.h"
#include <QtTest/QTest>
+#include <QVarLengthArray>
#include "analitza/value.h"
#include "analitzajit/jitanalyzer.h"
QTEST_MAIN( AnalitzaJitTest )
+Q_DECLARE_METATYPE(QVarLengthArray<double>);
+
static inline bool epscompare(double a, double b)
{
- return a==b || std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon();
+ return a==b || std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon();
+}
+
+static inline bool epscompare(QVarLengthArray<double> a, QVarLengthArray<double> b)
+{
+ bool ret = (a.size() == b.size());
+
+ for (int i = 0; (i < a.size()) && ret; ++i) {
+ ret = epscompare(a.at(i), b.at(i));
+ }
+
+ return ret;
}
AnalitzaJitTest::AnalitzaJitTest(QObject *parent)
@@ -82,8 +96,7 @@ void AnalitzaJitTest::testCalculateUnaryBooleanLambda()
bool result = 0;
- a->setExpression(Analitza::Expression(expression));
-
+ QVERIFY(a->setExpression(Analitza::Expression(expression)));
QVERIFY(a->calculateLambda(result));
QCOMPARE(result, expected);
}
@@ -137,8 +150,7 @@ void AnalitzaJitTest::testCalculateUnaryRealLambda()
double result = 0;
- a->setExpression(Analitza::Expression(expression));
-
+ QVERIFY(a->setExpression(Analitza::Expression(expression)));
QVERIFY(a->calculateLambda(result));
bool eq = epscompare(result, expected);
@@ -189,8 +201,7 @@ void AnalitzaJitTest::testCalculateBinaryRealLambda()
double result = 0;
- a->setExpression(Analitza::Expression(expression));
-
+ QVERIFY(a->setExpression(Analitza::Expression(expression)));
QVERIFY(a->calculateLambda(result));
bool eq = epscompare(result, expected);
@@ -202,4 +213,36 @@ void AnalitzaJitTest::testCalculateBinaryRealLambda()
QVERIFY(eq);
}
+void AnalitzaJitTest::testCalculateUnaryRealVectorLambda_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<double>("arg1value");
+ QTest::addColumn< QVarLengthArray<double> >("expected");
+
+ QTest::newRow("simple param") << "t->vector{t*t, 7*t}" << 5.0 << \
(QVarLengthArray<double>() << 25.0 << 35.0); +}
+
+void AnalitzaJitTest::testCalculateUnaryRealVectorLambda()
+{
+ QFETCH(QString, expression);
+ QFETCH(double, arg1value);
+ QFETCH( QVarLengthArray<double> , expected );
+
+ arg1->setValue(arg1value);
+
+ QVarLengthArray<double> result;
+
+ QVERIFY(a->setExpression(Analitza::Expression(expression)));
+
+ QVERIFY(a->calculateLambda(result));
+
+ bool eq = epscompare(result, expected);
+
+ if (!eq) {
+// qDebug() << "Actual: " << result;
+// qDebug() << "Expected: " << expected;
+ }
+ QVERIFY(eq);
+}
+
#include "analitzajittest.moc"
diff --git a/analitzajit/tests/analitzajittest.h \
b/analitzajit/tests/analitzajittest.h index 4cdb3e7..1a61782 100644
--- a/analitzajit/tests/analitzajittest.h
+++ b/analitzajit/tests/analitzajittest.h
@@ -48,6 +48,9 @@ Q_OBJECT
void testCalculateBinaryRealLambda_data();
void testCalculateBinaryRealLambda();
+ void testCalculateUnaryRealVectorLambda_data();
+ void testCalculateUnaryRealVectorLambda();
+
void cleanupTestCase();
private:
Analitza::JITAnalyzer *a;
diff --git a/analitzajit/typecompiler.cpp b/analitzajit/typecompiler.cpp
index 165c174..78973a5 100644
--- a/analitzajit/typecompiler.cpp
+++ b/analitzajit/typecompiler.cpp
@@ -23,26 +23,34 @@
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/DerivedTypes.h>
+static llvm::LLVMContext &llvmcontext = llvm::getGlobalContext();
+
using namespace Analitza;
-llvm::Type* TypeCompiler::compileType(const Analitza::ExpressionType& \
expressionType) +llvm::Type* TypeCompiler::compileType(const \
Analitza::ExpressionType& expressionType, bool containerAsPointer) {
llvm::Type *ret = 0;
switch(expressionType.type()) {
- case Analitza::ExpressionType::Value: {
- //TODO get ineger bit width from host then decide if 32 or 64 bits
- //TODO handle llvm::Type::getInt32Ty(llvm::getGlobalContext())
- ret = llvm::Type::getDoubleTy(llvm::getGlobalContext());
- } break;
- case Analitza::ExpressionType::Bool: {
- ret = llvm::Type::getInt1Ty(llvm::getGlobalContext()); //we need just one bit for \
bool + //TODO Value: Analitza must implementa way to deal with integer and complex \
scalars (not only reals) + case Analitza::ExpressionType::Value: ret = \
llvm::Type::getDoubleTy(llvmcontext); break; + case Analitza::ExpressionType::Bool: \
ret = llvm::Type::getInt1Ty(llvmcontext); break; + case \
Analitza::ExpressionType::Char: ret = llvm::Type::getInt8Ty(llvmcontext); break; \
+ case Analitza::ExpressionType::Vector: { + if (expressionType.size() > 0) {
+ //NOTE LLVM::VectorType can have issues with being platform independent ...we'll \
use array until that + //ret = \
llvm::VectorType::get(compileType(expressionType.contained()), \
expressionType.size()); + //ret = \
llvm::ArrayType::get(compileType(expressionType.contained()), expressionType.size()); \
+ if (containerAsPointer) { + ret = \
llvm::Type::getDoubleTy(llvm::getGlobalContext())->getPointerTo(); + } else {
+ ret = llvm::ArrayType::get(compileType(expressionType.contained()), \
expressionType.size());; + }
+ } else {
+ //TODO error user needs to specify the size of the vector
+ }
} break;
- //TODO
-// case Analitza::ExpressionType::Char: {
-// ret = llvm::Type::getInt8Ty(llvm::getGlobalContext());
-// } break;
- //TODO case Vector, List, Lambda, Matrix
+ //TODO case List, Lambda, Matrix
}
Q_ASSERT(ret);
@@ -50,23 +58,23 @@ llvm::Type* TypeCompiler::compileType(const \
Analitza::ExpressionType& expression return ret;
}
-QVector< llvm::Type* > TypeCompiler::compileTypes(const QList< \
Analitza::ExpressionType >& expressionTypes) +QVector< llvm::Type* > \
TypeCompiler::compileTypes(const QList< Analitza::ExpressionType >& expressionTypes, \
bool containerAsPointer) {
const int n = expressionTypes.size();
QVector< llvm::Type* > ret(n);
for (int i = 0; i < n; ++i)
- ret.append(compileType(expressionTypes.at(i)));
+ ret.append(compileType(expressionTypes.at(i), containerAsPointer));
return ret;
}
-QMap<QString, llvm::Type*> TypeCompiler::compileTypes(const QMap<QString, \
Analitza::ExpressionType>& expressionTypes) +QMap<QString, llvm::Type*> \
TypeCompiler::compileTypes(const QMap<QString, Analitza::ExpressionType>& \
expressionTypes, bool containerAsPointer) {
QMap<QString, llvm::Type*> ret;
foreach (const QString &var, expressionTypes.keys()) {
- ret[var] = compileType(expressionTypes[var]);
+ ret[var] = compileType(expressionTypes[var], containerAsPointer);
}
return ret;
diff --git a/analitzajit/typecompiler.h b/analitzajit/typecompiler.h
index 109c96a..a8c86e8 100644
--- a/analitzajit/typecompiler.h
+++ b/analitzajit/typecompiler.h
@@ -54,17 +54,31 @@ namespace Analitza
class ANALITZAJIT_EXPORT TypeCompiler //TODO : public \
Analitza::AbstractExpressionTypeVisitor {
public:
- /** @returns Returns LLVM type for a valid or supported ExpressionType, otherwise \
will return a null pointer. */
- static llvm::Type *compileType(const Analitza::ExpressionType &expressionType);
+ /**
+ * If @p containerAsPointer is true and @p expressionType is a container, then
+ * compilation will generate pointers of the contained type instead of a strict
+ * container type. For example, for a vector of 5 real numbers (i.e.
+ * @p expressionType equals to ExpressionType(ExpressionType::Vector, \
ExpressionType(ExpressionType::Value), -2)) + * we have this two cases:
+ *
+ * If @p containerAsPointer equals to true then the compiled code is:
+ * \code double* \endcode
+ *
+ * If @p containerAsPointer equals to false then the compiled code is:
+ * \code [5 x double] \endcode
+ *
+ /* @returns Returns LLVM type for a valid or supported ExpressionType, otherwise \
will return a null pointer. + */
+ static llvm::Type *compileType(const Analitza::ExpressionType &expressionType, \
bool containerAsPointer = false);
/** Convenience method that applies TypeCompiler::compileType over each element of \
@p expressionTypes */
- static QVector<llvm::Type*> compileTypes(const QList<Analitza::ExpressionType>& \
expressionTypes); + static QVector<llvm::Type*> compileTypes(const \
QList<Analitza::ExpressionType>& expressionTypes, bool containerAsPointer = false);
/**
* Sometimes the user manages associations between variable names and its types, \
so this is a convenience method
* that applies TypeCompiler::compileType for each variable type contained inside \
of @p expressionTypes
*/
- static QMap<QString, llvm::Type*> compileTypes(const QMap<QString, \
Analitza::ExpressionType>& expressionTypes); + static QMap<QString, llvm::Type*> \
compileTypes(const QMap<QString, Analitza::ExpressionType>& expressionTypes, bool \
containerAsPointer = false); };
}
diff --git a/cmake/FindLLVM.cmake b/cmake/FindLLVM.cmake
index 006f9f1..7404c78 100644
--- a/cmake/FindLLVM.cmake
+++ b/cmake/FindLLVM.cmake
@@ -94,9 +94,15 @@ if (LLVM_FOUND)
OUTPUT_VARIABLE LLVM_LFLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
-
+
+ execute_process(
+ COMMAND ${LLVM_CONFIG_EXECUTABLE} --system-libs
+ OUTPUT_VARIABLE LLVM_SYSTEM_LIBS
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
execute_process(
- COMMAND ${LLVM_CONFIG_EXECUTABLE} --libs core bitreader asmparser analysis jit \
target all-targets + COMMAND ${LLVM_CONFIG_EXECUTABLE} --libs
OUTPUT_VARIABLE LLVM_MODULE_LIBS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic