static reachable_type_t* add_tuple(reachable_method_stack_t** s, reachable_types_t* r, uint32_t* next_type_id, ast_t* type) { if(contains_dontcare(type)) return NULL; reachable_type_t* t = reach_type(r, type); if(t != NULL) return t; t = add_reachable_type(r, type); t->type_id = ++(*next_type_id); t->field_count = (uint32_t)ast_childcount(t->ast); t->fields = (reachable_field_t*)calloc(t->field_count, sizeof(reachable_field_t)); size_t index = 0; ast_t* child = ast_child(type); while(child != NULL) { t->fields[index].ast = ast_dup(child); t->fields[index].type = add_type(s, r, next_type_id, child);; index++; child = ast_sibling(child); } return t; }
LLVMValueRef gen_string(compile_t* c, ast_t* ast) { ast_t* type = ast_type(ast); const char* name = ast_name(ast); size_t len = ast_name_len(ast); LLVMValueRef args[4]; args[0] = LLVMConstInt(c->i32, 0, false); args[1] = LLVMConstInt(c->i32, 0, false); LLVMValueRef str = LLVMConstStringInContext(c->context, name, (int)len, false); LLVMValueRef g_str = LLVMAddGlobal(c->module, LLVMTypeOf(str), ""); LLVMSetLinkage(g_str, LLVMPrivateLinkage); LLVMSetInitializer(g_str, str); LLVMSetGlobalConstant(g_str, true); LLVMValueRef str_ptr = LLVMConstInBoundsGEP(g_str, args, 2); reach_type_t* t = reach_type(c->reach, type); args[0] = t->desc; args[1] = LLVMConstInt(c->intptr, len, false); args[2] = LLVMConstInt(c->intptr, len + 1, false); args[3] = str_ptr; LLVMValueRef inst = LLVMConstNamedStruct(t->structure, args, 4); LLVMValueRef g_inst = LLVMAddGlobal(c->module, t->structure, ""); LLVMSetInitializer(g_inst, inst); LLVMSetGlobalConstant(g_inst, true); LLVMSetLinkage(g_inst, LLVMPrivateLinkage); return g_inst; }
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]; reachable_type_t* t = reach_type(c->reachable, g->type_name); args[DESC_ID] = LLVMConstInt(c->i32, t->type_id, false); 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); }
LLVMValueRef gen_float(compile_t* c, ast_t* ast) { ast_t* type = ast_type(ast); reach_type_t* t = reach_type(c->reach, type); return LLVMConstReal(t->primitive, ast_float(ast)); }
static reachable_type_t* add_tuple(reachable_method_stack_t** s, reachable_types_t* r, uint32_t* next_type_id, ast_t* type) { if(contains_dontcare(type)) return NULL; const char* type_name = genname_type(type); reachable_type_t* t = reach_type(r, type_name); if(t != NULL) return t; t = add_reachable_type(r, type, type_name); t->type_id = ++(*next_type_id); ast_t* child = ast_child(type); while(child != NULL) { add_type(s, r, next_type_id, child); child = ast_sibling(child); } return t; }
static void donotoptimise_apply(compile_t* c, reach_type_t* t, reach_method_t* m) { const char* strtab_name = m->name; m->intrinsic = true; ast_t* typearg = ast_child(m->typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); LLVMTypeRef params[2]; params[0] = t->use_type; params[1] = t_elem->use_type; start_function(c, m, m->result->use_type, params, 2); LLVMValueRef obj = LLVMGetParam(m->func, 1); LLVMTypeRef void_fn = LLVMFunctionType(c->void_type, &t_elem->use_type, 1, false); LLVMValueRef asmstr = LLVMConstInlineAsm(void_fn, "", "imr,~{memory}", true, false); LLVMBuildCall(c->builder, asmstr, &obj, 1, ""); LLVMBuildRet(c->builder, m->result->instance); codegen_finishfun(c); BOX_FUNCTION(); }
static LLVMValueRef make_vtable(compile_t* c, gentype_t* g) { uint32_t vtable_size = genfun_vtable_size(c, g); if(vtable_size == 0) return LLVMConstArray(c->void_ptr, NULL, 0); size_t buf_size = vtable_size * sizeof(LLVMValueRef); LLVMValueRef* vtable = (LLVMValueRef*)pool_alloc_size(buf_size); memset(vtable, 0, buf_size); reachable_type_t* t = reach_type(c->reachable, g->type_name); size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) { const char* fullname = genname_fun(t->name, n->name, m->typeargs); token_id t = ast_id(m->r_fun); switch(t) { case TK_NEW: case TK_BE: if(g->underlying == TK_ACTOR) fullname = genname_be(fullname); break; default: {} } uint32_t index = m->vtable_index; assert(index != (uint32_t)-1); assert(vtable[index] == NULL); if(g->primitive != NULL) vtable[index] = make_unbox_function(c, g, fullname, t); else vtable[index] = make_function_ptr(c, fullname, c->void_ptr); } } for(uint32_t i = 0; i < vtable_size; i++) { if(vtable[i] == NULL) vtable[i] = LLVMConstNull(c->void_ptr); } LLVMValueRef r = LLVMConstArray(c->void_ptr, vtable, vtable_size); pool_free_size(buf_size, vtable); return r; }
static reachable_type_t* add_nominal(reachable_method_stack_t** s, reachable_types_t* r, uint32_t* next_type_id, ast_t* type) { const char* type_name = genname_type(type); reachable_type_t* t = reach_type(r, type_name); if(t != NULL) return t; t = add_reachable_type(r, type, type_name); AST_GET_CHILDREN(type, pkg, id, typeparams); ast_t* typeparam = ast_child(typeparams); while(typeparam != NULL) { add_type(s, r, next_type_id, typeparam); typeparam = ast_sibling(typeparam); } ast_t* def = (ast_t*)ast_data(type); switch(ast_id(def)) { case TK_INTERFACE: case TK_TRAIT: add_types_to_trait(s, r, t); break; case TK_PRIMITIVE: add_traits_to_type(s, r, t); add_special(s, t, type, "_init"); add_special(s, t, type, "_final"); break; case TK_STRUCT: case TK_CLASS: add_traits_to_type(s, r, t); add_special(s, t, type, "_final"); add_fields(s, r, next_type_id, type); break; case TK_ACTOR: add_traits_to_type(s, r, t); add_special(s, t, type, "_event_notify"); add_special(s, t, type, "_final"); add_fields(s, r, next_type_id, type); break; default: {} } if(t->type_id == 0) t->type_id = ++(*next_type_id); return t; }
LLVMValueRef gen_funptr(compile_t* c, ast_t* ast) { pony_assert((ast_id(ast) == TK_FUNREF) || (ast_id(ast) == TK_BEREF)); AST_GET_CHILDREN(ast, receiver, method); ast_t* typeargs = NULL; // Dig through function qualification. switch(ast_id(receiver)) { case TK_BEREF: case TK_FUNREF: typeargs = method; AST_GET_CHILDREN_NO_DECL(receiver, receiver, method); break; default: {} } // Generate the receiver. LLVMValueRef value = gen_expr(c, receiver); // Get the receiver type. ast_t* type = ast_type(receiver); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); const char* name = ast_name(method); token_id cap = cap_dispatch(type); reach_method_t* m = reach_method(t, cap, name, typeargs); LLVMValueRef funptr = dispatch_function(c, t, m, value); if(c->linkage != LLVMExternalLinkage) { // We must reset the function linkage and calling convention since we're // passing a function pointer to a FFI call. switch(t->underlying) { case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: case TK_ACTOR: set_method_external_nominal(t, name); break; case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_INTERFACE: case TK_TRAIT: set_method_external_interface(t, name); break; default: pony_assert(0); break; } } return funptr; }
uint32_t genfun_vtable_size(compile_t* c, gentype_t* g) { reachable_type_t* t = reach_type(c->reachable, g->type_name); if(t == NULL) return 0; return t->vtable_size; }
LLVMValueRef gen_tuple(compile_t* c, ast_t* ast) { ast_t* child = ast_child(ast); if(ast_sibling(child) == NULL) return gen_expr(c, child); deferred_reification_t* reify = c->frame->reify; ast_t* type = deferred_reify(reify, ast_type(ast), c->opt); // If we contain '_', we have no usable value. if(contains_dontcare(type)) { ast_free_unattached(type); return GEN_NOTNEEDED; } reach_type_t* t = reach_type(c->reach, type); compile_type_t* c_t = (compile_type_t*)t->c_type; int count = LLVMCountStructElementTypes(c_t->primitive); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetStructElementTypes(c_t->primitive, elements); LLVMValueRef tuple = LLVMGetUndef(c_t->primitive); int i = 0; while(child != NULL) { LLVMValueRef value = gen_expr(c, child); if(value == NULL) { ponyint_pool_free_size(buf_size, elements); return NULL; } // We'll have an undefined element if one of our source elements is a // variable declaration. This is ok, since the tuple value will never be // used. if(value == GEN_NOVALUE || value == GEN_NOTNEEDED) { ponyint_pool_free_size(buf_size, elements); return value; } ast_t* child_type = deferred_reify(reify, ast_type(child), c->opt); value = gen_assign_cast(c, elements[i], value, child_type); ast_free_unattached(child_type); tuple = LLVMBuildInsertValue(c->builder, tuple, value, i++, ""); child = ast_sibling(child); } ponyint_pool_free_size(buf_size, elements); return tuple; }
LLVMValueRef gen_localdecl(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); const char* name = ast_name(id); // If this local has already been generated, don't create another copy. This // can happen when the same ast node is generated more than once, such as // the condition block of a while expression. LLVMValueRef value = codegen_getlocal(c, name); if(value != NULL) return GEN_NOVALUE; ast_t* type = deferred_reify(c->frame->reify, ast_type(id), c->opt); reach_type_t* t = reach_type(c->reach, type); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; // All alloca should happen in the entry block of a function. LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef inst = LLVMGetFirstInstruction(entry_block); if(inst != NULL) LLVMPositionBuilderBefore(c->builder, inst); else LLVMPositionBuilderAtEnd(c->builder, entry_block); LLVMValueRef alloc = LLVMBuildAlloca(c->builder, c_t->mem_type, name); // Store the alloca to use when we reference this local. codegen_setlocal(c, name, alloc); LLVMMetadataRef file = codegen_difile(c); LLVMMetadataRef scope = codegen_discope(c); #if PONY_LLVM >= 700 uint32_t align_bytes = LLVMABIAlignmentOfType(c->target_data, c_t->mem_type); LLVMMetadataRef info = LLVMDIBuilderCreateAutoVariable(c->di, scope, name, strlen(name), file, (unsigned)ast_line(ast), c_t->di_type, true, LLVMDIFlagZero, align_bytes * 8); #else LLVMMetadataRef info = LLVMDIBuilderCreateAutoVariable(c->di, scope, name, file, (unsigned)ast_line(ast), c_t->di_type); #endif LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0); LLVMDIBuilderInsertDeclare(c->di, alloc, info, expr, (unsigned)ast_line(ast), (unsigned)ast_pos(ast), scope, LLVMGetInsertBlock(c->builder)); // Put the builder back where it was. LLVMPositionBuilderAtEnd(c->builder, this_block); return GEN_NOTNEEDED; }
LLVMValueRef gen_float(compile_t* c, ast_t* ast) { ast_t* type = deferred_reify(c->frame->reify, ast_type(ast), c->opt); reach_type_t* t = reach_type(c->reach, type); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; return LLVMConstReal(c_t->primitive, ast_float(ast)); }
static int boxed_subtypes_overlap(reach_t* reach, ast_t* left_type, ast_t* right_type) { reach_type_t* r_left = reach_type(reach, left_type); reach_type_t* r_right = reach_type(reach, right_type); int subtypes = BOXED_SUBTYPES_NONE; size_t i = HASHMAP_BEGIN; reach_type_t* sub_left; while((sub_left = reach_type_cache_next(&r_left->subtypes, &i)) != NULL) { if(!sub_left->can_be_boxed) { subtypes |= BOXED_SUBTYPES_UNBOXED; if(subtypes == BOXED_SUBTYPES_ALL) return subtypes; continue; } size_t j = HASHMAP_BEGIN; reach_type_t* sub_right; while((sub_right = reach_type_cache_next(&r_right->subtypes, &j)) != NULL) { if(sub_left == sub_right) { if(sub_left->underlying == TK_PRIMITIVE) subtypes |= BOXED_SUBTYPES_NUMERIC; else subtypes |= BOXED_SUBTYPES_TUPLE; if(subtypes == BOXED_SUBTYPES_ALL) return subtypes; } } } return subtypes; }
void genprim_maybe_methods(compile_t* c, reach_type_t* t) { ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); maybe_create(c, t, t_elem); maybe_none(c, t); maybe_apply(c, t, t_elem); maybe_is_none(c, t); }
LLVMValueRef gendesc_isentity(compile_t* c, LLVMValueRef desc, ast_t* type) { reach_type_t* t = reach_type(c->reach, type); if(t == NULL) return GEN_NOVALUE; LLVMValueRef dptr = LLVMBuildBitCast(c->builder, t->desc, c->descriptor_ptr, ""); return LLVMBuildICmp(c->builder, LLVMIntEQ, desc, dptr, ""); }
LLVMValueRef gendesc_isentity(compile_t* c, LLVMValueRef desc, ast_t* type) { reach_type_t* t = reach_type(c->reach, type); if(t == NULL) return GEN_NOVALUE; LLVMValueRef left = LLVMBuildPtrToInt(c->builder, desc, c->intptr, ""); LLVMValueRef right = LLVMConstPtrToInt(t->desc, c->intptr); return LLVMBuildICmp(c->builder, LLVMIntEQ, left, right, ""); }
LLVMValueRef gendesc_istrait(compile_t* c, LLVMValueRef desc, ast_t* type) { // Get the trait identifier. reach_type_t* t = reach_type(c->reach, type); assert(t != NULL); LLVMValueRef trait_id = LLVMConstInt(c->i32, t->type_id, false); // Read the count and the trait list from the descriptor. LLVMValueRef count = desc_field(c, desc, DESC_TRAIT_COUNT); LLVMValueRef list = desc_field(c, desc, DESC_TRAITS); 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 count, check an ID. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i32, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, count, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get ID and compare it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef gep[2]; gep[0] = LLVMConstInt(c->i32, 0, false); gep[1] = phi; LLVMValueRef id_ptr = LLVMBuildInBoundsGEP(c->builder, list, gep, 2, ""); LLVMValueRef id = LLVMBuildLoad(c->builder, id_ptr, ""); LLVMValueRef test_id = LLVMBuildICmp(c->builder, LLVMIntEQ, id, trait_id, ""); // Add one to the phi node. LLVMValueRef one = LLVMConstInt(c->i32, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); LLVMAddIncoming(phi, &inc, &body_block, 1); // Either to the post block or back to the condition. LLVMBuildCondBr(c->builder, test_id, post_block, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef result = LLVMBuildPhi(c->builder, c->i1, ""); LLVMAddIncoming(result, &test, &cond_block, 1); LLVMAddIncoming(result, &test_id, &body_block, 1); return result; }
static void trace_known(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, ast_t* type, int mutability) { reach_type_t* t = reach_type(c->reach, type); LLVMValueRef args[4]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, object, c->object_ptr, ""); args[2] = LLVMBuildBitCast(c->builder, t->desc, c->descriptor_ptr, ""); args[3] = LLVMConstInt(c->i32, mutability, false); gencall_runtime(c, "pony_traceknown", args, 4, ""); }
LLVMValueRef gen_localload(compile_t* c, ast_t* ast) { LLVMValueRef local_ptr = gen_localptr(c, ast); if(local_ptr == NULL) return NULL; ast_t* type = deferred_reify(c->frame->reify, ast_type(ast), c->opt); reach_type_t* t = reach_type(c->reach, type); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; LLVMValueRef value = LLVMBuildLoad(c->builder, local_ptr, ""); return gen_assign_cast(c, c_t->use_type, value, t->ast_cap); }
static LLVMValueRef make_trait_list(compile_t* c, gentype_t* g) { // The list is an array of integers. uint32_t count = trait_count(c, g); // If we have no traits, return a null pointer to a list. if(count == 0) return LLVMConstNull(LLVMPointerType(LLVMArrayType(c->i32, 0), 0)); // Sort the trait identifiers. size_t tid_size = count * sizeof(uint32_t); uint32_t* tid = (uint32_t*)pool_alloc_size(tid_size); reachable_type_t* t = reach_type(c->reachable, g->type_name); assert(t != NULL); size_t i = HASHMAP_BEGIN; size_t index = 0; reachable_type_t* provide; while((provide = reachable_type_cache_next(&t->subtypes, &i)) != NULL) tid[index++] = provide->type_id; qsort(tid, index, sizeof(uint32_t), cmp_uint32); index = unique_uint32(tid, index); // Create a constant array of trait identifiers. size_t list_size = index * sizeof(LLVMValueRef); LLVMValueRef* list = (LLVMValueRef*)pool_alloc_size(list_size); for(i = 0; i < index; i++) list[i] = LLVMConstInt(c->i32, tid[i], false); count = (uint32_t)index; LLVMValueRef trait_array = LLVMConstArray(c->i32, list, count); // Create a global to hold the array. const char* name = genname_traitlist(g->type_name); LLVMTypeRef type = LLVMArrayType(c->i32, count); LLVMValueRef global = LLVMAddGlobal(c->module, type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMInternalLinkage); LLVMSetInitializer(global, trait_array); pool_free_size(tid_size, tid); pool_free_size(list_size, list); return global; }
static void trace_array_elements(compile_t* c, reach_type_t* t, LLVMValueRef ctx, LLVMValueRef object, LLVMValueRef pointer) { // Get the type argument for the array. This will be used to generate the // per-element trace call. ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); if(!gentrace_needed(typearg)) return; reach_type_t* t_elem = reach_type(c->reach, typearg); pointer = LLVMBuildBitCast(c->builder, pointer, 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"); // Read the size. LLVMValueRef size = field_value(c, object, 1); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, trace 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 trace it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, pointer, &phi, 1, "elem"); LLVMValueRef elem = LLVMBuildLoad(c->builder, elem_ptr, ""); gentrace(c, ctx, elem, typearg); // 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); }
bool genfun_methods(compile_t* c, gentype_t* g) { reachable_type_t* t = reach_type(c->reachable, g->type_name); size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; LLVMValueRef fun; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) { switch(ast_id(m->r_fun)) { case TK_NEW: if(g->underlying == TK_ACTOR) fun = genfun_newbe(c, g, n->name, m->typeargs); else fun = genfun_new(c, g, n->name, m->typeargs); break; case TK_BE: fun = genfun_be(c, g, n->name, m->typeargs); break; case TK_FUN: fun = genfun_fun(c, g, n->name, m->typeargs); break; default: fun = NULL; break; } if(fun == NULL) return false; } } if(!genfun_allocator(c, g)) return false; return true; }
LLVMValueRef gen_localdecl(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); ast_t* type = ast_type(id); const char* name = ast_name(id); // If this local has already been generated, don't create another copy. This // can happen when the same ast node is generated more than once, such as // the condition block of a while expression. LLVMValueRef value = codegen_getlocal(c, name); if(value != NULL) return GEN_NOVALUE; reach_type_t* t = reach_type(c->reach, type); // All alloca should happen in the entry block of a function. LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef inst = LLVMGetFirstInstruction(entry_block); if(inst != NULL) LLVMPositionBuilderBefore(c->builder, inst); else LLVMPositionBuilderAtEnd(c->builder, entry_block); LLVMValueRef alloc = LLVMBuildAlloca(c->builder, t->use_type, name); // Store the alloca to use when we reference this local. codegen_setlocal(c, name, alloc); LLVMMetadataRef file = codegen_difile(c); LLVMMetadataRef scope = codegen_discope(c); LLVMMetadataRef info = LLVMDIBuilderCreateAutoVariable(c->di, scope, name, file, (unsigned)ast_line(ast), t->di_type); LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0); LLVMDIBuilderInsertDeclare(c->di, alloc, info, expr, (unsigned)ast_line(ast), (unsigned)ast_pos(ast), scope, LLVMGetInsertBlock(c->builder)); // Put the builder back where it was. LLVMPositionBuilderAtEnd(c->builder, this_block); return GEN_NOVALUE; }
static uint32_t trait_count(compile_t* c, gentype_t* g, uint32_t** list, size_t* list_size) { switch(g->underlying) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: { reachable_type_t* t = reach_type(c->reachable, g->type_name); assert(t != NULL); uint32_t count = (uint32_t)reachable_type_cache_size(&t->subtypes); if(count == 0) return 0; // Sort the trait identifiers. size_t tid_size = count * sizeof(uint32_t); uint32_t* tid = (uint32_t*)pool_alloc_size(tid_size); size_t i = HASHMAP_BEGIN; size_t index = 0; reachable_type_t* provide; while((provide = reachable_type_cache_next(&t->subtypes, &i)) != NULL) tid[index++] = provide->type_id; qsort(tid, index, sizeof(uint32_t), cmp_uint32); count = (uint32_t)unique_uint32(tid, index); if(list != NULL) { *list = tid; *list_size = tid_size; } else { pool_free_size(tid_size, tid); } return count; } default: {} } return 0; }
static uint32_t trait_count(compile_t* c, gentype_t* g) { switch(g->underlying) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: { reachable_type_t* t = reach_type(c->reachable, g->type_name); assert(t != NULL); return (uint32_t)reachable_type_cache_size(&t->subtypes); } default: {} } return 0; }
void genprim_pointer_methods(compile_t* c, reach_type_t* t) { ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); pointer_create(c, t); pointer_alloc(c, t, t_elem); pointer_realloc(c, t, t_elem); pointer_unsafe(c, t); pointer_apply(c, t, t_elem); pointer_update(c, t, t_elem); pointer_offset(c, t, t_elem); pointer_insert(c, t, t_elem); pointer_delete(c, t, t_elem); pointer_copy_to(c, t, t_elem); pointer_usize(c, t); }
static bool check_value(compile_t* c, ast_t* pattern, ast_t* param_type, LLVMValueRef value, LLVMBasicBlockRef next_block) { reach_type_t* t = reach_type(c->reach, param_type); LLVMValueRef r_value = gen_assign_cast(c, t->use_type, value, param_type); if(r_value == NULL) return false; LLVMValueRef result = gen_pattern_eq(c, pattern, r_value); if(result == NULL) return false; LLVMBasicBlockRef continue_block = codegen_block(c, "pattern_continue"); LLVMValueRef test = LLVMBuildTrunc(c->builder, result, c->i1, ""); LLVMBuildCondBr(c->builder, test, continue_block, next_block); LLVMPositionBuilderAtEnd(c->builder, continue_block); return true; }
LLVMValueRef gen_int(compile_t* c, ast_t* ast) { ast_t* type = ast_type(ast); reach_type_t* t = reach_type(c->reach, type); lexint_t* value = ast_int(ast); LLVMValueRef vlow = LLVMConstInt(c->i128, value->low, false); LLVMValueRef vhigh = LLVMConstInt(c->i128, value->high, false); LLVMValueRef shift = LLVMConstInt(c->i128, 64, false); vhigh = LLVMConstShl(vhigh, shift); vhigh = LLVMConstAdd(vhigh, vlow); if(t->primitive == c->i128) return vhigh; if((t->primitive == c->f32) || (t->primitive == c->f64)) return LLVMConstUIToFP(vhigh, t->primitive); return LLVMConstTrunc(vhigh, t->primitive); }
LLVMValueRef gen_fieldload(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, left, right); LLVMValueRef field = gen_fieldptr(c, ast); if(field == NULL) return NULL; deferred_reification_t* reify = c->frame->reify; ast_t* type = deferred_reify(reify, ast_type(right), c->opt); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; field = LLVMBuildLoad(c->builder, field, ""); return gen_assign_cast(c, c_t->use_type, field, t->ast_cap); }