static LLVMValueRef get_prototype(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs, ast_t* fun) { // Behaviours and actor constructors also have sender functions. bool sender = false; switch(ast_id(fun)) { case TK_NEW: sender = g->underlying == TK_ACTOR; break; case TK_BE: sender = true; break; default: {} } // Get a fully qualified name: starts with the type name, followed by the // type arguments, followed by the function name, followed by the function // level type arguments. const char* funname = genname_fun(g->type_name, name, typeargs); // If the function already exists, just return it. LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); if(func != NULL) return func; LLVMTypeRef ftype = get_signature(c, g, fun); if(ftype == NULL) return NULL; // If the function exists now, just return it. func = LLVMGetNamedFunction(c->module, funname); if(func != NULL) return func; if(sender) { // Generate the sender prototype. const char* be_name = genname_be(funname); func = codegen_addfun(c, be_name, ftype); // Change the return type to void for the handler. size_t count = LLVMCountParamTypes(ftype); size_t buf_size = count *sizeof(LLVMTypeRef); LLVMTypeRef* tparams = (LLVMTypeRef*)pool_alloc_size(buf_size); LLVMGetParamTypes(ftype, tparams); ftype = LLVMFunctionType(c->void_type, tparams, (int)count, false); pool_free_size(buf_size, tparams); } // Generate the function prototype. return codegen_addfun(c, funname, ftype); }
int test_kal_codegen_function() { kal_named_value *val; unsigned int arg_count = 1; char **args = malloc(sizeof(char*) * arg_count); args[0] = "foo"; LLVMModuleRef module = LLVMModuleCreateWithName("kal"); LLVMBuilderRef builder = LLVMCreateBuilder(); kal_ast_node *prototype = kal_ast_prototype_create("my_func", args, arg_count); kal_ast_node *lhs = kal_ast_variable_create("foo"); kal_ast_node *rhs = kal_ast_number_create(20); kal_ast_node *body = kal_ast_binary_expr_create(KAL_BINOP_PLUS, lhs, rhs); kal_ast_node *node = kal_ast_function_create(prototype, body); kal_codegen_reset(); LLVMValueRef value = kal_codegen(node, module, builder); mu_assert(value != NULL, ""); mu_assert(LLVMGetNamedFunction(module, "my_func") == value, ""); mu_assert(LLVMCountParams(value) == 1, ""); val = kal_codegen_named_value("foo"); mu_assert(val->value == LLVMGetParam(value, 0), ""); mu_assert(LLVMGetTypeKind(LLVMTypeOf(LLVMGetParam(value, 0))) == LLVMDoubleTypeKind, ""); LLVMDisposeBuilder(builder); LLVMDisposeModule(module); kal_ast_node_free(node); return 0; }
static LLVMValueRef get_sender(compile_t* c, gentype_t* g, const char* name, ast_t* typeargs) { const char* fun_name = genname_fun(g->type_name, name, typeargs); const char* be_name = genname_be(fun_name); return LLVMGetNamedFunction(c->module, be_name); }
LLVMValueRef genfun_proto(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs) { ast_t* fun = get_fun(g, name, typeargs); LLVMValueRef func = get_prototype(c, g, name, typeargs, fun); // Disable debugloc on calls to methods that have no debug info. if(!ast_debug(fun)) dwarf_location(&c->dwarf, NULL); switch(ast_id(fun)) { case TK_NEW: case TK_BE: if(g->underlying == TK_ACTOR) { const char* fun_name = genname_fun(g->type_name, name, typeargs); const char* be_name = genname_be(fun_name); func = LLVMGetNamedFunction(c->module, be_name); } break; default: {} } ast_free_unattached(fun); return func; }
static bool trace_fields(compile_t* c, gentype_t* g, LLVMValueRef ctx, LLVMValueRef object, int extra) { bool need_trace = false; for(int i = 0; i < g->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); if(g->field_keys[i] != TK_EMBED) { // Call the trace function indirectly depending on rcaps. LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, ctx, value, g->fields[i]); } else { // Call the trace function directly without marking the field. const char* fun = genname_trace(genname_type(g->fields[i])); LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, fun); if(trace_fn != NULL) { LLVMValueRef args[2]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, field, c->object_ptr, ""); LLVMBuildCall(c->builder, trace_fn, args, 2, ""); need_trace = true; } } } return need_trace; }
static bool trace_known(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) { gentype_t g; if(!gentype(c, type, &g)) return false; // Get the trace function statically. const char* fun = genname_trace(g.type_name); LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, fun); // If this type has no trace function, don't try to recurse in the runtime. if(trace_fn != NULL) { // Cast the value to an object pointer. LLVMValueRef args[3]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, value, c->object_ptr, ""); args[2] = trace_fn; gencall_runtime(c, "pony_traceobject", args, 3, ""); } else { // Cast the value to a void pointer. LLVMValueRef args[2]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, value, c->void_ptr, ""); gencall_runtime(c, "pony_trace", args, 2, ""); } return true; }
static void print_method(compile_t* c, printbuf_t* buf, reachable_type_t* t, const char* name, ast_t* typeargs) { const char* funname = genname_fun(t->name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); if(func == NULL) return; // Get a reified function. ast_t* fun = get_fun(t->ast, name, typeargs); if(fun == NULL) return; AST_GET_CHILDREN(fun, cap, id, typeparams, params, rtype, can_error, body, docstring); // Print the docstring if we have one. if(ast_id(docstring) == TK_STRING) { printbuf(buf, "/*\n" "%s" "*/\n", ast_name(docstring) ); } // Print the function signature. print_type_name(c, buf, rtype); printbuf(buf, " %s", funname); switch(ast_id(fun)) { case TK_NEW: case TK_BE: { ast_t* def = (ast_t*)ast_data(t->ast); if(ast_id(def) == TK_ACTOR) printbuf(buf, "__send"); break; } default: {} } printbuf(buf, "("); print_type_name(c, buf, t->ast); printbuf(buf, " self"); print_params(c, buf, params); printbuf(buf, ");\n\n"); ast_free_unattached(fun); }
static void genfun_dwarf(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs, ast_t* fun) { if(!codegen_hassource(c)) return; // Get the function. const char* funname = genname_fun(g->type_name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); assert(func != NULL); // Count the parameters, including the receiver. ast_t* params = ast_childidx(fun, 3); size_t count = ast_childcount(params) + 1; size_t buf_size = (count + 1) * sizeof(const char*); const char** pnames = (const char**)pool_alloc_size(buf_size); count = 0; // Return value type name and receiver type name. pnames[count++] = genname_type(ast_childidx(fun, 4)); pnames[count++] = g->type_name; // Get a type name for each parameter. ast_t* param = ast_child(params); while(param != NULL) { ast_t* ptype = ast_childidx(param, 1); pnames[count++] = genname_type(ptype); param = ast_sibling(param); } // Dwarf the method type dwarf_method(&c->dwarf, fun, name, funname, pnames, count, func); // Dwarf the receiver pointer. LLVMBasicBlockRef entry = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef argument = codegen_getlocal(c, stringtab("this")); dwarf_this(&c->dwarf, fun, g->type_name, entry, argument); // Dwarf locals for parameters param = ast_child(params); size_t index = 1; while(param != NULL) { argument = codegen_getlocal(c, ast_name(ast_child(param))); dwarf_parameter(&c->dwarf, param, pnames[index + 1], entry, argument, index); param = ast_sibling(param); index++; } pool_free_size(buf_size, pnames); }
LLVMValueRef gencall_runtime(compile_t* c, const char *name, LLVMValueRef* args, int count, const char* ret) { LLVMValueRef func = LLVMGetNamedFunction(c->module, name); pony_assert(func != NULL); return LLVMBuildCall(c->builder, func, args, count, ret); }
static LLVMValueRef make_function_ptr(compile_t* c, const char* name, LLVMTypeRef type) { LLVMValueRef fun = LLVMGetNamedFunction(c->module, name); if(fun == NULL) return LLVMConstNull(type); return LLVMConstBitCast(fun, type); }
void gencall_throw(compile_t* c) { LLVMValueRef func = LLVMGetNamedFunction(c->module, "pony_throw"); if(c->frame->invoke_target != NULL) invoke_fun(c, func, NULL, 0, "", false); else LLVMBuildCall(c->builder, func, NULL, 0, ""); LLVMBuildUnreachable(c->builder); }
LLVMValueRef gencall_runtime(compile_t* c, const char *name, LLVMValueRef* args, int count, const char* ret) { // Disable debug anchor dwarf_location(&c->dwarf, NULL); LLVMValueRef func = LLVMGetNamedFunction(c->module, name); if(func == NULL) return NULL; return LLVMBuildCall(c->builder, func, args, count, ret); }
static LLVMValueRef make_unbox_function(compile_t* c, gentype_t* g, const char* name) { LLVMValueRef fun = LLVMGetNamedFunction(c->module, name); if(fun == NULL) return LLVMConstNull(c->void_ptr); // Create a new unboxing function that forwards to the real function. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(fun)); int count = LLVMCountParamTypes(f_type); // If it takes no arguments, it's a special number constructor. Don't put it // in the vtable. if(count == 0) return LLVMConstNull(c->void_ptr); size_t buf_size = count *sizeof(LLVMTypeRef); LLVMTypeRef* params = (LLVMTypeRef*)pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, params); LLVMTypeRef ret_type = LLVMGetReturnType(f_type); // It's the same type, but it takes the boxed type instead of the primitive // type as the receiver. params[0] = g->structure_ptr; const char* unbox_name = genname_unbox(name); LLVMTypeRef unbox_type = LLVMFunctionType(ret_type, params, count, false); LLVMValueRef unbox_fun = codegen_addfun(c, unbox_name, unbox_type); codegen_startfun(c, unbox_fun, false); // Extract the primitive type from element 1 and call the real function. LLVMValueRef this_ptr = LLVMGetParam(unbox_fun, 0); LLVMValueRef primitive_ptr = LLVMBuildStructGEP(c->builder, this_ptr, 1, ""); LLVMValueRef primitive = LLVMBuildLoad(c->builder, primitive_ptr, ""); LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size); args[0] = primitive; for(int i = 1; i < count; i++) args[i] = LLVMGetParam(unbox_fun, i); LLVMValueRef result = codegen_call(c, fun, args, count); LLVMBuildRet(c->builder, result); codegen_finishfun(c); pool_free_size(buf_size, params); pool_free_size(buf_size, args); return LLVMConstBitCast(unbox_fun, c->void_ptr); }
LLVMValueRef lp_build_intrinsic(LLVMBuilderRef builder, const char *name, LLVMTypeRef ret_type, LLVMValueRef *args, unsigned num_args, unsigned attr_mask) { LLVMModuleRef module = LLVMGetGlobalParent(LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder))); LLVMValueRef function, call; bool set_callsite_attrs = HAVE_LLVM >= 0x0400 && !(attr_mask & LP_FUNC_ATTR_LEGACY); function = LLVMGetNamedFunction(module, name); if(!function) { LLVMTypeRef arg_types[LP_MAX_FUNC_ARGS]; unsigned i; assert(num_args <= LP_MAX_FUNC_ARGS); for(i = 0; i < num_args; ++i) { assert(args[i]); arg_types[i] = LLVMTypeOf(args[i]); } function = lp_declare_intrinsic(module, name, ret_type, arg_types, num_args); /* * If llvm removes an intrinsic we use, we'll hit this abort (rather * than a call to address zero in the jited code). */ if (LLVMGetIntrinsicID(function) == 0) { _debug_printf("llvm (version 0x%x) found no intrinsic for %s, going to crash...\n", HAVE_LLVM, name); abort(); } if (!set_callsite_attrs) lp_add_func_attributes(function, attr_mask); if (gallivm_debug & GALLIVM_DEBUG_IR) { lp_debug_dump_value(function); } } call = LLVMBuildCall(builder, function, args, num_args, ""); if (set_callsite_attrs) lp_add_func_attributes(call, attr_mask); return call; }
LLVMTypeRef genfun_sig(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs) { // If the function already exists, return its type. const char* funname = genname_fun(g->type_name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); if(func != NULL) return LLVMGetElementType(LLVMTypeOf(func)); ast_t* fun = get_fun(g, name, typeargs); LLVMTypeRef type = get_signature(c, g, fun); ast_free_unattached(fun); return type; }
static LLVMValueRef translateStringBinOp(NodeKind Op, LLVMValueRef ValueE1, LLVMValueRef ValueE2) { LLVMValueRef StrCmpFn = LLVMGetNamedFunction(Module, "strcmp"); LLVMValueRef CmpArgs[] = { ValueE1, ValueE2 }, CallStrCmp = LLVMBuildCall(Builder, StrCmpFn, CmpArgs, 2, ""), ZeroConst = LLVMConstInt(LLVMInt32Type(), 0, 1); switch (Op) { case LtOp: return LLVMBuildICmp(Builder, LLVMIntSLT, CallStrCmp, ZeroConst, ""); case LeOp: return LLVMBuildICmp(Builder, LLVMIntSLE, CallStrCmp, ZeroConst, ""); case GtOp: return LLVMBuildICmp(Builder, LLVMIntSGT, CallStrCmp, ZeroConst, ""); case GeOp: return LLVMBuildICmp(Builder, LLVMIntSGE, CallStrCmp, ZeroConst, ""); case EqOp: return LLVMBuildICmp(Builder, LLVMIntEQ, CallStrCmp, ZeroConst, ""); case DiffOp: return LLVMBuildICmp(Builder, LLVMIntNE, CallStrCmp, ZeroConst, ""); default: return NULL; } }
/** * lp_build_assert. * * Build an assertion in LLVM IR by building a function call to the * lp_assert() function above. * * \param condition should be an 'i1' or 'i32' value * \param msg a string to print if the assertion fails. */ LLVMValueRef lp_build_assert(LLVMBuilderRef builder, LLVMValueRef condition, const char *msg) { LLVMModuleRef module; LLVMTypeRef arg_types[2]; LLVMValueRef msg_string, assert_func, params[2], r; module = LLVMGetGlobalParent(LLVMGetBasicBlockParent( LLVMGetInsertBlock(builder))); msg_string = lp_build_const_string_variable(module, msg, strlen(msg) + 1); arg_types[0] = LLVMInt32Type(); arg_types[1] = LLVMPointerType(LLVMInt8Type(), 0); /* lookup the lp_assert function */ assert_func = LLVMGetNamedFunction(module, "lp_assert"); /* Create the assertion function if not found */ if (!assert_func) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidType(), arg_types, 2, 0); assert_func = LLVMAddFunction(module, "lp_assert", func_type); LLVMSetFunctionCallConv(assert_func, LLVMCCallConv); LLVMSetLinkage(assert_func, LLVMExternalLinkage); LLVMAddGlobalMapping(lp_build_engine, assert_func, func_to_pointer((func_pointer)lp_assert)); } assert(assert_func); /* build function call param list */ params[0] = LLVMBuildZExt(builder, condition, arg_types[0], ""); params[1] = LLVMBuildBitCast(builder, msg_string, arg_types[1], ""); /* check arg types */ assert(LLVMTypeOf(params[0]) == arg_types[0]); assert(LLVMTypeOf(params[1]) == arg_types[1]); r = LLVMBuildCall(builder, assert_func, params, 2, ""); return r; }
static bool trace_tuple(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) { // Invoke the trace function directly. Do not trace the address of the tuple. const char* type_name = genname_type(type); const char* trace_name = genname_tracetuple(type_name); LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, trace_name); // There will be no trace function if the tuple doesn't need tracing. if(trace_fn == NULL) return false; LLVMValueRef args[2]; args[0] = ctx; args[1] = value; LLVMBuildCall(c->builder, trace_fn, args, 2, ""); return true; }
/** * lp_build_printf. * * Build printf call in LLVM IR. The output goes to stdout. * The additional variable arguments need to have type * LLVMValueRef. */ LLVMValueRef lp_build_printf(struct gallivm_state *gallivm, const char *fmt, ...) { va_list arglist; int i = 0; int argcount = lp_get_printf_arg_count(fmt); LLVMBuilderRef builder = gallivm->builder; LLVMContextRef context = gallivm->context; LLVMModuleRef module = gallivm->module; LLVMValueRef params[50]; LLVMValueRef fmtarg = lp_build_const_string_variable(module, context, fmt, strlen(fmt) + 1); LLVMValueRef int0 = lp_build_const_int32(gallivm, 0); LLVMValueRef index[2]; LLVMValueRef func_printf = LLVMGetNamedFunction(module, "printf"); assert(Elements(params) >= argcount + 1); index[0] = index[1] = int0; if (!func_printf) { LLVMTypeRef printf_type = LLVMFunctionType(LLVMIntTypeInContext(context, 32), NULL, 0, 1); func_printf = LLVMAddFunction(module, "printf", printf_type); } params[0] = LLVMBuildGEP(builder, fmtarg, index, 2, ""); va_start(arglist, fmt); for (i = 1; i <= argcount; i++) { LLVMValueRef val = va_arg(arglist, LLVMValueRef); LLVMTypeRef type = LLVMTypeOf(val); /* printf wants doubles, so lets convert so that * we can actually print them */ if (LLVMGetTypeKind(type) == LLVMFloatTypeKind) val = LLVMBuildFPExt(builder, val, LLVMDoubleTypeInContext(context), ""); params[i] = val; } va_end(arglist); return LLVMBuildCall(builder, func_printf, params, argcount + 1, ""); }
void JITImpl::Functions::init(LLVMModuleRef module) { struct { const char *name; LLVMValueRef *ref; } initInfo[] = { { "jitStubImpl", &jitStubImpl }, { "jitGetPc", &jitGetPc }, { "jitUpdateExecutionFrequency", &jitUpdateExecutionFrequency }, { "jitComputeAddress", &jitComputeAddress }, { "jitCheckAddress", &jitCheckAddress }, { "jitInvalidateByteCheck", &jitInvalidateByteCheck }, { "jitInvalidateShortCheck", &jitInvalidateShortCheck }, { "jitInvalidateWordCheck", &jitInvalidateWordCheck }, { "jitInterpretOne", &jitInterpretOne }, }; for (unsigned i = 0; i < ARRAY_SIZE(initInfo); i++) { *initInfo[i].ref = LLVMGetNamedFunction(module, initInfo[i].name); assert(*initInfo[i].ref && "function not found in module"); } }
void JITImpl::init() { if (initialized) return; LLVMLinkInJIT(); LLVMInitializeNativeTarget(); LLVMMemoryBufferRef memBuffer = LLVMExtraCreateMemoryBufferWithPtr(instructionBitcode, instructionBitcodeSize); char *outMessage; if (LLVMParseBitcode(memBuffer, &module, &outMessage)) { std::cerr << "Error loading bitcode: " << outMessage << '\n'; std::abort(); } // TODO experiment with opt level. if (LLVMCreateJITCompilerForModule(&executionEngine, module, 1, &outMessage)) { std::cerr << "Error creating JIT compiler: " << outMessage << '\n'; std::abort(); } builder = LLVMCreateBuilder(); LLVMValueRef callee = LLVMGetNamedFunction(module, "jitInstructionTemplate"); assert(callee && "jitInstructionTemplate() not found in module"); jitFunctionType = LLVMGetElementType(LLVMTypeOf(callee)); functions.init(module); FPM = LLVMCreateFunctionPassManagerForModule(module); LLVMAddTargetData(LLVMGetExecutionEngineTargetData(executionEngine), FPM); LLVMAddBasicAliasAnalysisPass(FPM); LLVMAddJumpThreadingPass(FPM); LLVMAddGVNPass(FPM); LLVMAddJumpThreadingPass(FPM); LLVMAddCFGSimplificationPass(FPM); LLVMAddDeadStoreEliminationPass(FPM); LLVMAddInstructionCombiningPass(FPM); LLVMInitializeFunctionPassManager(FPM); if (DEBUG_JIT) { LLVMExtraRegisterJitDisassembler(executionEngine, LLVMGetTarget(module)); } initialized = true; }
LLVMValueRef lp_declare_intrinsic(LLVMModuleRef module, const char *name, LLVMTypeRef ret_type, LLVMTypeRef *arg_types, unsigned num_args) { LLVMTypeRef function_type; LLVMValueRef function; assert(!LLVMGetNamedFunction(module, name)); function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0); function = LLVMAddFunction(module, name, function_type); LLVMSetFunctionCallConv(function, LLVMCCallConv); LLVMSetLinkage(function, LLVMExternalLinkage); assert(LLVMIsDeclaration(function)); return function; }
static LLVMValueRef zephir_get_add_function(zephir_context *context) { LLVMValueRef function; LLVMTypeRef arg_tys[3]; function = LLVMGetNamedFunction(context->module, "add_function"); if (!function) { arg_tys[0] = context->types.zval_pointer_type; arg_tys[1] = context->types.zval_pointer_type; arg_tys[2] = context->types.zval_pointer_type; function = LLVMAddFunction(context->module, "add_function", LLVMFunctionType(LLVMVoidType(), arg_tys, 3, 0)); if (!function) { zend_error(E_ERROR, "Cannot register add_function"); } LLVMAddGlobalMapping(context->engine, function, add_function); LLVMSetFunctionCallConv(function, LLVMCCallConv); LLVMAddFunctionAttr(function, LLVMNoUnwindAttribute); } return function; }
LLVMValueRef ac_build_intrinsic(struct ac_llvm_context *ctx, const char *name, LLVMTypeRef return_type, LLVMValueRef *params, unsigned param_count, unsigned attrib_mask) { LLVMValueRef function, call; bool set_callsite_attrs = HAVE_LLVM >= 0x0400 && !(attrib_mask & AC_FUNC_ATTR_LEGACY); function = LLVMGetNamedFunction(ctx->module, name); if (!function) { LLVMTypeRef param_types[32], function_type; unsigned i; assert(param_count <= 32); for (i = 0; i < param_count; ++i) { assert(params[i]); param_types[i] = LLVMTypeOf(params[i]); } function_type = LLVMFunctionType(return_type, param_types, param_count, 0); function = LLVMAddFunction(ctx->module, name, function_type); LLVMSetFunctionCallConv(function, LLVMCCallConv); LLVMSetLinkage(function, LLVMExternalLinkage); if (!set_callsite_attrs) ac_add_func_attributes(ctx->context, function, attrib_mask); } call = LLVMBuildCall(ctx->builder, function, params, param_count, ""); if (set_callsite_attrs) ac_add_func_attributes(ctx->context, call, attrib_mask); return call; }
int test_kal_codegen_prototype() { kal_named_value *val; unsigned int arg_count = 3; char **args = malloc(sizeof(char*) * arg_count); args[0] = "foo"; args[1] = "bar"; args[2] = "baz"; LLVMModuleRef module = LLVMModuleCreateWithName("kal"); LLVMBuilderRef builder = LLVMCreateBuilder(); kal_ast_node *node = kal_ast_prototype_create("my_func", args, 3); kal_codegen_reset(); LLVMValueRef value = kal_codegen(node, module, builder); mu_assert(value != NULL, ""); mu_assert(LLVMGetNamedFunction(module, "my_func") == value, ""); mu_assert(LLVMCountParams(value) == 3, ""); val = kal_codegen_named_value("foo"); mu_assert(val->value == LLVMGetParam(value, 0), ""); mu_assert(LLVMGetTypeKind(LLVMTypeOf(LLVMGetParam(value, 0))) == LLVMDoubleTypeKind, ""); val = kal_codegen_named_value("bar"); mu_assert(val->value == LLVMGetParam(value, 1), ""); mu_assert(LLVMGetTypeKind(LLVMTypeOf(LLVMGetParam(value, 1))) == LLVMDoubleTypeKind, ""); val = kal_codegen_named_value("baz"); mu_assert(val->value == LLVMGetParam(value, 2), ""); mu_assert(LLVMGetTypeKind(LLVMTypeOf(LLVMGetParam(value, 2))) == LLVMDoubleTypeKind, ""); LLVMDisposeBuilder(builder); LLVMDisposeModule(module); kal_ast_node_free(node); return 0; }
void heapPush(LLVMValueRef ExecRA) { LLVMValueRef PushFunction = LLVMGetNamedFunction(Module, "push.heap"); LLVMBuildCall(Builder, PushFunction, &ExecRA, 1, ""); }
void heapPop() { LLVMValueRef PopFunction = LLVMGetNamedFunction(Module, "pop.heap"); LLVMBuildCall(Builder, PopFunction, NULL, 0, ""); }
static void gen_main(compile_t* c, gentype_t* main_g, gentype_t* env_g) { LLVMTypeRef params[3]; params[0] = c->i32; params[1] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0); params[2] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0); LLVMTypeRef ftype = LLVMFunctionType(c->i32, params, 3, false); LLVMValueRef func = LLVMAddFunction(c->module, "main", ftype); codegen_startfun(c, func, false); LLVMValueRef args[3]; args[0] = LLVMGetParam(func, 0); LLVMSetValueName(args[0], "argc"); args[1] = LLVMGetParam(func, 1); LLVMSetValueName(args[1], "argv"); args[2] = LLVMGetParam(func, 2); LLVMSetValueName(args[1], "envp"); // Initialise the pony runtime with argc and argv, getting a new argc. args[0] = gencall_runtime(c, "pony_init", args, 2, "argc"); // Create the main actor and become it. LLVMValueRef main_actor = create_main(c, main_g); // Create an Env on the main actor's heap. const char* env_name = "Env"; const char* env_create = genname_fun(env_name, "_create", NULL); LLVMValueRef env_args[4]; env_args[0] = gencall_alloc(c, env_g); env_args[1] = LLVMBuildZExt(c->builder, args[0], c->i64, ""); env_args[2] = args[1]; env_args[3] = args[2]; LLVMValueRef env = gencall_runtime(c, env_create, env_args, 4, "env"); LLVMSetInstructionCallConv(env, GEN_CALLCONV); // Run primitive initialisers using the main actor's heap. primitive_call(c, stringtab("_init"), env); // Create a type for the message. LLVMTypeRef f_params[4]; f_params[0] = c->i32; f_params[1] = c->i32; f_params[2] = c->void_ptr; f_params[3] = LLVMTypeOf(env); LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, 4, false); LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0); // Allocate the message, setting its size and ID. uint32_t index = genfun_vtable_index(c, main_g, stringtab("create"), NULL); size_t msg_size = LLVMABISizeOfType(c->target_data, msg_type); args[0] = LLVMConstInt(c->i32, pool_index(msg_size), false); args[1] = LLVMConstInt(c->i32, index, false); LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, ""); LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); // Set the message contents. LLVMValueRef env_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, 3, ""); LLVMBuildStore(c->builder, env, env_ptr); // Trace the message. gencall_runtime(c, "pony_gc_send", NULL, 0, ""); const char* env_trace = genname_trace(env_name); args[0] = LLVMBuildBitCast(c->builder, env, c->object_ptr, ""); args[1] = LLVMGetNamedFunction(c->module, env_trace); gencall_runtime(c, "pony_traceobject", args, 2, ""); gencall_runtime(c, "pony_send_done", NULL, 0, ""); // Send the message. args[0] = main_actor; args[1] = msg; gencall_runtime(c, "pony_sendv", args, 2, ""); // Start the runtime. LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); LLVMValueRef rc = gencall_runtime(c, "pony_start", &zero, 1, ""); // Run primitive finalisers. We create a new main actor as a context to run // the finalisers in, but we do not initialise or schedule it. LLVMValueRef final_actor = create_main(c, main_g); primitive_call(c, stringtab("_final"), NULL); args[0] = final_actor; gencall_runtime(c, "pony_destroy", args, 1, ""); // Return the runtime exit code. LLVMBuildRet(c->builder, rc); codegen_finishfun(c); // External linkage for main(). LLVMSetLinkage(func, LLVMExternalLinkage); }
/** * Fetch a pixel into a 4 float AoS. * * \param format_desc describes format of the image we're fetching from * \param ptr address of the pixel block (or the texel if uncompressed) * \param i, j the sub-block pixel coordinates. For non-compressed formats * these will always be (0, 0). * \return a 4 element vector with the pixel's RGBA values. */ LLVMValueRef lp_build_fetch_rgba_aos(struct gallivm_state *gallivm, const struct util_format_description *format_desc, struct lp_type type, LLVMValueRef base_ptr, LLVMValueRef offset, LLVMValueRef i, LLVMValueRef j) { LLVMBuilderRef builder = gallivm->builder; unsigned num_pixels = type.length / 4; struct lp_build_context bld; assert(type.length <= LP_MAX_VECTOR_LENGTH); assert(type.length % 4 == 0); lp_build_context_init(&bld, gallivm, type); /* * Trivial case * * The format matches the type (apart of a swizzle) so no need for * scaling or converting. */ if (format_matches_type(format_desc, type) && format_desc->block.bits <= type.width * 4 && util_is_power_of_two(format_desc->block.bits)) { LLVMValueRef packed; /* * The format matches the type (apart of a swizzle) so no need for * scaling or converting. */ packed = lp_build_gather(gallivm, type.length/4, format_desc->block.bits, type.width*4, base_ptr, offset); assert(format_desc->block.bits <= type.width * type.length); packed = LLVMBuildBitCast(gallivm->builder, packed, lp_build_vec_type(gallivm, type), ""); return lp_build_format_swizzle_aos(format_desc, &bld, packed); } /* * Bit arithmetic */ if (format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN && (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) && format_desc->block.width == 1 && format_desc->block.height == 1 && util_is_power_of_two(format_desc->block.bits) && format_desc->block.bits <= 32 && format_desc->is_bitmask && !format_desc->is_mixed && (format_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED || format_desc->channel[1].type == UTIL_FORMAT_TYPE_UNSIGNED)) { LLVMValueRef tmps[LP_MAX_VECTOR_LENGTH/4]; LLVMValueRef res; unsigned k; /* * Unpack a pixel at a time into a <4 x float> RGBA vector */ for (k = 0; k < num_pixels; ++k) { LLVMValueRef packed; packed = lp_build_gather_elem(gallivm, num_pixels, format_desc->block.bits, 32, base_ptr, offset, k); tmps[k] = lp_build_unpack_arith_rgba_aos(gallivm, format_desc, packed); } /* * Type conversion. * * TODO: We could avoid floating conversion for integer to * integer conversions. */ if (gallivm_debug & GALLIVM_DEBUG_PERF && !type.floating) { debug_printf("%s: unpacking %s with floating point\n", __FUNCTION__, format_desc->short_name); } lp_build_conv(gallivm, lp_float32_vec4_type(), type, tmps, num_pixels, &res, 1); return lp_build_format_swizzle_aos(format_desc, &bld, res); } /* * YUV / subsampled formats */ if (format_desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) { struct lp_type tmp_type; LLVMValueRef tmp; memset(&tmp_type, 0, sizeof tmp_type); tmp_type.width = 8; tmp_type.length = num_pixels * 4; tmp_type.norm = TRUE; tmp = lp_build_fetch_subsampled_rgba_aos(gallivm, format_desc, num_pixels, base_ptr, offset, i, j); lp_build_conv(gallivm, tmp_type, type, &tmp, 1, &tmp, 1); return tmp; } /* * Fallback to util_format_description::fetch_rgba_8unorm(). */ if (format_desc->fetch_rgba_8unorm && !type.floating && type.width == 8 && !type.sign && type.norm) { /* * Fallback to calling util_format_description::fetch_rgba_8unorm. * * This is definitely not the most efficient way of fetching pixels, as * we miss the opportunity to do vectorization, but this it is a * convenient for formats or scenarios for which there was no opportunity * or incentive to optimize. */ LLVMModuleRef module = LLVMGetGlobalParent(LLVMGetBasicBlockParent(LLVMGetInsertBlock(gallivm->builder))); char name[256]; LLVMTypeRef i8t = LLVMInt8TypeInContext(gallivm->context); LLVMTypeRef pi8t = LLVMPointerType(i8t, 0); LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context); LLVMValueRef function; LLVMValueRef tmp_ptr; LLVMValueRef tmp; LLVMValueRef res; LLVMValueRef callee; unsigned k; util_snprintf(name, sizeof name, "util_format_%s_fetch_rgba_8unorm", format_desc->short_name); if (gallivm_debug & GALLIVM_DEBUG_PERF) { debug_printf("%s: falling back to %s\n", __FUNCTION__, name); } /* * Declare and bind format_desc->fetch_rgba_8unorm(). */ function = LLVMGetNamedFunction(module, name); if (!function) { /* * Function to call looks like: * fetch(uint8_t *dst, const uint8_t *src, unsigned i, unsigned j) */ LLVMTypeRef ret_type; LLVMTypeRef arg_types[4]; LLVMTypeRef function_type; ret_type = LLVMVoidTypeInContext(gallivm->context); arg_types[0] = pi8t; arg_types[1] = pi8t; arg_types[2] = i32t; arg_types[3] = i32t; function_type = LLVMFunctionType(ret_type, arg_types, Elements(arg_types), 0); function = LLVMAddFunction(module, name, function_type); LLVMSetFunctionCallConv(function, LLVMCCallConv); LLVMSetLinkage(function, LLVMExternalLinkage); assert(LLVMIsDeclaration(function)); } /* make const pointer for the C fetch_rgba_float function */ callee = lp_build_const_int_pointer(gallivm, func_to_pointer((func_pointer) format_desc->fetch_rgba_8unorm)); /* cast the callee pointer to the function's type */ function = LLVMBuildBitCast(builder, callee, LLVMTypeOf(function), "cast callee"); tmp_ptr = lp_build_alloca(gallivm, i32t, ""); res = LLVMGetUndef(LLVMVectorType(i32t, num_pixels)); /* * Invoke format_desc->fetch_rgba_8unorm() for each pixel and insert the result * in the SoA vectors. */ for (k = 0; k < num_pixels; ++k) { LLVMValueRef index = lp_build_const_int32(gallivm, k); LLVMValueRef args[4]; args[0] = LLVMBuildBitCast(builder, tmp_ptr, pi8t, ""); args[1] = lp_build_gather_elem_ptr(gallivm, num_pixels, base_ptr, offset, k); if (num_pixels == 1) { args[2] = i; args[3] = j; } else { args[2] = LLVMBuildExtractElement(builder, i, index, ""); args[3] = LLVMBuildExtractElement(builder, j, index, ""); } LLVMBuildCall(builder, function, args, Elements(args), ""); tmp = LLVMBuildLoad(builder, tmp_ptr, ""); if (num_pixels == 1) { res = tmp; } else { res = LLVMBuildInsertElement(builder, res, tmp, index, ""); } } /* Bitcast from <n x i32> to <4n x i8> */ res = LLVMBuildBitCast(builder, res, bld.vec_type, ""); return res; } /* * Fallback to util_format_description::fetch_rgba_float(). */ if (format_desc->fetch_rgba_float) { /* * Fallback to calling util_format_description::fetch_rgba_float. * * This is definitely not the most efficient way of fetching pixels, as * we miss the opportunity to do vectorization, but this it is a * convenient for formats or scenarios for which there was no opportunity * or incentive to optimize. */ LLVMModuleRef module = LLVMGetGlobalParent(LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder))); char name[256]; LLVMTypeRef f32t = LLVMFloatTypeInContext(gallivm->context); LLVMTypeRef f32x4t = LLVMVectorType(f32t, 4); LLVMTypeRef pf32t = LLVMPointerType(f32t, 0); LLVMTypeRef pi8t = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0); LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context); LLVMValueRef function; LLVMValueRef tmp_ptr; LLVMValueRef tmps[LP_MAX_VECTOR_LENGTH/4]; LLVMValueRef res; LLVMValueRef callee; unsigned k; util_snprintf(name, sizeof name, "util_format_%s_fetch_rgba_float", format_desc->short_name); if (gallivm_debug & GALLIVM_DEBUG_PERF) { debug_printf("%s: falling back to %s\n", __FUNCTION__, name); } /* * Declare and bind format_desc->fetch_rgba_float(). */ function = LLVMGetNamedFunction(module, name); if (!function) { /* * Function to call looks like: * fetch(float *dst, const uint8_t *src, unsigned i, unsigned j) */ LLVMTypeRef ret_type; LLVMTypeRef arg_types[4]; LLVMTypeRef function_type; ret_type = LLVMVoidTypeInContext(gallivm->context); arg_types[0] = pf32t; arg_types[1] = pi8t; arg_types[2] = i32t; arg_types[3] = i32t; function_type = LLVMFunctionType(ret_type, arg_types, Elements(arg_types), 0); function = LLVMAddFunction(module, name, function_type); LLVMSetFunctionCallConv(function, LLVMCCallConv); LLVMSetLinkage(function, LLVMExternalLinkage); assert(LLVMIsDeclaration(function)); } /* Note: we're using this casting here instead of LLVMAddGlobalMapping() * to work around a bug in LLVM 2.6. */ /* make const pointer for the C fetch_rgba_float function */ callee = lp_build_const_int_pointer(gallivm, func_to_pointer((func_pointer) format_desc->fetch_rgba_float)); /* cast the callee pointer to the function's type */ function = LLVMBuildBitCast(builder, callee, LLVMTypeOf(function), "cast callee"); tmp_ptr = lp_build_alloca(gallivm, f32x4t, ""); /* * Invoke format_desc->fetch_rgba_float() for each pixel and insert the result * in the SoA vectors. */ for (k = 0; k < num_pixels; ++k) { LLVMValueRef args[4]; args[0] = LLVMBuildBitCast(builder, tmp_ptr, pf32t, ""); args[1] = lp_build_gather_elem_ptr(gallivm, num_pixels, base_ptr, offset, k); if (num_pixels == 1) { args[2] = i; args[3] = j; } else { LLVMValueRef index = lp_build_const_int32(gallivm, k); args[2] = LLVMBuildExtractElement(builder, i, index, ""); args[3] = LLVMBuildExtractElement(builder, j, index, ""); } LLVMBuildCall(builder, function, args, Elements(args), ""); tmps[k] = LLVMBuildLoad(builder, tmp_ptr, ""); } lp_build_conv(gallivm, lp_float32_vec4_type(), type, tmps, num_pixels, &res, 1); return res; } assert(0); return lp_build_undef(gallivm, type); }
LLVMValueRef gen_ffi(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, id, typeargs, args, named_args, can_err); bool err = (ast_id(can_err) == TK_QUESTION); // Get the function name, +1 to skip leading @ const char* f_name = ast_name(id) + 1; // Get the return type. ast_t* type = ast_type(ast); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); // Get the function. LLVMValueRef func = LLVMGetNamedFunction(c->module, f_name); if(func == NULL) { // If we have no prototype, declare one. ast_t* decl = (ast_t*)ast_data(ast); if(decl != NULL) { // Define using the declared types. AST_GET_CHILDREN(decl, decl_id, decl_ret, decl_params, decl_err); err = (ast_id(decl_err) == TK_QUESTION); func = declare_ffi(c, f_name, t, decl_params, err, false); } else if(!strncmp(f_name, "llvm.", 5)) { // Intrinsic, so use the exact types we supply. func = declare_ffi(c, f_name, t, args, err, true); } else { // Make it varargs. func = declare_ffi_vararg(c, f_name, t, err); } } // Generate the arguments. int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* f_args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); LLVMTypeRef* f_params = NULL; bool vararg = (LLVMIsFunctionVarArg(f_type) != 0); if(!vararg) { f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, f_params); } ast_t* arg = ast_child(args); for(int i = 0; i < count; i++) { f_args[i] = gen_expr(c, arg); if(!vararg) f_args[i] = cast_ffi_arg(c, f_args[i], f_params[i]); if(f_args[i] == NULL) { ponyint_pool_free_size(buf_size, f_args); return NULL; } arg = ast_sibling(arg); } // If we can error out and we have an invoke target, generate an invoke // instead of a call. LLVMValueRef result; codegen_debugloc(c, ast); if(err && (c->frame->invoke_target != NULL)) result = invoke_fun(c, func, f_args, count, "", false); else result = LLVMBuildCall(c->builder, func, f_args, count, ""); codegen_debugloc(c, NULL); ponyint_pool_free_size(buf_size, f_args); if(!vararg) ponyint_pool_free_size(buf_size, f_params); // Special case a None return value, which is used for void functions. if(is_none(type)) return t->instance; return result; }