[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