void genprim_string_deserialise(compile_t* c, reach_type_t* t) { // Generate the deserisalise function. t->deserialise_fn = codegen_addfun(c, genname_serialise(t->name), c->trace_type); codegen_startfun(c, t->deserialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); gendeserialise_typeid(c, t, object); // Deserialise the string contents. LLVMValueRef alloc = field_value(c, object, 2); LLVMValueRef ptr_offset = field_value(c, object, 3); ptr_offset = LLVMBuildPtrToInt(c->builder, ptr_offset, c->intptr, ""); LLVMValueRef args[3]; args[0] = ctx; args[1] = ptr_offset; args[2] = alloc; LLVMValueRef ptr_addr = gencall_runtime(c, "pony_deserialise_block", args, 3, ""); LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, object, 3, ""); LLVMBuildStore(c->builder, ptr_addr, ptr); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
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); LLVMSetFunctionCallConv(g->dispatch_fn, LLVMCCallConv); codegen_startfun(c, g->dispatch_fn, false); LLVMBasicBlockRef unreachable = codegen_block(c, "unreachable"); // Read the message ID. LLVMValueRef msg = LLVMGetParam(g->dispatch_fn, 2); LLVMValueRef id_ptr = LLVMBuildStructGEP(c->builder, 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 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 void deserialise(compile_t* c, reach_type_t* t, LLVMValueRef ctx, LLVMValueRef object) { // The contents have already been copied. int extra = 0; switch(t->underlying) { case TK_PRIMITIVE: case TK_CLASS: { gendeserialise_typeid(c, t, object); extra++; break; } case TK_ACTOR: { // Skip the actor pad. gendeserialise_typeid(c, t, object); extra += 2; break; } case TK_TUPLETYPE: { // Get the tuple primitive type. if(LLVMTypeOf(object) == t->structure_ptr) { gendeserialise_typeid(c, t, object); object = LLVMBuildStructGEP(c->builder, object, 1, ""); } break; } default: {} } for(uint32_t i = 0; i < t->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); gendeserialise_element(c, t->fields[i].type, t->fields[i].embed, ctx, field); } }
static void set_descriptor(compile_t* c, reach_type_t* t, LLVMValueRef value) { if(t->underlying == TK_STRUCT) return; LLVMValueRef desc_ptr = LLVMBuildStructGEP(c->builder, value, 0, ""); LLVMValueRef store = LLVMBuildStore(c->builder, t->desc, desc_ptr); const char id[] = "tbaa"; LLVMSetMetadata(store, LLVMGetMDKindID(id, sizeof(id) - 1), c->tbaa_descptr); }
static LLVMTypeRef send_message(compile_t* c, ast_t* fun, LLVMValueRef to, LLVMValueRef func, uint32_t index) { // Get the parameter types. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); int count = LLVMCountParamTypes(f_type) + 2; VLA(LLVMTypeRef, f_params, count); LLVMGetParamTypes(f_type, &f_params[2]); // The first one becomes the message size, the second the message ID. f_params[0] = c->i32; f_params[1] = c->i32; f_params[2] = c->void_ptr; LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, count, false); LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0); // Allocate the message, setting its size and ID. size_t msg_size = LLVMABISizeOfType(c->target_data, msg_type); LLVMValueRef args[2]; 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, ""); // Trace while populating the message contents. LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_send", NULL, 0, ""); ast_t* params = ast_childidx(fun, 3); ast_t* param = ast_child(params); bool need_trace = false; for(int i = 3; i < count; i++) { LLVMValueRef arg = LLVMGetParam(func, i - 2); LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i, ""); LLVMBuildStore(c->builder, arg, arg_ptr); need_trace |= gentrace(c, arg, ast_type(param)); param = ast_sibling(param); } if(need_trace) gencall_runtime(c, "pony_send_done", NULL, 0, ""); else LLVMInstructionEraseFromParent(start_trace); // Send the message. args[0] = LLVMBuildBitCast(c->builder, to, c->object_ptr, ""); args[1] = msg; gencall_runtime(c, "pony_sendv", args, 2, ""); // Return the type of the message. return msg_type_ptr; }
LLVMValueRef gendesc_vtable(compile_t* c, LLVMValueRef object, size_t colour) { LLVMValueRef desc = gendesc_fetch(c, object); LLVMValueRef vtable = LLVMBuildStructGEP(c->builder, desc, DESC_VTABLE, ""); LLVMValueRef gep[2]; gep[0] = LLVMConstInt(c->i32, 0, false); gep[1] = LLVMConstInt(c->i32, colour, false); LLVMValueRef func_ptr = LLVMBuildInBoundsGEP(c->builder, vtable, gep, 2, ""); return LLVMBuildLoad(c->builder, func_ptr, ""); }
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); }
static void add_dispatch_case(compile_t* c, gentype_t* g, ast_t* fun, uint32_t index, LLVMValueRef handler, LLVMTypeRef type) { // Add a case to the dispatch function to handle this message. codegen_startfun(c, g->dispatch_fn, false); LLVMBasicBlockRef block = codegen_block(c, "handler"); LLVMValueRef id = LLVMConstInt(c->i32, index, false); LLVMAddCase(g->dispatch_switch, id, block); // Destructure the message. LLVMPositionBuilderAtEnd(c->builder, block); LLVMValueRef ctx = LLVMGetParam(g->dispatch_fn, 0); LLVMValueRef this_ptr = LLVMGetParam(g->dispatch_fn, 1); LLVMValueRef msg = LLVMBuildBitCast(c->builder, LLVMGetParam(g->dispatch_fn, 2), type, ""); int count = LLVMCountParams(handler); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size); args[0] = LLVMBuildBitCast(c->builder, this_ptr, g->use_type, ""); // Trace the message. LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_recv", &ctx, 1, ""); ast_t* params = ast_childidx(fun, 3); ast_t* param = ast_child(params); bool need_trace = false; for(int i = 1; i < count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, msg, i + 2, ""); args[i] = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, ctx, args[i], ast_type(param)); param = ast_sibling(param); } if(need_trace) { gencall_runtime(c, "pony_recv_done", &ctx, 1, ""); } else { LLVMInstructionEraseFromParent(start_trace); } // Call the handler. codegen_call(c, handler, args, count); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); pool_free_size(buf_size, args); }
static bool trace_fields(compile_t* c, gentype_t* g, 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, ""); LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, value, g->fields[i]); } return need_trace; }
LLVMValueRef gencall_allocstruct(compile_t* c, gentype_t* g) { // Disable debug anchor dwarf_location(&c->dwarf, NULL); // We explicitly want a boxed version. // Get the size of the structure. size_t size = (size_t)LLVMABISizeOfType(c->target_data, g->structure); // Get the finaliser, if there is one. const char* final = genname_finalise(g->type_name); LLVMValueRef final_fun = LLVMGetNamedFunction(c->module, final); // Allocate the object. LLVMValueRef args[3]; args[0] = codegen_ctx(c); LLVMValueRef result; if(final_fun == NULL) { if(size <= HEAP_MAX) { uint32_t index = ponyint_heap_index(size); args[1] = LLVMConstInt(c->i32, index, false); result = gencall_runtime(c, "pony_alloc_small", args, 2, ""); } else { args[1] = LLVMConstInt(c->intptr, size, false); result = gencall_runtime(c, "pony_alloc_large", args, 2, ""); } } else { args[1] = LLVMConstInt(c->intptr, size, false); args[2] = LLVMConstBitCast(final_fun, c->final_fn); result = gencall_runtime(c, "pony_alloc_final", args, 3, ""); } result = LLVMBuildBitCast(c->builder, result, g->structure_ptr, ""); // Set the descriptor. if(g->underlying != TK_STRUCT) { LLVMValueRef desc_ptr = LLVMBuildStructGEP(c->builder, result, 0, ""); LLVMBuildStore(c->builder, g->desc, desc_ptr); } return result; }
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value, ast_t* l_type, ast_t* right) { pony_assert(ast_id(l_type) == TK_NOMINAL); pony_assert(ast_id(right) == TK_ID); ast_t* def; ast_t* field; uint32_t index; get_fieldinfo(l_type, right, &def, &field, &index); if(ast_id(def) != TK_STRUCT) index++; if(ast_id(def) == TK_ACTOR) index++; return LLVMBuildStructGEP(c->builder, l_value, index, ""); }
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value, ast_t* l_type, ast_t* right) { switch(ast_id(l_type)) { case TK_NOMINAL: { assert(ast_id(right) == TK_ID); ast_t* def = (ast_t*)ast_data(l_type); ast_t* field = ast_get(def, ast_name(right), NULL); int index = (int)ast_index(field); if(ast_id(def) != TK_STRUCT) index++; if(ast_id(def) == TK_ACTOR) index++; return LLVMBuildStructGEP(c->builder, l_value, index, ""); } case TK_TUPLETYPE: { assert(ast_id(right) == TK_INT); int index = (int)ast_int(right)->low; return LLVMBuildExtractValue(c->builder, l_value, index, ""); } case TK_ARROW: return make_fieldptr(c, l_value, ast_childidx(l_type, 1), right); default: {} } assert(0); return NULL; }
void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[], ast_t* args_ast) { // Allocate the message, setting its size and ID. compile_method_t* c_m = (compile_method_t*)m->c_method; size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, c_m->msg_type); LLVMTypeRef msg_type_ptr = LLVMPointerType(c_m->msg_type, 0); size_t params_buf_size = (m->param_count + 3) * sizeof(LLVMTypeRef); LLVMTypeRef* param_types = (LLVMTypeRef*)ponyint_pool_alloc_size(params_buf_size); LLVMGetStructElementTypes(c_m->msg_type, param_types); size_t args_buf_size = (m->param_count + 1) * sizeof(LLVMValueRef); LLVMValueRef* cast_args = (LLVMValueRef*)ponyint_pool_alloc_size(args_buf_size); size_t arg_types_buf_size = m->param_count * sizeof(ast_t*); ast_t** arg_types = (ast_t**)ponyint_pool_alloc_size(arg_types_buf_size); ast_t* arg_ast = ast_child(args_ast); deferred_reification_t* reify = c->frame->reify; for(size_t i = 0; i < m->param_count; i++) { arg_types[i] = deferred_reify(reify, ast_type(arg_ast), c->opt); cast_args[i+1] = gen_assign_cast(c, param_types[i+3], args[i+1], arg_types[i]); arg_ast = ast_sibling(arg_ast); } LLVMValueRef msg_args[5]; msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false); msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false); LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, ""); LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); LLVMSetMetadataStr(msg, "pony.msgsend", md); LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); for(unsigned int i = 0; i < m->param_count; i++) { LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, ""); LLVMBuildStore(c->builder, cast_args[i+1], arg_ptr); } // Trace while populating the message contents. bool need_trace = false; for(size_t i = 0; i < m->param_count; i++) { if(gentrace_needed(c, arg_types[i], m->params[i].ast)) { need_trace = true; break; } } LLVMValueRef ctx = codegen_ctx(c); if(need_trace) { LLVMValueRef gc = gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); LLVMSetMetadataStr(gc, "pony.msgsend", md); for(size_t i = 0; i < m->param_count; i++) { gentrace(c, ctx, args[i+1], cast_args[i+1], arg_types[i], m->params[i].ast); } gc = gencall_runtime(c, "pony_send_done", &ctx, 1, ""); LLVMSetMetadataStr(gc, "pony.msgsend", md); } // Send the message. msg_args[0] = ctx; msg_args[1] = LLVMBuildBitCast(c->builder, args[0], c->object_ptr, ""); msg_args[2] = msg; msg_args[3] = msg; msg_args[4] = LLVMConstInt(c->i1, 1, false); LLVMValueRef send; if(ast_id(m->fun->ast) == TK_NEW) send = gencall_runtime(c, "pony_sendv_single", msg_args, 5, ""); else send = gencall_runtime(c, "pony_sendv", msg_args, 5, ""); LLVMSetMetadataStr(send, "pony.msgsend", md); ponyint_pool_free_size(params_buf_size, param_types); ponyint_pool_free_size(args_buf_size, cast_args); for(size_t i = 0; i < m->param_count; i++) ast_free_unattached(arg_types[i]); ponyint_pool_free_size(arg_types_buf_size, arg_types); }
static bool gen_field_init(compile_t* c, gentype_t* g) { LLVMValueRef this_ptr = LLVMGetParam(codegen_fun(c), 0); ast_t* def = (ast_t*)ast_data(g->ast); ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); // Struct index of the current field. int index = 1; if(ast_id(def) == TK_ACTOR) index++; // Iterate through all fields. while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: { // Skip this field if it has no initialiser. AST_GET_CHILDREN(member, id, type, body); if(ast_id(body) != TK_NONE) { // Reify the initialiser. ast_t* this_type = set_cap_and_ephemeral(g->ast, TK_REF, TK_NONE); ast_t* var = lookup(NULL, NULL, this_type, ast_name(id)); ast_free_unattached(this_type); assert(var != NULL); body = ast_childidx(var, 2); // Get the field pointer. dwarf_location(&c->dwarf, body); LLVMValueRef l_value = LLVMBuildStructGEP(c->builder, this_ptr, index, ""); // Cast the initialiser to the field type. LLVMValueRef r_value = gen_expr(c, body); if(r_value == NULL) return false; LLVMTypeRef l_type = LLVMGetElementType(LLVMTypeOf(l_value)); LLVMValueRef cast_value = gen_assign_cast(c, l_type, r_value, ast_type(body)); if(cast_value == NULL) return false; // Store the result. LLVMBuildStore(c->builder, cast_value, l_value); } index++; break; } default: {} } member = ast_sibling(member); } return true; }
static bool make_trace(compile_t* c, gentype_t* g) { // Do nothing if we have no fields. if(g->field_count == 0) return true; if(g->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(g->ast, pkg, id); const char* package = ast_name(pkg); const char* name = ast_name(id); if((package == c->str_1) && (name == c->str_Array)) { genprim_array_trace(c, g); return true; } } // Create a trace function. const char* trace_name = genname_trace(g->type_name); LLVMValueRef trace_fn = codegen_addfun(c, trace_name, c->trace_type); codegen_startfun(c, trace_fn, false); LLVMSetFunctionCallConv(trace_fn, LLVMCCallConv); LLVMValueRef arg = LLVMGetParam(trace_fn, 0); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, g->structure_ptr, "object"); // If we don't ever trace anything, delete this function. bool need_trace; if(g->underlying == TK_TUPLETYPE) { // Create another function that traces the tuple members. const char* trace_tuple_name = genname_tracetuple(g->type_name); LLVMTypeRef trace_tuple_type = LLVMFunctionType(c->void_type, &g->primitive, 1, false); LLVMValueRef trace_tuple_fn = codegen_addfun(c, trace_tuple_name, trace_tuple_type); codegen_startfun(c, trace_tuple_fn, false); LLVMSetFunctionCallConv(trace_tuple_fn, LLVMCCallConv); LLVMValueRef arg = LLVMGetParam(trace_tuple_fn, 0); need_trace = trace_elements(c, g, arg); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(need_trace) { // Get the tuple primitive. LLVMValueRef tuple_ptr = LLVMBuildStructGEP(c->builder, object, 1, ""); LLVMValueRef tuple = LLVMBuildLoad(c->builder, tuple_ptr, ""); // Call the tuple trace function with the unboxed primitive type. LLVMBuildCall(c->builder, trace_tuple_fn, &tuple, 1, ""); } else { LLVMDeleteFunction(trace_tuple_fn); } } else { int extra = 1; // Actors have a pad. if(g->underlying == TK_ACTOR) extra++; need_trace = trace_fields(c, g, object, extra); } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(!need_trace) LLVMDeleteFunction(trace_fn); return true; }
static bool make_trace(compile_t* c, reach_type_t* t) { if(t->trace_fn == NULL) return true; if(t->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(t->ast, pkg, id); const char* package = ast_name(pkg); const char* name = ast_name(id); if((package == c->str_builtin) && (name == c->str_Array)) { genprim_array_trace(c, t); return true; } } // Generate the trace function. codegen_startfun(c, t->trace_fn, NULL, NULL); LLVMSetFunctionCallConv(t->trace_fn, LLVMCCallConv); LLVMSetLinkage(t->trace_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->trace_fn, 0); LLVMValueRef arg = LLVMGetParam(t->trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, "object"); int extra = 0; // Non-structs have a type descriptor. if(t->underlying != TK_STRUCT) extra++; // Actors have a pad. if(t->underlying == TK_ACTOR) extra++; for(uint32_t i = 0; i < t->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); if(!t->fields[i].embed) { // Call the trace function indirectly depending on rcaps. LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); gentrace(c, ctx, value, t->fields[i].ast); } else { // Call the trace function directly without marking the field. LLVMValueRef trace_fn = t->fields[i].type->trace_fn; 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, ""); } } } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); return true; }
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); }
/* * Create a function that deforms a tuple of type desc up to natts columns. */ LLVMValueRef slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts) { char *funcname; LLVMModuleRef mod; LLVMBuilderRef b; LLVMTypeRef deform_sig; LLVMValueRef v_deform_fn; LLVMBasicBlockRef b_entry; LLVMBasicBlockRef b_adjust_unavail_cols; LLVMBasicBlockRef b_find_start; LLVMBasicBlockRef b_out; LLVMBasicBlockRef b_dead; LLVMBasicBlockRef *attcheckattnoblocks; LLVMBasicBlockRef *attstartblocks; LLVMBasicBlockRef *attisnullblocks; LLVMBasicBlockRef *attcheckalignblocks; LLVMBasicBlockRef *attalignblocks; LLVMBasicBlockRef *attstoreblocks; LLVMValueRef v_offp; LLVMValueRef v_tupdata_base; LLVMValueRef v_tts_values; LLVMValueRef v_tts_nulls; LLVMValueRef v_slotoffp; LLVMValueRef v_slowp; LLVMValueRef v_nvalidp; LLVMValueRef v_nvalid; LLVMValueRef v_maxatt; LLVMValueRef v_slot; LLVMValueRef v_tupleheaderp; LLVMValueRef v_tuplep; LLVMValueRef v_infomask1; LLVMValueRef v_infomask2; LLVMValueRef v_bits; LLVMValueRef v_hoff; LLVMValueRef v_hasnulls; /* last column (0 indexed) guaranteed to exist */ int guaranteed_column_number = -1; /* current known alignment */ int known_alignment = 0; /* if true, known_alignment describes definite offset of column */ bool attguaranteedalign = true; int attnum; mod = llvm_mutable_module(context); funcname = llvm_expand_funcname(context, "deform"); /* * Check which columns do have to exist, so we don't have to check the * rows natts unnecessarily. */ for (attnum = 0; attnum < desc->natts; attnum++) { Form_pg_attribute att = TupleDescAttr(desc, attnum); /* * If the column is possibly missing, we can't rely on its (or * subsequent) NOT NULL constraints to indicate minimum attributes in * the tuple, so stop here. */ if (att->atthasmissing) break; /* * Column is NOT NULL and there've been no preceding missing columns, * it's guaranteed that all columns up to here exist at least in the * NULL bitmap. */ if (att->attnotnull) guaranteed_column_number = attnum; } /* Create the signature and function */ { LLVMTypeRef param_types[1]; param_types[0] = l_ptr(StructTupleTableSlot); deform_sig = LLVMFunctionType(LLVMVoidType(), param_types, lengthof(param_types), 0); } v_deform_fn = LLVMAddFunction(mod, funcname, deform_sig); LLVMSetLinkage(v_deform_fn, LLVMInternalLinkage); LLVMSetParamAlignment(LLVMGetParam(v_deform_fn, 0), MAXIMUM_ALIGNOF); llvm_copy_attributes(AttributeTemplate, v_deform_fn); b_entry = LLVMAppendBasicBlock(v_deform_fn, "entry"); b_adjust_unavail_cols = LLVMAppendBasicBlock(v_deform_fn, "adjust_unavail_cols"); b_find_start = LLVMAppendBasicBlock(v_deform_fn, "find_startblock"); b_out = LLVMAppendBasicBlock(v_deform_fn, "outblock"); b_dead = LLVMAppendBasicBlock(v_deform_fn, "deadblock"); b = LLVMCreateBuilder(); attcheckattnoblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attstartblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attisnullblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attcheckalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attstoreblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); known_alignment = 0; LLVMPositionBuilderAtEnd(b, b_entry); /* perform allocas first, llvm only converts those to registers */ v_offp = LLVMBuildAlloca(b, TypeSizeT, "v_offp"); v_slot = LLVMGetParam(v_deform_fn, 0); v_tts_values = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_VALUES, "tts_values"); v_tts_nulls = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL, "tts_ISNULL"); v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, ""); v_slowp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_SLOW, ""); v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, ""); v_tupleheaderp = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_TUPLE, "tupleheader"); v_tuplep = l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA, "tuple"); v_bits = LLVMBuildBitCast(b, LLVMBuildStructGEP(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_BITS, ""), l_ptr(LLVMInt8Type()), "t_bits"); v_infomask1 = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK, "infomask1"); v_infomask2 = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2, "infomask2"); /* t_infomask & HEAP_HASNULL */ v_hasnulls = LLVMBuildICmp(b, LLVMIntNE, LLVMBuildAnd(b, l_int16_const(HEAP_HASNULL), v_infomask1, ""), l_int16_const(0), "hasnulls"); /* t_infomask2 & HEAP_NATTS_MASK */ v_maxatt = LLVMBuildAnd(b, l_int16_const(HEAP_NATTS_MASK), v_infomask2, "maxatt"); v_hoff = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_HOFF, "t_hoff"); v_tupdata_base = LLVMBuildGEP(b, LLVMBuildBitCast(b, v_tuplep, l_ptr(LLVMInt8Type()), ""), &v_hoff, 1, "v_tupdata_base"); /* * Load tuple start offset from slot. Will be reset below in case there's * no existing deformed columns in slot. */ { LLVMValueRef v_off_start; v_off_start = LLVMBuildLoad(b, v_slotoffp, "v_slot_off"); v_off_start = LLVMBuildZExt(b, v_off_start, TypeSizeT, ""); LLVMBuildStore(b, v_off_start, v_offp); } /* build the basic block for each attribute, need them as jump target */ for (attnum = 0; attnum < natts; attnum++) { attcheckattnoblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckattno", attnum); attstartblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.start", attnum); attisnullblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attisnull", attnum); attcheckalignblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckalign", attnum); attalignblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.align", attnum); attstoreblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.store", attnum); } /* * Check if's guaranteed the all the desired attributes are available in * tuple. If so, we can start deforming. If not, need to make sure to * fetch the missing columns. */ if ((natts - 1) <= guaranteed_column_number) { /* just skip through unnecessary blocks */ LLVMBuildBr(b, b_adjust_unavail_cols); LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols); LLVMBuildBr(b, b_find_start); } else { LLVMValueRef v_params[3]; /* branch if not all columns available */ LLVMBuildCondBr(b, LLVMBuildICmp(b, LLVMIntULT, v_maxatt, l_int16_const(natts), ""), b_adjust_unavail_cols, b_find_start); /* if not, memset tts_isnull of relevant cols to true */ LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols); v_params[0] = v_slot; v_params[1] = LLVMBuildZExt(b, v_maxatt, LLVMInt32Type(), ""); v_params[2] = l_int32_const(natts); LLVMBuildCall(b, llvm_get_decl(mod, FuncSlotGetmissingattrs), v_params, lengthof(v_params), ""); LLVMBuildBr(b, b_find_start); } LLVMPositionBuilderAtEnd(b, b_find_start); v_nvalid = LLVMBuildLoad(b, v_nvalidp, ""); /* * Build switch to go from nvalid to the right startblock. Callers * currently don't have the knowledge, but it'd be good for performance to * avoid this check when it's known that the slot is empty (e.g. in scan * nodes). */ if (true) { LLVMValueRef v_switch = LLVMBuildSwitch(b, v_nvalid, b_dead, natts); for (attnum = 0; attnum < natts; attnum++) { LLVMValueRef v_attno = l_int32_const(attnum); LLVMAddCase(v_switch, v_attno, attcheckattnoblocks[attnum]); } } else { /* jump from entry block to first block */ LLVMBuildBr(b, attcheckattnoblocks[0]); } LLVMPositionBuilderAtEnd(b, b_dead); LLVMBuildUnreachable(b); /* * Iterate over each attribute that needs to be deformed, build code to * deform it. */ for (attnum = 0; attnum < natts; attnum++) { Form_pg_attribute att = TupleDescAttr(desc, attnum); LLVMValueRef v_incby; int alignto; LLVMValueRef l_attno = l_int16_const(attnum); LLVMValueRef v_attdatap; LLVMValueRef v_resultp; /* build block checking whether we did all the necessary attributes */ LLVMPositionBuilderAtEnd(b, attcheckattnoblocks[attnum]); /* * If this is the first attribute, slot->tts_nvalid was 0. Therefore * reset offset to 0 to, it be from a previous execution. */ if (attnum == 0) { LLVMBuildStore(b, l_sizet_const(0), v_offp); } /* * Build check whether column is available (i.e. whether the tuple has * that many columns stored). We can avoid the branch if we know * there's a subsequent NOT NULL column. */ if (attnum <= guaranteed_column_number) { LLVMBuildBr(b, attstartblocks[attnum]); } else { LLVMValueRef v_islast; v_islast = LLVMBuildICmp(b, LLVMIntUGE, l_attno, v_maxatt, "heap_natts"); LLVMBuildCondBr(b, v_islast, b_out, attstartblocks[attnum]); } LLVMPositionBuilderAtEnd(b, attstartblocks[attnum]); /* * Check for nulls if necessary. No need to take missing attributes * into account, because in case they're present the heaptuple's natts * would have indicated that a slot_getmissingattrs() is needed. */ if (!att->attnotnull) { LLVMBasicBlockRef b_ifnotnull; LLVMBasicBlockRef b_ifnull; LLVMBasicBlockRef b_next; LLVMValueRef v_attisnull; LLVMValueRef v_nullbyteno; LLVMValueRef v_nullbytemask; LLVMValueRef v_nullbyte; LLVMValueRef v_nullbit; b_ifnotnull = attcheckalignblocks[attnum]; b_ifnull = attisnullblocks[attnum]; if (attnum + 1 == natts) b_next = b_out; else b_next = attcheckattnoblocks[attnum + 1]; v_nullbyteno = l_int32_const(attnum >> 3); v_nullbytemask = l_int8_const(1 << ((attnum) & 0x07)); v_nullbyte = l_load_gep1(b, v_bits, v_nullbyteno, "attnullbyte"); v_nullbit = LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildAnd(b, v_nullbyte, v_nullbytemask, ""), l_int8_const(0), "attisnull"); v_attisnull = LLVMBuildAnd(b, v_hasnulls, v_nullbit, ""); LLVMBuildCondBr(b, v_attisnull, b_ifnull, b_ifnotnull); LLVMPositionBuilderAtEnd(b, b_ifnull); /* store null-byte */ LLVMBuildStore(b, l_int8_const(1), LLVMBuildGEP(b, v_tts_nulls, &l_attno, 1, "")); /* store zero datum */ LLVMBuildStore(b, l_sizet_const(0), LLVMBuildGEP(b, v_tts_values, &l_attno, 1, "")); LLVMBuildBr(b, b_next); attguaranteedalign = false; } else {
static LLVMValueRef make_unbox_function(compile_t* c, reach_type_t* t, reach_method_t* m) { // Create a new unboxing function that forwards to the real function. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(m->func)); int count = LLVMCountParamTypes(f_type); // Leave space for a receiver if it's a constructor vtable entry. size_t buf_size = (count + 1) * sizeof(LLVMTypeRef); LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, params); LLVMTypeRef ret_type = LLVMGetReturnType(f_type); const char* unbox_name = genname_unbox(m->full_name); if(ast_id(m->r_fun) != TK_NEW) { // It's the same type, but it takes the boxed type instead of the primitive // type as the receiver. params[0] = t->structure_ptr; } else { // For a constructor, the unbox_fun has a receiver, even though the real // method does not. memmove(¶ms[1], ¶ms[0], count * sizeof(LLVMTypeRef*)); params[0] = t->structure_ptr; count++; } LLVMTypeRef unbox_type = LLVMFunctionType(ret_type, params, count, false); LLVMValueRef unbox_fun = codegen_addfun(c, unbox_name, unbox_type); codegen_startfun(c, unbox_fun, NULL, NULL); // 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*)ponyint_pool_alloc_size(buf_size); if(ast_id(m->r_fun) != TK_NEW) { // If it's not a constructor, pass the extracted primitive as the receiver. args[0] = primitive; for(int i = 1; i < count; i++) args[i] = LLVMGetParam(unbox_fun, i); } else { count--; for(int i = 0; i < count; i++) args[i] = LLVMGetParam(unbox_fun, i + 1); } LLVMValueRef result = codegen_call(c, m->func, args, count); LLVMBuildRet(c->builder, result); codegen_finishfun(c); ponyint_pool_free_size(buf_size, params); ponyint_pool_free_size(buf_size, args); return LLVMConstBitCast(unbox_fun, c->void_ptr); }
static LLVMValueRef desc_field(compile_t* c, LLVMValueRef desc, int index) { LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, desc, index, ""); return LLVMBuildLoad(c->builder, ptr, ""); }
void decode_packed_struct_inline( struct llvm_ctx *ctx, LLVMValueRef dst, IDL_tree ctyp, LLVMValueRef first_mr, LLVMValueRef bit_offset) { const struct packed_format *fmt = packed_format_of(ctyp); assert(fmt != NULL); char **names = NULL; T s_type = llvm_struct_type(ctx, &names, ctyp); int names_len = 0; while(names[names_len] != NULL) names_len++; assert(names_len == fmt->num_items); assert(LLVMCountStructElementTypes(s_type) == names_len); T types[MAX(names_len, 1)]; LLVMGetStructElementTypes(s_type, types); int cur_word = 0; V wordval = NULL; for(int i=0; i<fmt->num_items; i++) { const struct packed_item *pi = fmt->items[i]; int field_ix = strv_lookup(names, pi->name); if(field_ix < 0) { fprintf(stderr, "%s: not the way to go.\n", __func__); abort(); } V start_mr = LLVMBuildAdd(ctx->builder, first_mr, CONST_INT(pi->word), tmp_f(ctx->pr, "%s.start.mr", pi->name)); V dstptr = LLVMBuildStructGEP(ctx->builder, dst, field_ix, tmp_f(ctx->pr, "%s.start.ptr", pi->name)); if(pi->dim > 1) { /* array types. TODO */ fprintf(stderr, "%s: struct-member arrays not implemented\n", __func__); abort(); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) { decode_packed_struct(ctx, &dstptr, pi->type, start_mr, CONST_INT(pi->bit)); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) { fprintf(stderr, "%s: union-member types not implemented\n", __func__); abort(); } else if(IS_LONGLONG_TYPE(pi->type)) { /* long long on a 32-bit architecture. can be #ifdef'd out for * 64-bit targets, where it'd be just a value type. */ V dtmp = NULL; build_read_ipc_parameter(ctx, &dtmp, pi->type, start_mr); LLVMBuildStore(ctx->builder, dtmp, dstptr); } else if(is_value_type(pi->type)) { /* word-size and smaller items. */ if(cur_word != pi->word || wordval == NULL) { cur_word = pi->word; V old_wv = wordval; wordval = build_ipc_input_val_ix(ctx, start_mr, tmp_f(ctx->pr, "st.word%d", pi->word)); if(old_wv == NULL) { /* shift it down, since we start at an offset. */ wordval = LLVMBuildLShr(ctx->builder, wordval, bit_offset, "st.bitoffs.shifted"); } } V subval = LLVMBuildLShr(ctx->builder, wordval, CONST_INT(pi->bit), tmp_f(ctx->pr, "st.word%d.shr%d", pi->word, pi->bit)); if(pi->len < BITS_PER_WORD) { subval = LLVMBuildAnd(ctx->builder, subval, CONST_WORD((1 << pi->len) - 1), tmp_f(ctx->pr, "st.word%d.s%d.m%d", pi->word, pi->bit, pi->len)); } subval = LLVMBuildTruncOrBitCast(ctx->builder, subval, types[field_ix], "st.val.cast"); LLVMBuildStore(ctx->builder, subval, dstptr); } else if(IS_MAPGRANT_TYPE(pi->type)) { /* two words, like peas in a pod */ assert(pi->bit == 0); build_read_ipc_parameter(ctx, &dstptr, pi->type, start_mr); } else { NOTDEFINED(pi->type); } } g_strfreev(names); }
LLVMValueRef encode_packed_struct_inline( struct llvm_ctx *ctx, LLVMValueRef first_mr_word, LLVMValueRef bit_offset, IDL_tree ctyp, LLVMValueRef src_base) { const struct packed_format *fmt = packed_format_of(ctyp); assert(fmt != NULL); /* for sub-word items, bit_offset is required. for word and larger ones it * is forbidden. */ assert(bit_offset == NULL || (fmt->num_bits < BITS_PER_WORD && fmt->num_words == 1)); assert(bit_offset != NULL || fmt->num_bits >= BITS_PER_WORD); char **names = NULL; T s_type = llvm_struct_type(ctx, &names, ctyp); int names_len = 0; while(names[names_len] != NULL) names_len++; assert(names_len == fmt->num_items); assert(LLVMCountStructElementTypes(s_type) == names_len); T types[MAX(names_len, 1)]; LLVMGetStructElementTypes(s_type, types); V wordval = CONST_WORD(0); int cur_word = 0, wordval_fill = 0; for(int i=0; i<fmt->num_items; i++) { assert(wordval_fill <= BITS_PER_WORD); const struct packed_item *pi = fmt->items[i]; assert(bit_offset == NULL || pi->word == 0); int field_ix = strv_lookup(names, pi->name); if(field_ix < 0) { fprintf(stderr, "%s: not the way to go.\n", __func__); abort(); } V start_mr = NULL; if(bit_offset == NULL) { start_mr = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(pi->word), "word.ix"); } /* flush previous word? */ if(wordval_fill > 0 && cur_word != pi->word) { assert(bit_offset == NULL); V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word)); LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix, tmp_f(ctx->pr, "flush.w%d.addr", cur_word))); wordval = CONST_WORD(0); wordval_fill = 0; cur_word = pi->word; } V valptr = LLVMBuildStructGEP(ctx->builder, src_base, field_ix, tmp_f(ctx->pr, "%s.start.ptr", pi->name)); if(pi->dim > 1) { /* array types. TODO */ fprintf(stderr, "%s: struct-member arrays not implemented\n", __func__); abort(); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) { if(pi->len < BITS_PER_WORD) { wordval = encode_packed_struct(ctx, wordval, CONST_INT(pi->bit), pi->type, valptr); wordval_fill = (wordval_fill + pi->len) % BITS_PER_WORD; } else { encode_packed_struct(ctx, start_mr, NULL, pi->type, valptr); } } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) { fprintf(stderr, "%s: union-member types not implemented\n", __func__); abort(); } else if(IS_LONGLONG_TYPE(pi->type)) { assert(bit_offset == NULL); assert(pi->bit == 0 && wordval_fill == 0); V val = LLVMBuildLoad(ctx->builder, valptr, "longlong.fld"); build_write_ipc_parameter(ctx, start_mr, pi->type, &val); } else if(is_value_type(pi->type)) { /* word-size and smaller items. */ V val = LLVMBuildLoad(ctx->builder, valptr, tmp_f(ctx->pr, "fld.%s.val", pi->name)); val = LLVMBuildZExtOrBitCast(ctx->builder, val, ctx->wordt, tmp_f(ctx->pr, "fld.%s.word", pi->name)); V bitoffs = CONST_INT(pi->bit); V shifted = LLVMBuildShl(ctx->builder, val, bitoffs, tmp_f(ctx->pr, "fld.%s.shifted", pi->name)); wordval = LLVMBuildOr(ctx->builder, shifted, wordval, tmp_f(ctx->pr, "word%d.%s.merged", cur_word, pi->name)); wordval_fill += pi->len; } else if(IS_MAPGRANT_TYPE(pi->type)) { assert(bit_offset == NULL); assert(pi->bit == 0 && wordval_fill == 0); build_write_ipc_parameter(ctx, start_mr, pi->type, &valptr); } else { NOTDEFINED(pi->type); } } if(bit_offset == NULL && wordval_fill > 0) { /* flush final partial word if the last item was sub-word */ V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word)); LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix, tmp_f(ctx->pr, "flush.w%d.addr", cur_word))); wordval = NULL; } else if(bit_offset != NULL) { /* shift and merge */ wordval = LLVMBuildOr(ctx->builder, first_mr_word, LLVMBuildShl(ctx->builder, wordval, bit_offset, "short.shifted"), "rv.merged"); } g_strfreev(names); return wordval; }
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); }
static void serialise(compile_t* c, reach_type_t* t, LLVMValueRef ctx, LLVMValueRef object, LLVMValueRef offset) { LLVMTypeRef structure = t->structure; int extra = 0; switch(t->underlying) { case TK_PRIMITIVE: { genserialise_typeid(c, t, offset); if(t->primitive != NULL) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, 1, ""); LLVMValueRef f_size = LLVMConstInt(c->intptr, LLVMOffsetOfElement(c->target_data, structure, 1), false); LLVMValueRef f_offset = LLVMBuildInBoundsGEP(c->builder, offset, &f_size, 1, ""); genserialise_element(c, t, false, ctx, field, f_offset); } return; } case TK_CLASS: { genserialise_typeid(c, t, offset); extra++; break; } case TK_ACTOR: { // Skip the actor pad. genserialise_typeid(c, t, offset); extra += 2; break; } case TK_TUPLETYPE: { // Get the tuple primitive type. if(LLVMTypeOf(object) == t->structure_ptr) { genserialise_typeid(c, t, offset); object = LLVMBuildStructGEP(c->builder, object, 1, ""); LLVMValueRef size = LLVMConstInt(c->intptr, LLVMOffsetOfElement(c->target_data, structure, 1), false); offset = LLVMBuildInBoundsGEP(c->builder, offset, &size, 1, ""); } structure = t->primitive; break; } default: {} } for(uint32_t i = 0; i < t->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); LLVMValueRef f_size = LLVMConstInt(c->intptr, LLVMOffsetOfElement(c->target_data, structure, i + extra), false); LLVMValueRef f_offset = LLVMBuildInBoundsGEP(c->builder, offset, &f_size, 1, ""); genserialise_element(c, t->fields[i].type, t->fields[i].embed, ctx, field, f_offset); } }
void genprim_array_deserialise(compile_t* c, reach_type_t* t) { // Generate the deserisalise function. t->deserialise_fn = codegen_addfun(c, genname_serialise(t->name), c->trace_type); codegen_startfun(c, t->deserialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); gendeserialise_typeid(c, t, object); // Deserialise the array contents. LLVMValueRef alloc = field_value(c, object, 2); LLVMValueRef ptr_offset = field_value(c, object, 3); ptr_offset = LLVMBuildPtrToInt(c->builder, ptr_offset, c->intptr, ""); ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); size_t abisize = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, abisize, false); LLVMValueRef args[3]; args[0] = ctx; args[1] = ptr_offset; args[2] = LLVMBuildMul(c->builder, alloc, l_size, ""); LLVMValueRef ptr = gencall_runtime(c, "pony_deserialise_block", args, 3, ""); LLVMValueRef ptr_loc = LLVMBuildStructGEP(c->builder, object, 3, ""); LLVMBuildStore(c->builder, ptr, ptr_loc); if((t_elem->underlying == TK_PRIMITIVE) && (t_elem->primitive != NULL)) { // Do nothing. A memcpy is sufficient. } else { LLVMValueRef size = field_value(c, object, 1); ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, deserialise an element. The // initial index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and deserialise it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, ptr, &phi, 1, ""); gendeserialise_element(c, t_elem, false, ctx, elem_ptr); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
static LLVMTypeRef send_message(compile_t* c, ast_t* params, LLVMValueRef to, LLVMValueRef func, uint32_t index) { // Get the parameter types. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); int count = LLVMCountParamTypes(f_type) + 2; size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, &f_params[2]); // The first one becomes the message size, the second the message ID. f_params[0] = c->i32; f_params[1] = c->i32; f_params[2] = c->void_ptr; LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, count, false); LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0); ponyint_pool_free_size(buf_size, f_params); // Allocate the message, setting its size and ID. size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, msg_type); LLVMValueRef args[3]; 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, ""); for(int i = 3; i < count; i++) { LLVMValueRef arg = LLVMGetParam(func, i - 2); LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i, ""); LLVMBuildStore(c->builder, arg, arg_ptr); } // Trace while populating the message contents. LLVMValueRef ctx = codegen_ctx(c); ast_t* param = ast_child(params); bool need_trace = false; while(param != NULL) { if(gentrace_needed(ast_type(param))) { need_trace = true; break; } param = ast_sibling(param); } if(need_trace) { gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); param = ast_child(params); for(int i = 3; i < count; i++) { LLVMValueRef arg = LLVMGetParam(func, i - 2); gentrace(c, ctx, arg, ast_type(param)); param = ast_sibling(param); } gencall_runtime(c, "pony_send_done", &ctx, 1, ""); } // Send the message. args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, to, c->object_ptr, ""); args[2] = msg; gencall_runtime(c, "pony_sendv", args, 3, ""); // Return the type of the message. return msg_type_ptr; }
LLVMValueRef gendesc_fetch(compile_t* c, LLVMValueRef object) { LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, object, 0, ""); return LLVMBuildLoad(c->builder, ptr, ""); }
static LLVMValueRef field_value(compile_t* c, LLVMValueRef object, int index) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, index, ""); return LLVMBuildLoad(c->builder, field, ""); }
void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef orig_args[], LLVMValueRef cast_args[], ast_t* args_ast) { // Allocate the message, setting its size and ID. size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, m->msg_type); LLVMTypeRef msg_type_ptr = LLVMPointerType(m->msg_type, 0); LLVMValueRef msg_args[3]; msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false); msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false); LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, ""); LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); for(unsigned int i = 0; i < m->param_count; i++) { LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, ""); LLVMBuildStore(c->builder, cast_args[i+1], arg_ptr); } // Trace while populating the message contents. ast_t* params = ast_childidx(m->r_fun, 3); ast_t* param = ast_child(params); ast_t* arg_ast = ast_child(args_ast); bool need_trace = false; while(param != NULL) { if(gentrace_needed(c, ast_type(arg_ast), ast_type(param))) { need_trace = true; break; } param = ast_sibling(param); arg_ast = ast_sibling(arg_ast); } LLVMValueRef ctx = codegen_ctx(c); if(need_trace) { gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); param = ast_child(params); arg_ast = ast_child(args_ast); for(size_t i = 0; i < m->param_count; i++) { gentrace(c, ctx, orig_args[i+1], cast_args[i+1], ast_type(arg_ast), ast_type(param)); param = ast_sibling(param); arg_ast = ast_sibling(arg_ast); } gencall_runtime(c, "pony_send_done", &ctx, 1, ""); } // Send the message. msg_args[0] = ctx; msg_args[1] = LLVMBuildBitCast(c->builder, cast_args[0], c->object_ptr, ""); msg_args[2] = msg; gencall_runtime(c, "pony_sendv", msg_args, 3, ""); }