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); _______________________________________________ Bf-blender-cvs mailing list [email protected] https://lists.blender.org/mailman/listinfo/bf-blender-cvs
