static void make_dispatch(compile_t* c, gentype_t* g) { // Do nothing if we're not an actor. if(g->underlying != TK_ACTOR) return; // Create a dispatch function. const char* dispatch_name = genname_dispatch(g->type_name); g->dispatch_fn = codegen_addfun(c, dispatch_name, c->dispatch_type); codegen_startfun(c, g->dispatch_fn, false); LLVMBasicBlockRef unreachable = codegen_block(c, "unreachable"); LLVMValueRef this_ptr = LLVMGetParam(g->dispatch_fn, 0); LLVMSetValueName(this_ptr, "this"); g->dispatch_msg = LLVMGetParam(g->dispatch_fn, 1); LLVMSetValueName(g->dispatch_msg, "msg"); // Read the message ID. LLVMValueRef id_ptr = LLVMBuildStructGEP(c->builder, g->dispatch_msg, 1, ""); LLVMValueRef id = LLVMBuildLoad(c->builder, id_ptr, "id"); // Store a reference to the dispatch switch. When we build behaviours, we // will add cases to this switch statement based on message ID. g->dispatch_switch = LLVMBuildSwitch(c->builder, id, unreachable, 0); // Mark the default case as unreachable. LLVMPositionBuilderAtEnd(c->builder, unreachable); LLVMBuildUnreachable(c->builder); codegen_finishfun(c); }
static void handle_line(char **tokens, int ntokens) { char *name = tokens[0]; LLVMValueRef param; LLVMValueRef res; LLVMModuleRef M = LLVMModuleCreateWithName(name); LLVMTypeRef I64ty = LLVMInt64Type(); LLVMTypeRef I64Ptrty = LLVMPointerType(I64ty, 0); LLVMTypeRef Fty = LLVMFunctionType(I64ty, &I64Ptrty, 1, 0); LLVMValueRef F = LLVMAddFunction(M, name, Fty); LLVMBuilderRef builder = LLVMCreateBuilder(); LLVMPositionBuilderAtEnd(builder, LLVMAppendBasicBlock(F, "entry")); LLVMGetParams(F, ¶m); LLVMSetValueName(param, "in"); res = build_from_tokens(tokens + 1, ntokens - 1, builder, param); if (res) { char *irstr = LLVMPrintModuleToString(M); puts(irstr); LLVMDisposeMessage(irstr); } LLVMDisposeBuilder(builder); LLVMDisposeModule(M); }
static LLVMValueRef CreateFibFunction(LLVMModuleRef M, LLVMContextRef Context) { LLVMBuilderRef B = LLVMCreateBuilderInContext(Context); // Create the fib function and insert it into module M. This function is said // to return an int and take an int parameter. LLVMTypeRef ParamTypes[] = {LLVMInt32TypeInContext(Context)}; LLVMTypeRef ReturnType = LLVMInt32TypeInContext(Context); LLVMTypeRef FunctionTy = LLVMFunctionType(ReturnType, ParamTypes, 1, 0); LLVMValueRef FibF = LLVMAddFunction(M, "fib", FunctionTy); // Add a basic block to the function. LLVMBasicBlockRef BB = LLVMAppendBasicBlockInContext(Context, FibF, "EntryBlock"); // Get pointers to the constants. LLVMValueRef One = LLVMConstInt(LLVMInt32TypeInContext(Context), 1, 0); LLVMValueRef Two = LLVMConstInt(LLVMInt32TypeInContext(Context), 2, 0); // Get pointer to the integer argument of the add1 function... LLVMValueRef ArgX = LLVMGetFirstParam(FibF); // Get the arg. LLVMSetValueName(ArgX, "AnArg"); // Give it a nice symbolic name for fun. // Create the true_block. LLVMBasicBlockRef RetBB = LLVMAppendBasicBlockInContext(Context, FibF, "return"); // Create an exit block. LLVMBasicBlockRef RecurseBB = LLVMAppendBasicBlockInContext(Context, FibF, "recurse"); // Create the "if (arg <= 2) goto exitbb" LLVMPositionBuilderAtEnd(B, BB); LLVMValueRef CondInst = LLVMBuildICmp(B, LLVMIntSLE, ArgX, Two, "cond"); LLVMBuildCondBr(B, CondInst, RetBB, RecurseBB); // Create: ret int 1 LLVMPositionBuilderAtEnd(B, RetBB); LLVMBuildRet(B, One); // create fib(x-1) LLVMPositionBuilderAtEnd(B, RecurseBB); LLVMValueRef Sub = LLVMBuildSub(B, ArgX, One, "arg"); LLVMValueRef CallFibX1 = LLVMBuildCall(B, FibF, &Sub, 1, "fibx1"); LLVMSetTailCall(CallFibX1, 1); // create fib(x-2) LLVMPositionBuilderAtEnd(B, RecurseBB); Sub = LLVMBuildSub(B, ArgX, Two, "arg"); LLVMValueRef CallFibX2 = LLVMBuildCall(B, FibF, &Sub, 1, "fibx2"); LLVMSetTailCall(CallFibX2, 1); // fib(x-1)+fib(x-2) LLVMPositionBuilderAtEnd(B, RecurseBB); LLVMValueRef Sum = LLVMBuildAdd(B, CallFibX1, CallFibX2, "addresult"); // Create the return instruction and add it to the basic block LLVMPositionBuilderAtEnd(B, RecurseBB); LLVMBuildRet(B, Sum); return FibF; }
static void name_param(compile_t* c, reachable_type_t* t, reachable_method_t* m, LLVMValueRef func, const char* name, unsigned index, size_t line, size_t pos) { LLVMValueRef value = LLVMGetParam(func, index); LLVMSetValueName(value, name); LLVMValueRef alloc = LLVMBuildAlloca(c->builder, t->use_type, name); LLVMBuildStore(c->builder, value, alloc); codegen_setlocal(c, name, alloc); LLVMMetadataRef info; if(index == 0) { info = LLVMDIBuilderCreateArtificialVariable(c->di, m->di_method, name, index + 1, m->di_file, (unsigned)ast_line(m->r_fun), t->di_type); } else { info = LLVMDIBuilderCreateParameterVariable(c->di, m->di_method, name, index + 1, m->di_file, (unsigned)ast_line(m->r_fun), t->di_type); } LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0); LLVMDIBuilderInsertDeclare(c->di, alloc, info, expr, (unsigned)line, (unsigned)pos, m->di_method, LLVMGetInsertBlock(c->builder)); }
static void name_param(compile_t* c, LLVMValueRef func, const char* name, ast_t* type, int index) { gentype_t g; gentype(c, type, &g); LLVMValueRef param = LLVMGetParam(func, index); LLVMSetValueName(param, name); LLVMValueRef value = LLVMBuildAlloca(c->builder, g.use_type, name); LLVMBuildStore(c->builder, param, value); codegen_setlocal(c, name, value); }
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); }
static void gen_main(compile_t* c, reach_type_t* t_main, reach_type_t* t_env) { 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, NULL, NULL); LLVMValueRef args[4]; 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[2], "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 ctx = gencall_runtime(c, "pony_ctx", NULL, 0, ""); codegen_setctx(c, ctx); LLVMValueRef main_actor = create_main(c, t_main, ctx); // Create an Env on the main actor's heap. reach_method_t* m = reach_method(t_env, TK_NONE, c->str__create, NULL); LLVMValueRef env_args[4]; env_args[0] = gencall_alloc(c, t_env); env_args[1] = args[0]; env_args[2] = LLVMBuildBitCast(c->builder, args[1], c->void_ptr, ""); env_args[3] = LLVMBuildBitCast(c->builder, args[2], c->void_ptr, ""); codegen_call(c, m->func, env_args, 4); LLVMValueRef env = env_args[0]; // Run primitive initialisers using the main actor's heap. primitive_call(c, c->str__init); // 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 = reach_vtable_index(t_main, c->str_create); size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, msg_type); args[0] = LLVMConstInt(c->i32, ponyint_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. args[0] = ctx; gencall_runtime(c, "pony_gc_send", args, 1, ""); args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, env, c->object_ptr, ""); args[2] = LLVMBuildBitCast(c->builder, t_env->desc, c->descriptor_ptr, ""); args[3] = LLVMConstInt(c->i32, PONY_TRACE_IMMUTABLE, false); gencall_runtime(c, "pony_traceknown", args, 4, ""); args[0] = ctx; gencall_runtime(c, "pony_send_done", args, 1, ""); // Send the message. args[0] = ctx; args[1] = main_actor; args[2] = msg; gencall_runtime(c, "pony_sendv", args, 3, ""); // 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. if(need_primitive_call(c, c->str__final)) { LLVMValueRef final_actor = create_main(c, t_main, ctx); primitive_call(c, c->str__final); args[0] = final_actor; gencall_runtime(c, "ponyint_destroy", args, 1, ""); } // Return the runtime exit code. LLVMBuildRet(c->builder, rc); codegen_finishfun(c); // External linkage for main(). LLVMSetLinkage(func, LLVMExternalLinkage); }
// 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; }