void gendesc_init(compile_t* c, reach_type_t* t) { if(t->desc_type == NULL) return; // Initialise the global descriptor. uint32_t event_notify_index = reach_vtable_index(t, c->str__event_notify); uint32_t size = (uint32_t)LLVMABISizeOfType(c->target_data, t->structure); uint32_t trait_count = 0; LLVMValueRef trait_list = make_trait_list(c, t, &trait_count); LLVMValueRef args[DESC_LENGTH]; args[DESC_ID] = LLVMConstInt(c->i32, t->type_id, false); args[DESC_SIZE] = LLVMConstInt(c->i32, size, false); args[DESC_TRAIT_COUNT] = LLVMConstInt(c->i32, trait_count, false); args[DESC_FIELD_COUNT] = make_field_count(c, t); args[DESC_FIELD_OFFSET] = make_field_offset(c, t); args[DESC_TRACE] = make_function_ptr(t->trace_fn, c->trace_fn); args[DESC_SERIALISE] = make_function_ptr(t->serialise_fn, c->trace_fn); args[DESC_DESERIALISE] = make_function_ptr(t->deserialise_fn, c->trace_fn); args[DESC_DISPATCH] = make_function_ptr(t->dispatch_fn, c->dispatch_fn); args[DESC_FINALISE] = make_function_ptr(t->final_fn, c->final_fn); args[DESC_EVENT_NOTIFY] = LLVMConstInt(c->i32, event_notify_index, false); args[DESC_TRAITS] = trait_list; args[DESC_FIELDS] = make_field_list(c, t); args[DESC_VTABLE] = make_vtable(c, t); LLVMValueRef desc = LLVMConstNamedStruct(t->desc_type, args, DESC_LENGTH); LLVMSetInitializer(t->desc, desc); LLVMSetGlobalConstant(t->desc, true); }
static void pointer_offset(compile_t* c, reach_type_t* t, reach_type_t* t_elem) { FIND_METHOD("_offset"); LLVMTypeRef params[3]; params[0] = t->use_type; params[1] = c->intptr; start_function(c, m, t->use_type, params, 2); // Set up a constant integer for the allocation size. size_t size = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, size, false); LLVMValueRef ptr = LLVMGetParam(m->func, 0); LLVMValueRef n = LLVMGetParam(m->func, 1); // Return ptr + (n * sizeof(len)). LLVMValueRef src = LLVMBuildPtrToInt(c->builder, ptr, c->intptr, ""); LLVMValueRef offset = LLVMBuildMul(c->builder, n, l_size, ""); LLVMValueRef result = LLVMBuildAdd(c->builder, src, offset, ""); result = LLVMBuildIntToPtr(c->builder, result, t->use_type, ""); LLVMBuildRet(c->builder, result); codegen_finishfun(c); BOX_FUNCTION(); }
static void pointer_alloc(compile_t* c, reach_type_t* t, reach_type_t* t_elem) { FIND_METHOD("_alloc"); LLVMTypeRef params[2]; params[0] = t->use_type; params[1] = c->intptr; start_function(c, m, t->use_type, params, 2); // Set up a constant integer for the allocation size. size_t size = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, size, false); LLVMValueRef len = LLVMGetParam(m->func, 1); LLVMValueRef args[2]; args[0] = codegen_ctx(c); args[1] = LLVMBuildMul(c->builder, len, l_size, ""); LLVMValueRef result = gencall_runtime(c, "pony_alloc", args, 2, ""); result = LLVMBuildBitCast(c->builder, result, t->use_type, ""); LLVMBuildRet(c->builder, result); codegen_finishfun(c); }
LLVMValueRef codegen_addfun(compile_t* c, const char* name, LLVMTypeRef type) { // Add the function and set the calling convention. LLVMValueRef fun = LLVMAddFunction(c->module, name, type); LLVMSetFunctionCallConv(fun, c->callconv); LLVMValueRef arg = LLVMGetFirstParam(fun); uint32_t i = 1; while(arg != NULL) { LLVMTypeRef type = LLVMTypeOf(arg); if(LLVMGetTypeKind(type) == LLVMPointerTypeKind) { LLVMTypeRef elem = LLVMGetElementType(type); if(LLVMGetTypeKind(elem) == LLVMStructTypeKind) { size_t size = (size_t)LLVMABISizeOfType(c->target_data, elem); LLVMSetDereferenceable(fun, i, size); } } arg = LLVMGetNextParam(arg); i++; } return fun; }
LLVMValueRef gen_numeric_size_table(compile_t* c) { uint32_t len = c->reach->numeric_type_count; if(len == 0) return NULL; size_t size = len * sizeof(LLVMValueRef); LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(size); uint32_t count = 0; reach_type_t* t; size_t i = HASHMAP_BEGIN; while(count < len) { t = reach_types_next(&c->reach->types, &i); pony_assert(t != NULL); if(t->is_trait || (t->underlying == TK_STRUCT)) continue; uint32_t type_id = t->type_id; if((type_id % 4) == 0) { size_t type_size = (size_t)LLVMABISizeOfType(c->target_data, t->use_type); args[type_id >> 2] = LLVMConstInt(c->i32, type_size, false); count++; } }
void gendesc_init(compile_t* c, gentype_t* g) { // Initialise the global descriptor. uint32_t size = (uint32_t)LLVMABISizeOfType(c->target_data, g->structure); // Generate a separate type ID for every type. LLVMValueRef args[DESC_LENGTH]; args[DESC_ID] = make_type_id(c, g->type_name); args[DESC_SIZE] = LLVMConstInt(c->i32, size, false); args[DESC_TRAIT_COUNT] = make_trait_count(c, g); args[DESC_FIELD_COUNT] = make_field_count(c, g); args[DESC_TRACE] = make_function_ptr(c, genname_trace(g->type_name), c->trace_fn); args[DESC_SERIALISE] = make_function_ptr(c, genname_serialise(g->type_name), c->trace_fn); args[DESC_DESERIALISE] = make_function_ptr(c, genname_deserialise(g->type_name), c->trace_fn); args[DESC_DISPATCH] = make_function_ptr(c, genname_dispatch(g->type_name), c->dispatch_fn); args[DESC_FINALISE] = make_function_ptr(c, genname_finalise(g->type_name), c->final_fn); args[DESC_EVENT_NOTIFY] = LLVMConstInt(c->i32, genfun_vtable_index(c, g, stringtab("_event_notify"), NULL), false); args[DESC_TRAITS] = make_trait_list(c, g); args[DESC_FIELDS] = make_field_list(c, g); args[DESC_VTABLE] = make_vtable(c, g); LLVMValueRef desc = LLVMConstNamedStruct(g->desc_type, args, DESC_LENGTH); LLVMSetInitializer(g->desc, desc); LLVMSetGlobalConstant(g->desc, true); }
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; }
static LLVMValueRef cast_ffi_arg(compile_t* c, ffi_decl_t* decl, ast_t* ast, LLVMValueRef arg, LLVMTypeRef param, const char* name) { if(arg == NULL) return NULL; LLVMTypeRef arg_type = LLVMTypeOf(arg); if(param == arg_type) return arg; if((LLVMABISizeOfType(c->target_data, param) != LLVMABISizeOfType(c->target_data, arg_type))) { report_ffi_type_err(c, decl, ast, name); return NULL; } switch(LLVMGetTypeKind(param)) { case LLVMPointerTypeKind: if(LLVMGetTypeKind(arg_type) == LLVMIntegerTypeKind) return LLVMBuildIntToPtr(c->builder, arg, param, ""); else return LLVMBuildBitCast(c->builder, arg, param, ""); case LLVMIntegerTypeKind: if(LLVMGetTypeKind(arg_type) == LLVMPointerTypeKind) return LLVMBuildPtrToInt(c->builder, arg, param, ""); break; case LLVMStructTypeKind: pony_assert(LLVMGetTypeKind(arg_type) == LLVMStructTypeKind); return arg; default: {} } pony_assert(false); return NULL; }
void gencall_lifetime_end(compile_t* c, LLVMValueRef ptr) { LLVMValueRef func = LLVMLifetimeEnd(c->module); LLVMTypeRef type = LLVMGetElementType(LLVMTypeOf(ptr)); size_t size = (size_t)LLVMABISizeOfType(c->target_data, type); LLVMValueRef args[2]; args[0] = LLVMConstInt(c->i64, size, false); args[1] = LLVMBuildBitCast(c->builder, ptr, c->void_ptr, ""); LLVMBuildCall(c->builder, func, args, 2, ""); }
static LLVMMetadataRef make_debug_field(compile_t* c, reach_type_t* t, uint32_t i) { const char* name; char buf[32]; unsigned flags = 0; uint64_t offset = 0; ast_t* ast; if(t->underlying != TK_TUPLETYPE) { ast_t* def = (ast_t*)ast_data(t->ast); ast_t* members = ast_childidx(def, 4); ast = ast_childidx(members, i); name = ast_name(ast_child(ast)); if(is_name_private(name)) flags |= DW_FLAG_Private; uint32_t extra = 0; if(t->underlying != TK_STRUCT) extra++; if(t->underlying == TK_ACTOR) extra++; offset = LLVMOffsetOfElement(c->target_data, t->structure, i + extra); } else { snprintf(buf, 32, "_%d", i + 1); name = buf; ast = t->ast; offset = LLVMOffsetOfElement(c->target_data, t->primitive, i); } LLVMTypeRef type; LLVMMetadataRef di_type; if(t->fields[i].embed) { type = t->fields[i].type->structure; di_type = t->fields[i].type->di_type_embed; } else { type = t->fields[i].type->use_type; di_type = t->fields[i].type->di_type; } uint64_t size = LLVMABISizeOfType(c->target_data, type); uint64_t align = LLVMABIAlignmentOfType(c->target_data, type); return LLVMDIBuilderCreateMemberType(c->di, c->di_unit, name, t->di_file, (unsigned)ast_line(ast), 8 * size, 8 * align, 8 * offset, flags, di_type); }
static void setup_dwarf(dwarf_t* dwarf, dwarf_meta_t* meta, gentype_t* g, bool opaque, bool field) { memset(meta, 0, sizeof(dwarf_meta_t)); ast_t* ast = g->ast; LLVMTypeRef type = g->primitive; if(is_machine_word(ast)) { if(is_float(ast)) meta->flags |= DWARF_FLOAT; else if(is_signed(dwarf->opt, ast)) meta->flags |= DWARF_SIGNED; else if(is_bool(ast)) meta->flags |= DWARF_BOOLEAN; } else if(is_pointer(ast) || is_maybe(ast) || !is_concrete(ast) || (is_constructable(ast) && field)) { type = g->use_type; } else if(is_constructable(ast)) { type = g->structure; } bool defined_type = g->underlying != TK_TUPLETYPE && g->underlying != TK_UNIONTYPE && g->underlying != TK_ISECTTYPE; source_t* source; if(defined_type) ast = (ast_t*)ast_data(ast); source = ast_source(ast); meta->file = source->file; meta->name = g->type_name; meta->line = ast_line(ast); meta->pos = ast_pos(ast); if(!opaque) { meta->size = LLVMABISizeOfType(dwarf->target_data, type) << 3; meta->align = LLVMABIAlignmentOfType(dwarf->target_data, type) << 3; } }
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 void pointer_delete(compile_t* c, reach_type_t* t, reach_type_t* t_elem) { FIND_METHOD("_delete"); LLVMTypeRef params[3]; params[0] = t->use_type; params[1] = c->intptr; params[2] = c->intptr; start_function(c, m, t_elem->use_type, params, 3); // Set up a constant integer for the allocation size. size_t size = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, size, false); LLVMValueRef ptr = LLVMGetParam(m->func, 0); LLVMValueRef n = LLVMGetParam(m->func, 1); LLVMValueRef len = LLVMGetParam(m->func, 2); LLVMValueRef elem_ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMValueRef result = LLVMBuildLoad(c->builder, elem_ptr, ""); LLVMValueRef dst = LLVMBuildPtrToInt(c->builder, elem_ptr, c->intptr, ""); LLVMValueRef offset = LLVMBuildMul(c->builder, n, l_size, ""); LLVMValueRef src = LLVMBuildAdd(c->builder, dst, offset, ""); LLVMValueRef elen = LLVMBuildMul(c->builder, len, l_size, ""); LLVMValueRef args[5]; args[0] = LLVMBuildIntToPtr(c->builder, dst, c->void_ptr, ""); args[1] = LLVMBuildIntToPtr(c->builder, src, c->void_ptr, ""); args[2] = elen; args[3] = LLVMConstInt(c->i32, 1, false); args[4] = LLVMConstInt(c->i1, 0, false); // llvm.memmove.*(ptr, ptr + (n * sizeof(elem)), len * sizeof(elem)) if(target_is_ilp32(c->opt->triple)) { gencall_runtime(c, "llvm.memmove.p0i8.p0i8.i32", args, 5, ""); } else { gencall_runtime(c, "llvm.memmove.p0i8.p0i8.i64", args, 5, ""); } // Return ptr[0]. LLVMBuildRet(c->builder, result); codegen_finishfun(c); }
static void make_debug_fields(compile_t* c, reach_type_t* t) { LLVMMetadataRef fields = NULL; if(t->field_count > 0) { size_t buf_size = t->field_count * sizeof(LLVMMetadataRef); LLVMMetadataRef* data = (LLVMMetadataRef*)ponyint_pool_alloc_size( buf_size); for(uint32_t i = 0; i < t->field_count; i++) data[i] = make_debug_field(c, t, i); fields = LLVMDIBuilderGetOrCreateArray(c->di, data, t->field_count); ponyint_pool_free_size(buf_size, data); } LLVMTypeRef type; if(t->underlying != TK_TUPLETYPE) type = t->structure; else type = t->primitive; uint64_t size = 0; uint64_t align = 0; if(type != NULL) { size = LLVMABISizeOfType(c->target_data, type); align = LLVMABIAlignmentOfType(c->target_data, type); } LLVMMetadataRef di_type = LLVMDIBuilderCreateStructType(c->di, c->di_unit, t->name, t->di_file, (unsigned) ast_line(t->ast), 8 * size, 8 * align, fields); if(t->underlying != TK_TUPLETYPE) { LLVMMetadataReplaceAllUsesWith(t->di_type_embed, di_type); t->di_type_embed = di_type; } else { LLVMMetadataReplaceAllUsesWith(t->di_type, di_type); t->di_type = di_type; } }
LLVMValueRef codegen_addfun(compile_t* c, const char* name, LLVMTypeRef type, bool pony_abi) { // Add the function and set the calling convention and the linkage type. LLVMValueRef fun = LLVMAddFunction(c->module, name, type); LLVMSetFunctionCallConv(fun, c->callconv); LLVMSetLinkage(fun, c->linkage); LLVMSetUnnamedAddr(fun, true); if(pony_abi) { LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); LLVMSetMetadataStr(fun, "pony.abi", md); } LLVMValueRef arg = LLVMGetFirstParam(fun); uint32_t i = 1; while(arg != NULL) { LLVMTypeRef type = LLVMTypeOf(arg); if(LLVMGetTypeKind(type) == LLVMPointerTypeKind) { LLVMTypeRef elem = LLVMGetElementType(type); if(LLVMGetTypeKind(elem) == LLVMStructTypeKind) { size_t size = (size_t)LLVMABISizeOfType(c->target_data, elem); #if PONY_LLVM >= 309 LLVM_DECLARE_ATTRIBUTEREF(deref_attr, dereferenceable, size); LLVMAddAttributeAtIndex(fun, i, deref_attr); #else LLVMSetDereferenceable(fun, i, size); #endif } } arg = LLVMGetNextParam(arg); i++; } return fun; }
static void make_debug_basic(compile_t* c, reach_type_t* t) { uint64_t size = LLVMABISizeOfType(c->target_data, t->primitive); uint64_t align = LLVMABIAlignmentOfType(c->target_data, t->primitive); unsigned encoding; if(is_bool(t->ast)) { encoding = DW_ATE_boolean; } else if(is_float(t->ast)) { encoding = DW_ATE_float; } else if(is_signed(t->ast)) { encoding = DW_ATE_signed; } else { encoding = DW_ATE_unsigned; } t->di_type = LLVMDIBuilderCreateBasicType(c->di, t->name, 8 * size, 8 * align, encoding); }
static void pointer_copy_to(compile_t* c, reach_type_t* t, reach_type_t* t_elem) { FIND_METHOD("_copy_to"); LLVMTypeRef params[3]; params[0] = t->use_type; params[1] = t->use_type; params[2] = c->intptr; start_function(c, m, t->use_type, params, 3); // Set up a constant integer for the allocation size. size_t size = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, size, false); LLVMValueRef ptr = LLVMGetParam(m->func, 0); LLVMValueRef ptr2 = LLVMGetParam(m->func, 1); LLVMValueRef n = LLVMGetParam(m->func, 2); LLVMValueRef elen = LLVMBuildMul(c->builder, n, l_size, ""); LLVMValueRef args[5]; args[0] = LLVMBuildBitCast(c->builder, ptr2, c->void_ptr, ""); args[1] = LLVMBuildBitCast(c->builder, ptr, c->void_ptr, ""); args[2] = elen; args[3] = LLVMConstInt(c->i32, 1, false); args[4] = LLVMConstInt(c->i1, 0, false); // llvm.memcpy.*(ptr2, ptr, n * sizeof(elem), 1, 0) if(target_is_ilp32(c->opt->triple)) { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i32", args, 5, ""); } else { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i64", args, 5, ""); } LLVMBuildRet(c->builder, ptr); codegen_finishfun(c); BOX_FUNCTION(); }
void genprim_array_serialise_trace(compile_t* c, reach_type_t* t) { // Generate the serialise_trace function. t->serialise_trace_fn = codegen_addfun(c, genname_serialise_trace(t->name), c->trace_type); codegen_startfun(c, t->serialise_trace_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_trace_fn, LLVMCCallConv); LLVMSetLinkage(t->serialise_trace_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->serialise_trace_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->use_type, ""); // Read the size. LLVMValueRef size = field_value(c, object, 1); // Calculate the size of the element type. 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); // Reserve space for the array elements. LLVMValueRef pointer = field_value(c, object, 3); LLVMValueRef args[3]; args[0] = ctx; args[1] = pointer; args[2] = LLVMBuildMul(c->builder, size, l_size, ""); gencall_runtime(c, "pony_serialise_reserve", args, 3, ""); // Trace the array elements. trace_array_elements(c, t, ctx, object, pointer); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
LLVMValueRef codegen_addfun(compile_t* c, const char* name, LLVMTypeRef type) { // Add the function and set the calling convention. LLVMValueRef fun = LLVMAddFunction(c->module, name, type); if(!c->opt->library) LLVMSetFunctionCallConv(fun, GEN_CALLCONV); LLVMValueRef arg = LLVMGetFirstParam(fun); uint32_t i = 1; while(arg != NULL) { LLVMTypeRef type = LLVMTypeOf(arg); if(LLVMGetTypeKind(type) == LLVMPointerTypeKind) { LLVMTypeRef elem = LLVMGetElementType(type); if(LLVMGetTypeKind(elem) == LLVMStructTypeKind) { uint64_t size = LLVMABISizeOfType(c->target_data, elem); LLVMSetDereferenceable(fun, i, size); } // Set the noalias attribute on all arguments. This is fortran-like // semantics for parameter aliasing, similar to C restrict. if(!c->opt->no_restrict) LLVMAddAttribute(arg, LLVMNoAliasAttribute); } arg = LLVMGetNextParam(arg); i++; } return fun; }
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 make_struct(compile_t* c, reach_type_t* t) { LLVMTypeRef type; int extra = 0; switch(t->underlying) { case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_INTERFACE: case TK_TRAIT: return true; case TK_TUPLETYPE: type = t->primitive; break; case TK_STRUCT: // Pointer and Maybe will have no structure. if(t->structure == NULL) return true; type = t->structure; break; case TK_PRIMITIVE: // Machine words will have a primitive. if(t->primitive != NULL) { // The ABI size for machine words and tuples is the boxed size. t->abi_size = (size_t)LLVMABISizeOfType(c->target_data, t->structure); return true; } extra = 1; type = t->structure; break; case TK_CLASS: extra = 1; type = t->structure; break; case TK_ACTOR: extra = 2; type = t->structure; break; default: assert(0); return false; } size_t buf_size = (t->field_count + extra) * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); // Create the type descriptor as element 0. if(extra > 0) elements[0] = LLVMPointerType(t->desc_type, 0); // Create the actor pad as element 1. if(extra > 1) elements[1] = c->actor_pad; for(uint32_t i = 0; i < t->field_count; i++) { if(t->fields[i].embed) elements[i + extra] = t->fields[i].type->structure; else elements[i + extra] = t->fields[i].type->use_type; if(elements[i + extra] == NULL) { assert(0); return false; } } LLVMStructSetBody(type, elements, t->field_count + extra, false); ponyint_pool_free_size(buf_size, elements); return true; }
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); }
/* TargetData.t -> Llvm.lltype -> Int64.t */ CAMLprim value llvm_abi_size(LLVMTargetDataRef TD, LLVMTypeRef Ty) { return caml_copy_int64(LLVMABISizeOfType(TD, Ty)); }
/* Llvm.lltype -> DataLayout.t -> Int64.t */ CAMLprim value llvm_datalayout_abi_size(LLVMTypeRef Ty, value DL) { return caml_copy_int64(LLVMABISizeOfType(DataLayout_val(DL), Ty)); }
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, ""); }
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 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); }
bool gentypes(compile_t* c) { reach_type_t* t; size_t i; genprim_builtins(c); if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Data prototypes\n"); i = HASHMAP_BEGIN; while((t = reach_types_next(&c->reach->types, &i)) != NULL) { if(!make_opaque_struct(c, t)) return false; gendesc_type(c, t); make_debug_info(c, t); make_box_type(c, t); make_dispatch(c, t); gentrace_prototype(c, t); } gendesc_table(c); if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Data types\n"); i = HASHMAP_BEGIN; while((t = reach_types_next(&c->reach->types, &i)) != NULL) { if(!make_struct(c, t)) return false; make_global_instance(c, t); } if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Function prototypes\n"); i = HASHMAP_BEGIN; while((t = reach_types_next(&c->reach->types, &i)) != NULL) { // The ABI size for machine words and tuples is the boxed size. if(t->structure != NULL) t->abi_size = (size_t)LLVMABISizeOfType(c->target_data, t->structure); make_debug_final(c, t); make_pointer_methods(c, t); if(!genfun_method_sigs(c, t)) return false; } if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Functions\n"); i = HASHMAP_BEGIN; while((t = reach_types_next(&c->reach->types, &i)) != NULL) { if(!genfun_method_bodies(c, t)) return false; } if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Descriptors\n"); i = HASHMAP_BEGIN; while((t = reach_types_next(&c->reach->types, &i)) != NULL) { if(!make_trace(c, t)) return false; if(!genserialise(c, t)) return false; gendesc_init(c, t); } return true; }
void genprim_array_serialise(compile_t* c, reach_type_t* t) { // Generate the serialise function. t->serialise_fn = codegen_addfun(c, genname_serialise(t->name), c->serialise_type); codegen_startfun(c, t->serialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->serialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_fn, 1); LLVMValueRef addr = LLVMGetParam(t->serialise_fn, 2); LLVMValueRef offset = LLVMGetParam(t->serialise_fn, 3); LLVMValueRef mut = LLVMGetParam(t->serialise_fn, 4); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); LLVMValueRef offset_addr = LLVMBuildAdd(c->builder, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), offset, ""); genserialise_typeid(c, t, offset_addr); // Don't serialise our contents if we are opaque. LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntNE, mut, LLVMConstInt(c->i32, PONY_TRACE_OPAQUE, false), ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); LLVMPositionBuilderAtEnd(c->builder, body_block); // Write the size twice, effectively rewriting alloc to be the same as size. LLVMValueRef size = field_value(c, object, 1); LLVMValueRef size_loc = field_loc(c, offset_addr, t->structure, c->intptr, 1); LLVMBuildStore(c->builder, size, size_loc); LLVMValueRef alloc_loc = field_loc(c, offset_addr, t->structure, c->intptr, 2); LLVMBuildStore(c->builder, size, alloc_loc); // Write the pointer. LLVMValueRef ptr = field_value(c, object, 3); // The resulting offset will only be invalid (i.e. have the high bit set) if // the size is zero. For an opaque array, we don't serialise the contents, // so we don't get here, so we don't end up with an invalid offset. LLVMValueRef args[5]; args[0] = ctx; args[1] = ptr; LLVMValueRef ptr_offset = gencall_runtime(c, "pony_serialise_offset", args, 2, ""); LLVMValueRef ptr_loc = field_loc(c, offset_addr, t->structure, c->intptr, 3); LLVMBuildStore(c->builder, ptr_offset, ptr_loc); LLVMValueRef ptr_offset_addr = LLVMBuildAdd(c->builder, ptr_offset, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), ""); // Serialise elements. 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); if((t_elem->underlying == TK_PRIMITIVE) && (t_elem->primitive != NULL)) { // memcpy machine words args[0] = LLVMBuildIntToPtr(c->builder, ptr_offset_addr, c->void_ptr, ""); args[1] = LLVMBuildBitCast(c->builder, ptr, c->void_ptr, ""); args[2] = LLVMBuildMul(c->builder, size, l_size, ""); args[3] = LLVMConstInt(c->i32, 1, false); args[4] = LLVMConstInt(c->i1, 0, false); if(target_is_ilp32(c->opt->triple)) { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i32", args, 5, ""); } else { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i64", args, 5, ""); } } else { 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"); LLVMValueRef offset_var = LLVMBuildAlloca(c->builder, c->intptr, ""); LLVMBuildStore(c->builder, ptr_offset_addr, offset_var); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, serialise 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 serialise it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, ptr, &phi, 1, ""); ptr_offset_addr = LLVMBuildLoad(c->builder, offset_var, ""); genserialise_element(c, t_elem, false, ctx, elem_ptr, ptr_offset_addr); ptr_offset_addr = LLVMBuildAdd(c->builder, ptr_offset_addr, l_size, ""); LLVMBuildStore(c->builder, ptr_offset_addr, offset_var); // 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); } LLVMBuildBr(c->builder, post_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; }