[Bf-blender-cvs] [50410d1] object_nodes: Completed basic expression tree code generation.

Lukas Tönne noreply at git.blender.org
Fri Apr 8 17:30:52 CEST 2016


Commit: 50410d1ce56eedcc71070a143dffbab00ae72d3f
Author: Lukas Tönne
Date:   Fri Apr 8 17:28:42 2016 +0200
Branches: object_nodes
https://developer.blender.org/rB50410d1ce56eedcc71070a143dffbab00ae72d3f

Completed basic expression tree code generation.

The code uses a pointer-based signature convention for node functions,
which helps to avoid issues with type coercion through clang.
In the future we could either find a more reliable way to produce llvm IR
for the nodes, or use node functions as external functions without inlining.

===================================================================

M	source/blender/blenvm/llvm/llvm_codegen.cc
M	source/blender/blenvm/modules/mod_value.cc
M	source/blender/blenvm/modules/mod_value.h

===================================================================

diff --git a/source/blender/blenvm/llvm/llvm_codegen.cc b/source/blender/blenvm/llvm/llvm_codegen.cc
index 91d62de..5ad1311 100644
--- a/source/blender/blenvm/llvm/llvm_codegen.cc
+++ b/source/blender/blenvm/llvm/llvm_codegen.cc
@@ -39,6 +39,20 @@
 #include "llvm_function.h"
 #include "llvm_headers.h"
 
