// Recursively generates LLVM code for the literal integer AST node. // // node - The node to generate an LLVM value for. // module - The compilation unit this node is a part of. // value - A pointer to where the LLVM value should be returned. // // Returns 0 if successful, otherwise returns -1. int qip_ast_int_literal_codegen(qip_ast_node *node, qip_module *module, LLVMValueRef *value) { LLVMContextRef context = LLVMGetModuleContext(module->llvm_module); *value = LLVMConstInt(LLVMInt64TypeInContext(context), node->int_literal.value, true); return 0; }
// Generates the allocas for the function arguments. This has to be called // from the block since that is where the entry block is created. // // node - The function node. // module - The compilation unit this node is a part of. // // Returns 0 if successful, otherwise returns -1. int qip_ast_function_codegen_args(qip_ast_node *node, qip_module *module) { int rc; unsigned int i; check(node != NULL, "Node required"); check(node->type == QIP_AST_TYPE_FUNCTION, "Node type expected to be 'function'"); check(module != NULL, "Module required"); LLVMBuilderRef builder = module->compiler->llvm_builder; LLVMContextRef context = LLVMGetModuleContext(module->llvm_module); // Retrieve current function scope. qip_scope *scope = NULL; rc = qip_module_get_current_function_scope(module, &scope); check(rc == 0 && scope != NULL, "Unable to retrieve current function scope"); // Codegen allocas. LLVMValueRef *values = malloc(sizeof(LLVMValueRef) * node->function.arg_count); check_mem(values); for(i=0; i<node->function.arg_count; i++) { rc = qip_ast_node_codegen(node->function.args[i], module, &values[i]); check(rc == 0, "Unable to determine function argument type"); } scope->llvm_last_alloca = LLVMBuildAlloca(builder, LLVMInt1TypeInContext(context), "nop"); // Codegen store instructions. for(i=0; i<node->function.arg_count; i++) { LLVMValueRef param = LLVMGetParam(scope->llvm_function, i); LLVMValueRef build_value = LLVMBuildStore(builder, param, values[i]); check(build_value != NULL, "Unable to create store instruction"); } free(values); return 0; error: if(values) free(values); return -1; }
void lp_add_function_attr(LLVMValueRef function_or_call, int attr_idx, enum lp_func_attr attr) { #if HAVE_LLVM < 0x0400 LLVMAttribute llvm_attr = lp_attr_to_llvm_attr(attr); if (LLVMIsAFunction(function_or_call)) { if (attr_idx == -1) { LLVMAddFunctionAttr(function_or_call, llvm_attr); } else { LLVMAddAttribute(LLVMGetParam(function_or_call, attr_idx - 1), llvm_attr); } } else { LLVMAddInstrAttribute(function_or_call, attr_idx, llvm_attr); } #else LLVMModuleRef module; if (LLVMIsAFunction(function_or_call)) { module = LLVMGetGlobalParent(function_or_call); } else { LLVMBasicBlockRef bb = LLVMGetInstructionParent(function_or_call); LLVMValueRef function = LLVMGetBasicBlockParent(bb); module = LLVMGetGlobalParent(function); } LLVMContextRef ctx = LLVMGetModuleContext(module); const char *attr_name = attr_to_str(attr); unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(ctx, kind_id, 0); if (LLVMIsAFunction(function_or_call)) LLVMAddAttributeAtIndex(function_or_call, attr_idx, llvm_attr); else LLVMAddCallSiteAttribute(function_or_call, attr_idx, llvm_attr); #endif }
/** * Compile an LLVM module to machine code. * * @returns 0 for success, 1 for failure */ unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_shader_binary *binary, const char *gpu_family, unsigned dump, LLVMTargetMachineRef tm) { char cpu[CPU_STRING_LEN]; char fs[FS_STRING_LEN]; char *err; bool dispose_tm = false; LLVMContextRef llvm_ctx; unsigned rval = 0; LLVMMemoryBufferRef out_buffer; unsigned buffer_size; const char *buffer_data; char triple[TRIPLE_STRING_LEN]; LLVMBool mem_err; if (!tm) { strncpy(triple, "r600--", TRIPLE_STRING_LEN); LLVMTargetRef target = radeon_llvm_get_r600_target(triple); if (!target) { return 1; } strncpy(cpu, gpu_family, CPU_STRING_LEN); memset(fs, 0, sizeof(fs)); if (dump) { strncpy(fs, "+DumpCode", FS_STRING_LEN); } tm = LLVMCreateTargetMachine(target, triple, cpu, fs, LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault); dispose_tm = true; } if (dump) { LLVMDumpModule(M); } /* Setup Diagnostic Handler*/ llvm_ctx = LLVMGetModuleContext(M); #if HAVE_LLVM >= 0x0305 LLVMContextSetDiagnosticHandler(llvm_ctx, radeonDiagnosticHandler, &rval); #endif rval = 0; /* Compile IR*/ mem_err = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err, &out_buffer); /* Process Errors/Warnings */ if (mem_err) { fprintf(stderr, "%s: %s", __FUNCTION__, err); FREE(err); LLVMDisposeTargetMachine(tm); return 1; } if (0 != rval) { fprintf(stderr, "%s: Processing Diag Flag\n", __FUNCTION__); } /* Extract Shader Code*/ buffer_size = LLVMGetBufferSize(out_buffer); buffer_data = LLVMGetBufferStart(out_buffer); radeon_elf_read(buffer_data, buffer_size, binary, dump); /* Clean up */ LLVMDisposeMemoryBuffer(out_buffer); if (dispose_tm) { LLVMDisposeTargetMachine(tm); } return rval; }
// Generates the function prototype but overrides the name. This is used by // the metadata to create external APIs to C. // // node - The node. // module - The compilation unit this node is a part of. // function_name - The name of the function to generate. // is_external - A flag stating if this is an external prototype. // value - A pointer to where the LLVM value should be returned to. // // Returns 0 if successful, otherwise returns -1. int qip_ast_function_codegen_prototype_with_name(qip_ast_node *node, qip_module *module, bstring function_name, bool is_external, LLVMValueRef *value) { int rc; unsigned int i; LLVMValueRef func = NULL; bstring arg_type_name = NULL; bstring return_type_name = NULL; LLVMContextRef context = LLVMGetModuleContext(module->llvm_module); // Determine the number of arguments. External calls always have an // additional first argument that is the module reference. unsigned int offset = (is_external ? 1 : 0); unsigned int total_arg_count = node->function.arg_count + offset; // Check for an existing prototype. func = LLVMGetNamedFunction(module->llvm_module, bdata(function_name)); // If a prototype exists then simply verify it matches and return it. if(func != NULL) { check(LLVMCountBasicBlocks(func) == 0, "Illegal function redefinition"); check(LLVMCountParams(func) == total_arg_count, "Function prototype already exists with different arguments"); } // If there is no prototype then create one. else { // Dynamically generate the return type of the function if it is missing. if(node->function.return_type == NULL) { rc = qip_ast_function_generate_return_type(node, module); check(rc == 0, "Unable to generate return type for function"); } // Create a list of function argument types. qip_ast_node *arg; LLVMTypeRef *params = malloc(sizeof(LLVMTypeRef) * total_arg_count); // Create module argument for external calls. if(is_external) { params[0] = LLVMPointerType(LLVMInt8TypeInContext(context), 0); } // Create arguments. for(i=0; i<node->function.arg_count; i++) { qip_ast_node *arg = node->function.args[i]; LLVMTypeRef param = NULL; rc = qip_module_get_type_ref(module, arg->farg.var_decl->var_decl.type, NULL, ¶m); check(rc == 0, "Unable to determine function argument type"); // Pass argument as reference if this is a complex type. if(qip_module_is_complex_type(module, param)) { params[i+offset] = LLVMPointerType(param, 0); } // Otherwise pass it by value. else { params[i+offset] = param; } } // Determine return type. LLVMTypeRef return_type; rc = qip_module_get_type_ref(module, node->function.return_type, NULL, &return_type); check(rc == 0, "Unable to determine function return type"); if(qip_module_is_complex_type(module, return_type)) { return_type = LLVMPointerType(return_type, 0); } // Create function type. LLVMTypeRef funcType = LLVMFunctionType(return_type, params, total_arg_count, false); check(funcType != NULL, "Unable to create function type"); // Create function. func = LLVMAddFunction(module->llvm_module, bdata(function_name), funcType); check(func != NULL, "Unable to create function"); // Assign module argument name. if(is_external) { LLVMSetValueName(LLVMGetParam(func, 0), "module"); } // Assign names to function arguments. for(i=0; i<node->function.arg_count; i++) { arg = node->function.args[i]; LLVMValueRef param = LLVMGetParam(func, i+offset); LLVMSetValueName(param, bdata(arg->farg.var_decl->var_decl.name)); } } // Return function prototype; *value = func; bdestroy(arg_type_name); bdestroy(return_type_name); return 0; error: bdestroy(arg_type_name); bdestroy(return_type_name); if(func) LLVMDeleteFunction(func); *value = NULL; return -1; }
/** * Compile an LLVM module to machine code. * * @returns 0 for success, 1 for failure */ unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_shader_binary *binary, const char *gpu_family, LLVMTargetMachineRef tm, struct pipe_debug_callback *debug) { struct radeon_llvm_diagnostics diag; char cpu[CPU_STRING_LEN]; char fs[FS_STRING_LEN]; char *err; bool dispose_tm = false; LLVMContextRef llvm_ctx; LLVMMemoryBufferRef out_buffer; unsigned buffer_size; const char *buffer_data; char triple[TRIPLE_STRING_LEN]; LLVMBool mem_err; diag.debug = debug; diag.retval = 0; if (!tm) { strncpy(triple, "r600--", TRIPLE_STRING_LEN); LLVMTargetRef target = radeon_llvm_get_r600_target(triple); if (!target) { return 1; } strncpy(cpu, gpu_family, CPU_STRING_LEN); memset(fs, 0, sizeof(fs)); strncpy(fs, "+DumpCode", FS_STRING_LEN); tm = LLVMCreateTargetMachine(target, triple, cpu, fs, LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault); dispose_tm = true; } /* Setup Diagnostic Handler*/ llvm_ctx = LLVMGetModuleContext(M); LLVMContextSetDiagnosticHandler(llvm_ctx, radeonDiagnosticHandler, &diag); /* Compile IR*/ mem_err = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err, &out_buffer); /* Process Errors/Warnings */ if (mem_err) { fprintf(stderr, "%s: %s", __FUNCTION__, err); pipe_debug_message(debug, SHADER_INFO, "LLVM emit error: %s", err); FREE(err); diag.retval = 1; goto out; } /* Extract Shader Code*/ buffer_size = LLVMGetBufferSize(out_buffer); buffer_data = LLVMGetBufferStart(out_buffer); radeon_elf_read(buffer_data, buffer_size, binary); /* Clean up */ LLVMDisposeMemoryBuffer(out_buffer); out: if (dispose_tm) { LLVMDisposeTargetMachine(tm); } if (diag.retval != 0) pipe_debug_message(debug, SHADER_INFO, "LLVM compile failed"); return diag.retval; }