static void genfun_dwarf(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs, ast_t* fun) { if(!codegen_hassource(c)) return; // Get the function. const char* funname = genname_fun(g->type_name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); assert(func != NULL); // Count the parameters, including the receiver. ast_t* params = ast_childidx(fun, 3); size_t count = ast_childcount(params) + 1; size_t buf_size = (count + 1) * sizeof(const char*); const char** pnames = (const char**)pool_alloc_size(buf_size); count = 0; // Return value type name and receiver type name. pnames[count++] = genname_type(ast_childidx(fun, 4)); pnames[count++] = g->type_name; // Get a type name for each parameter. ast_t* param = ast_child(params); while(param != NULL) { ast_t* ptype = ast_childidx(param, 1); pnames[count++] = genname_type(ptype); param = ast_sibling(param); } // Dwarf the method type dwarf_method(&c->dwarf, fun, name, funname, pnames, count, func); // Dwarf the receiver pointer. LLVMBasicBlockRef entry = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef argument = codegen_getlocal(c, stringtab("this")); dwarf_this(&c->dwarf, fun, g->type_name, entry, argument); // Dwarf locals for parameters param = ast_child(params); size_t index = 1; while(param != NULL) { argument = codegen_getlocal(c, ast_name(ast_child(param))); dwarf_parameter(&c->dwarf, param, pnames[index + 1], entry, argument, index); param = ast_sibling(param); index++; } pool_free_size(buf_size, pnames); }
bool gentype(compile_t* c, ast_t* ast, gentype_t* g) { memset(g, 0, sizeof(gentype_t)); if(ast == NULL) return false; if(contains_dontcare(ast)) return true; g->ast = ast; g->type_name = genname_type(ast); g->desc_name = genname_descriptor(g->type_name); switch(ast_id(ast)) { case TK_NOMINAL: return make_nominal(c, ast, g, false); case TK_TUPLETYPE: return make_tuple(c, ast, g); case TK_UNIONTYPE: case TK_ISECTTYPE: // Just a raw object pointer. g->underlying = ast_id(ast); g->use_type = c->object_ptr; return true; default: {} } assert(0); return false; }
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; }
uint32_t genfun_vtable_index(compile_t* c, gentype_t* g, const char* name, ast_t* typeargs) { switch(ast_id(g->ast)) { case TK_NOMINAL: return vtable_index(c, g->type_name, name, typeargs); case TK_ISECTTYPE: { ast_t* child = ast_child(g->ast); while(child != NULL) { const char* type_name = genname_type(child); uint32_t index = vtable_index(c, type_name, name, typeargs); if(index != (uint32_t)-1) return index; child = ast_sibling(child); } return -1; } default: {} } return -1; }
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 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 gendesc_istrait(compile_t* c, LLVMValueRef desc, ast_t* type) { // Get the trait identifier. reachable_type_t* t = reach_type(c->reachable, genname_type(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 = LLVMBuildGEP(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 reachable_type_t* add_reachable_type(reachable_types_t* r, ast_t* type) { reachable_type_t* t = POOL_ALLOC(reachable_type_t); memset(t, 0, sizeof(reachable_type_t)); t->name = genname_type(type); t->ast = set_cap_and_ephemeral(type, TK_REF, TK_NONE); reachable_method_names_init(&t->methods, 0); reachable_type_cache_init(&t->subtypes, 0); reachable_types_put(r, t); return t; }
static void print_base_type(compile_t* c, printbuf_t* buf, ast_t* type) { if(ast_id(type) == TK_NOMINAL) { const char* name = genname_type(type); const char* c_name = c_type_name(c, name); if(c_name != NULL) printbuf(buf, c_name); else printbuf(buf, "%s*", name); } else { printbuf(buf, "void*"); } }
bool gentype_prelim(compile_t* c, ast_t* ast, gentype_t* g) { if(ast_id(ast) == TK_NOMINAL) { memset(g, 0, sizeof(gentype_t)); g->ast = ast; g->type_name = genname_type(ast); g->desc_name = genname_descriptor(g->type_name); return make_nominal(c, ast, g, true); } return gentype(c, ast, g); }
static void typeargs_append(char* name, ast_t* typeargs, bool function) { if(typeargs == NULL) return; if(function) strcat(name, "_"); ast_t* typearg = ast_child(typeargs); while(typearg != NULL) { name_append(name, genname_type(typearg)); typearg = ast_sibling(typearg); } }
static size_t typeargs_len(ast_t* typeargs) { if(typeargs == NULL) return 0; ast_t* typearg = ast_child(typeargs); size_t len = 0; while(typearg != NULL) { const char* argname = genname_type(typearg); len += strlen(argname) + 1; typearg = ast_sibling(typearg); } return len; }
static bool trace_tuple(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) { // Invoke the trace function directly. Do not trace the address of the tuple. const char* type_name = genname_type(type); const char* trace_name = genname_tracetuple(type_name); LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, trace_name); // There will be no trace function if the tuple doesn't need tracing. if(trace_fn == NULL) return false; LLVMValueRef args[2]; args[0] = ctx; args[1] = value; LLVMBuildCall(c->builder, trace_fn, args, 2, ""); return true; }
reach_type_t* reach_type(reach_t* r, ast_t* type) { reach_type_t k; k.name = genname_type(type); return reach_types_get(&r->types, &k); }
reachable_type_t* reach_type(reachable_types_t* r, ast_t* type) { reachable_type_t k; k.name = genname_type(type); return reachable_types_get(r, &k); }
LLVMValueRef gendesc_typeid(compile_t* c, ast_t* type) { return make_type_id(c, genname_type(type)); }