+/* call signature convention in llvm modules:
+ * BYVALUE:   Pass struct types directly into (inlined) functions,
+ *            Return type is a struct with all outputs, or a single
+ *            value if node has just one output.
+ * BYPOINTER: Pass arguments as pointers/references.
+ *            First function args are output pointers, followed by
+ *            inputs const pointers.
+ *            This call style is necessary to avoid type coercion by
+ *            the clang compiler! See
+ *            http://stackoverflow.com/questions/22776391/why-does-clang-coerce-struct-parameters-to-ints
+ */
+//#define BVM_NODE_CALL_BYVALUE
+#define BVM_NODE_CALL_BYPOINTER
+
 /* TypeBuilder specializations for own structs */
 
 namespace llvm {
@@ -104,14 +118,14 @@ namespace blenvm {
  * rather than storing full TypeDesc in each socket!
  * These functions just provides per-socket type names in the meantime.
  */
-inline string dummy_type_name(const InputKey &input)
+inline string dummy_type_name(ConstInputKey input)
 {
 	size_t hash = std::hash<const NodeInstance *>()(input.node) ^ std::hash<const NodeInput *>()(input.socket);
 	std::stringstream ss;
 	ss << "InputType" << (unsigned short)hash;
 	return ss.str();
 }
-inline string dummy_type_name(const OutputKey &output)
+inline string dummy_type_name(ConstOutputKey output)
 {
 	size_t hash = std::hash<const NodeInstance *>()(output.node) ^ std::hash<const NodeOutput *>()(output.socket);
 	std::stringstream ss;
@@ -298,21 +312,47 @@ llvm::CallInst *LLVMCompiler::codegen_node_call(llvm::BasicBlock *block,
 	std::vector<Value *> args;
 	
 	Value *retval = NULL;
+#ifdef BVM_NODE_CALL_BYVALUE
 	if (evalfunc->hasStructRetAttr()) {
 		Argument *retarg = &(*evalfunc->getArgumentList().begin());
 		retval = builder.CreateAlloca(retarg->getType()->getPointerElementType());
 		
 		args.push_back(retval);
 	}
+#endif
+#ifdef BVM_NODE_CALL_BYPOINTER
+	for (int i = 0; i < node->num_outputs(); ++i) {
+		ConstOutputKey output = node->output(i);
+		Type *output_type = codegen_type(dummy_type_name(output), &output.socket->typedesc);
+		AllocaInst *outputmem = builder.CreateAlloca(output_type);
+		
+		Type *arg_type = evalfunc->getFunctionType()->getParamType(args.size());
+		Value *value = builder.CreatePointerBitCastOrAddrSpaceCast(outputmem, arg_type);
+		args.push_back(value);
+		
+		/* use as node output values */
+		bool ok = output_values.insert(OutputValuePair(output, outputmem)).second;
+		BLI_assert(ok && "Value for node output already defined!");
+	}
+#endif
 	
 	/* set input arguments */
 	for (int i = 0; i < node->num_inputs(); ++i) {
 		ConstInputKey input = node->input(i);
 		
 		switch (input.value_type()) {
-			case INPUT_CONSTANT:
-				args.push_back(codegen_constant(input.value()));
+			case INPUT_CONSTANT: {
+				/* create storage for the global value */
+				Constant *constval = codegen_constant(input.value());
+				AllocaInst *constmem = builder.CreateAlloca(constval->getType());
+				builder.CreateStore(constval, constmem);
+				
+				/* use the pointer as function argument */
+				Type *arg_type = evalfunc->getFunctionType()->getParamType(args.size());
+				Value *value = builder.CreatePointerBitCastOrAddrSpaceCast(constmem, arg_type);
+				args.push_back(value);
 				break;
+			}
 			case INPUT_EXPRESSION:
 				args.push_back(output_values.at(input.link()));
 				break;
@@ -327,16 +367,32 @@ llvm::CallInst *LLVMCompiler::codegen_node_call(llvm::BasicBlock *block,
 	if (!retval)
 		retval = call;
 	
-	for (int i = 0; i < node->num_outputs(); ++i) {
-		ConstOutputKey output = node->output(i);
-		Value *value = builder.CreateStructGEP(retval, i);
-		if (!value) {
-			printf("Error: no output value defined for '%s':'%s'\n", node->name.c_str(), output.socket->name.c_str());
+	if (node->num_outputs() == 0) {
+		/* nothing to return */
+	}
+	else {
+#ifdef BVM_NODE_CALL_BYVALUE
+		if (evalfunc->hasStructRetAttr()) {
+			for (int i = 0; i < node->num_outputs(); ++i) {
+				ConstOutputKey output = node->output(i);
+				Value *value = builder.CreateStructGEP(retval, i);
+				if (!value) {
+					printf("Error: no output value defined for '%s':'%s'\n", node->name.c_str(), output.socket->name.c_str());
+				}
+				
+				/* use as node output values */
+				bool ok = output_values.insert(OutputValuePair(output, value)).second;
+				BLI_assert(ok && "Value for node output already defined!");
+			}
 		}
-		
-		/* use as node output values */
-		bool ok = output_values.insert(OutputValuePair(output, value)).second;
-		BLI_assert(ok && "Value for node output already defined!");
+		else {
+			BLI_assert(node->num_outputs() == 1);
+			ConstOutputKey output = node->output(0);
+			/* use as node output values */
+			bool ok = output_values.insert(OutputValuePair(output, retval)).second;
+			BLI_assert(ok && "Value for node output already defined!");
+		}
+#endif
 	}
 	
 	return call;
@@ -375,10 +431,6 @@ llvm::BasicBlock *LLVMCompiler::codegen_function_body_expression(const NodeGraph
 	for (NodeGraph::NodeInstanceMap::const_iterator it = graph.nodes.begin(); it != graph.nodes.end(); ++it)
 		nodes.insert(it->second);
 	
-	printf("DOING THE NODES: ---\n");
-	module()->dump();
-	printf("--------------------\n");
-	
 	for (OrderedNodeSet::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
 		const NodeInstance &node = **it;
 		
@@ -392,9 +444,9 @@ llvm::BasicBlock *LLVMCompiler::codegen_function_body_expression(const NodeGraph
 		
 		Value *retptr = builder.CreateStructGEP(retarg, i);
 		
-//		Value *value = output_values.at(output.key);
-//		Value *retval = builder.CreateLoad(value);
-//		builder.CreateStore(retval, retptr);
+		Value *value = output_values.at(output.key);
+		Value *retval = builder.CreateLoad(value);
+		builder.CreateStore(retval, retptr);
 	}
 	
 	builder.CreateRetVoid();
@@ -407,7 +459,7 @@ llvm::Function *LLVMCompiler::codegen_node_function(const string &name, const No
 	using namespace llvm;
 	
 	FunctionType *functype = codegen_node_function_type(graph);
-	Function *func = llvm::cast<Function>(module()->getOrInsertFunction(name, functype));
+	Function *func = Function::Create(functype, Function::ExternalLinkage, name, module());
 	Argument *retarg = func->getArgumentList().begin();
 	retarg->addAttr(AttributeSet::get(context(), AttributeSet::ReturnIndex, Attribute::StructRet));
 	
@@ -426,15 +478,20 @@ FunctionLLVM *LLVMCompiler::compile_function(const string &name, const NodeGraph
 	using namespace llvm;
 	
 	m_module = new Module(name, context());
-	llvm_execution_engine()->addModule(m_module);
 	llvm_link_module_full(m_module);
 	
 	Function *func = codegen_node_function(name, graph);
-	assert(func != NULL && "codegen_node_function returned NULL!");
+	BLI_assert(m_module->getFunction(name) && "Function not registered in module!");
+	BLI_assert(func != NULL && "codegen_node_function returned NULL!");
 	
 	printf("=== NODE FUNCTION ===\n");
+	fflush(stdout);
 	func->dump();
 	printf("=====================\n");
+	fflush(stdout);
+	
+	verifyFunction(*func, &outs());
+	verifyModule(*m_module, &outs());
 	
 	FunctionPassManager fpm(m_module);
 	PassManagerBuilder builder;
@@ -444,13 +501,14 @@ FunctionLLVM *LLVMCompiler::compile_function(const string &name, const NodeGraph
 	
 	fpm.run(*func);
 	
-	llvm_execution_engine()->finalizeObject();
-	
+	/* Note: Adding module to exec engine before creating the function prevents compilation! */
+	llvm_execution_engine()->addModule(m_module);
 	uint64_t address = llvm_execution_engine()->getFunctionAddress(name);
 	BLI_assert(address != 0);
 	
 	llvm_execution_engine()->removeModule(m_module);
 	delete m_module;
+	m_module = NULL;
 	
 	FunctionLLVM *fn = new FunctionLLVM(address);
 	return fn;
diff --git a/source/blender/blenvm/modules/mod_value.cc b/source/blender/blenvm/modules/mod_value.cc
index 11c43e8..40bb82a 100644
--- a/source/blender/blenvm/modules/mod_value.cc
+++ b/source/blender/blenvm/modules/mod_value.cc
@@ -28,9 +28,9 @@
 #include "mod_math.h"
 #include "mod_value.h"
 
-void VALUE_FLOAT(float *result, const float *value)
+void VALUE_FLOAT(float &result, const float &value)
 {
-	*result = *value;
+	result = value;
 }
 
 void VALUE_FLOAT3(float3 &result, const float3 &value)
diff --git a/source/blender/blenvm/modules/mod_value.h b/source/blender/blenvm/modules/mod_value.h
index a0eff6d..0ae585d 100644
--- a/source/blender/blenvm/modules/mod_value.h
+++ b/source/blender/blenvm/modules/mod_value.h
@@ -28,7 +28,7 @@
 #ifndef __MOD_VALUE_H__
 #define __MOD_VALUE_H__
 
-__attribute__((annotate("VALUE_FLOAT"))) void VALUE_FLOAT(float *result, const float *value);
+__attribute__((annotate("VALUE_FLOAT"))) void VALUE_FLOAT(float &result, const float &value);
 __attribute__((annotate("VALUE_FLOAT3"))) void VALUE_FLOAT3(float3 &result, const float3 &value);
 __attribute__((annotate("VALUE_FLOAT4"))) void VALUE_FLOAT4(float4 &result, const float4 &value);
 __attribute__((annotate("VALUE_INT"))) void VALUE_INT(int &result, const int &value);




More information about the Bf-blender-cvs mailing list