static void name_param(compile_t* c, reachable_type_t* t, reachable_method_t* m, LLVMValueRef func, const char* name, unsigned index, size_t line, size_t pos) { LLVMValueRef value = LLVMGetParam(func, index); LLVMSetValueName(value, name); LLVMValueRef alloc = LLVMBuildAlloca(c->builder, t->use_type, name); LLVMBuildStore(c->builder, value, alloc); codegen_setlocal(c, name, alloc); LLVMMetadataRef info; if(index == 0) { info = LLVMDIBuilderCreateArtificialVariable(c->di, m->di_method, name, index + 1, m->di_file, (unsigned)ast_line(m->r_fun), t->di_type); } else { info = LLVMDIBuilderCreateParameterVariable(c->di, m->di_method, name, index + 1, m->di_file, (unsigned)ast_line(m->r_fun), t->di_type); } LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0); LLVMDIBuilderInsertDeclare(c->di, alloc, info, expr, (unsigned)line, (unsigned)pos, m->di_method, LLVMGetInsertBlock(c->builder)); }
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; }
/** * Make sure the definition of something occurs before its use. This is for * both fields and local variable. */ static bool def_before_use(ast_t* def, ast_t* use, const char* name) { if((ast_line(def) > ast_line(use)) || ((ast_line(def) == ast_line(use)) && (ast_pos(def) > ast_pos(use)))) { ast_error(use, "declaration of '%s' appears after use", name); ast_error(def, "declaration of '%s' appears here", name); return false; } return true; }
/** * Make sure the definition of something occurs before its use. This is for * both fields and local variable. */ bool def_before_use(pass_opt_t* opt, ast_t* def, ast_t* use, const char* name) { if((ast_line(def) > ast_line(use)) || ((ast_line(def) == ast_line(use)) && (ast_pos(def) > ast_pos(use)))) { ast_error(opt->check.errors, use, "declaration of '%s' appears after use", name); ast_error_continue(opt->check.errors, def, "declaration of '%s' appears here", name); return false; } return true; }
static void name_params(compile_t* c, reachable_type_t* t, reachable_method_t* m, ast_t* params, LLVMValueRef func) { // Name the receiver 'this'. name_param(c, t, m, func, c->str_this, 0, ast_line(params), ast_pos(params)); // Name each parameter. ast_t* param = ast_child(params); for(size_t i = 0; i < m->param_count; i++) { name_param(c, m->params[i], m, func, ast_name(ast_child(param)), (unsigned)i + 1, ast_line(param), ast_pos(param)); param = ast_sibling(param); } }
static bool names_typealias(pass_opt_t* opt, ast_t** astp, ast_t* def) { ast_t* ast = *astp; AST_GET_CHILDREN(ast, pkg, id, typeargs, cap, eph); // Make sure the alias is resolved, AST_GET_CHILDREN(def, alias_id, typeparams, def_cap, provides); ast_t* alias = ast_child(provides); if(!names_resolvealias(opt, def, &alias)) return false; // Reify the alias. ast_t* r_alias = reify(typeparams, alias, typeparams, typeargs); if(r_alias == NULL) return false; // Apply our cap and ephemeral to the result. if(!names_applycap(r_alias, cap, eph)) { ast_free_unattached(r_alias); return false; } // Maintain the position info of the original reference to aid error // reporting. ast_setpos(r_alias, ast_line(ast), ast_pos(ast)); // Replace this with the alias. ast_replace(astp, r_alias); 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; }
void codegen_debugloc(compile_t* c, ast_t* ast) { if(ast != NULL) { LLVMSetCurrentDebugLocation2(c->builder, (unsigned)ast_line(ast), (unsigned)ast_pos(ast), c->frame->di_scope); } else { LLVMSetCurrentDebugLocation2(c->builder, 0, 0, NULL); } }
static void make_debug_prototype(compile_t* c, reach_type_t* t) { t->di_type = LLVMDIBuilderCreateReplaceableStruct(c->di, t->name, c->di_unit, t->di_file, (unsigned)ast_line(t->ast)); if(t->underlying != TK_TUPLETYPE) { t->di_type_embed = t->di_type; t->di_type = LLVMDIBuilderCreatePointerType(c->di, t->di_type_embed, 0, 0); } }
void dwarf_method(dwarf_t* dwarf, ast_t* fun, const char* name, const char* mangled, const char** params, size_t count, LLVMValueRef ir) { dwarf_meta_t meta; memset(&meta, 0, sizeof(dwarf_meta_t)); source_t* source = ast_source(fun); ast_t* seq = ast_childidx(fun, 6); meta.file = source->file; meta.name = name; meta.mangled = mangled; meta.params = params; meta.line = ast_line(fun); meta.pos = ast_pos(fun); meta.offset = ast_line(seq); meta.size = count; symbols_method(dwarf->symbols, &meta, ir); }
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); }
void dwarf_lexicalscope(dwarf_t* dwarf, ast_t* ast) { dwarf_meta_t meta; memset(&meta, 0, sizeof(dwarf_meta_t)); symbols_push_frame(dwarf->symbols, NULL); source_t* source = ast_source(ast); meta.file = source->file; meta.line = ast_line(ast); meta.pos = ast_pos(ast); symbols_lexicalscope(dwarf->symbols, &meta); }
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; } }
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; } }
void codegen_pushscope(compile_t* c, ast_t* ast) { compile_frame_t* frame = push_frame(c); frame->fun = frame->prev->fun; frame->break_target = frame->prev->break_target; frame->continue_target = frame->prev->continue_target; frame->invoke_target = frame->prev->invoke_target; frame->di_file = frame->prev->di_file; if(frame->prev->di_scope != NULL) { frame->di_scope = LLVMDIBuilderCreateLexicalBlock(c->di, frame->prev->di_scope, frame->di_file, (unsigned)ast_line(ast), (unsigned)ast_pos(ast)); } }
void dwarf_location(dwarf_t* dwarf, ast_t* ast) { if(dwarf->has_source && (ast != NULL)) { size_t line = ast_line(ast); size_t pos = ast_pos(ast); if(!ast_debug(ast)) symbols_reset(dwarf->symbols, true); else symbols_location(dwarf->symbols, line, pos); } else if(dwarf->symbols != NULL) { symbols_reset(dwarf->symbols, true); } }
static void meta_local(dwarf_meta_t* meta, ast_t* ast, const char* name, const char* type, LLVMBasicBlockRef entry, LLVMValueRef storage, size_t offset, bool constant) { memset(meta, 0, sizeof(dwarf_meta_t)); source_t* source = ast_source(ast); meta->file = source->file; meta->name = name; meta->mangled = type; meta->line = ast_line(ast); meta->pos = ast_pos(ast); meta->offset = offset + 1; meta->entry = entry; meta->storage = storage; if(constant) meta->flags = DWARF_CONSTANT; }
// Check the number of configs we have to process and print a warning if it's a // lot. static void check_config_count(buildflagset_t* config, ast_t* location) { pony_assert(config != NULL); pony_assert(location != NULL); double config_count = buildflagset_configcount(config); if(config_count > 10000) { source_t* source = ast_source(location); const char* file = NULL; if(source != NULL) file = source->file; if(file == NULL) file = ""; printf("Processing %g configs at %s:" __zu ", this may take some time\n", config_count, file, ast_line(location)); } }
static void make_function_debug(compile_t* c, reachable_type_t* t, reachable_method_t* m, LLVMValueRef func) { AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); // Count the parameters, including the receiver and the result. size_t count = m->param_count + 2; size_t md_size = count * sizeof(reachable_type_t*); LLVMMetadataRef* md = (LLVMMetadataRef*)ponyint_pool_alloc_size(md_size); md[0] = m->result->di_type; md[1] = t->di_type; for(size_t i = 0; i < m->param_count; i++) md[i + 2] = m->params[i]->di_type; m->di_file = t->di_file; LLVMMetadataRef type_array = LLVMDIBuilderGetOrCreateTypeArray(c->di, md, count); LLVMMetadataRef subroutine = LLVMDIBuilderCreateSubroutineType(c->di, m->di_file, type_array); LLVMMetadataRef scope; if(t->di_type_embed != NULL) scope = t->di_type_embed; else scope = t->di_type; m->di_method = LLVMDIBuilderCreateMethod(c->di, scope, ast_name(id), m->full_name, m->di_file, (unsigned)ast_line(m->r_fun), subroutine, func, c->opt->release); ponyint_pool_free_size(md_size, md); }
static void add_fields(reach_t* r, reach_type_t* t, pass_opt_t* opt) { ast_t* def = (ast_t*)ast_data(t->ast); ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typeparams = ast_childidx(def, 1); ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { t->field_count++; break; } default: {} } member = ast_sibling(member); } if(t->field_count == 0) return; t->fields = (reach_field_t*)calloc(t->field_count, sizeof(reach_field_t)); member = ast_child(members); size_t index = 0; while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { ast_t* r_member = lookup(NULL, NULL, t->ast, ast_name(ast_child(member))); assert(r_member != NULL); AST_GET_CHILDREN(r_member, name, type, init); t->fields[index].embed = ast_id(member) == TK_EMBED; t->fields[index].ast = reify(ast_type(member), typeparams, typeargs, opt, true); ast_setpos(t->fields[index].ast, NULL, ast_line(name), ast_pos(name)); t->fields[index].type = add_type(r, type, opt); if(r_member != member) ast_free_unattached(r_member); index++; break; } default: {} } member = ast_sibling(member); } }
static void setup_type_fields(gentype_t* g) { assert(ast_id(g->ast) == TK_NOMINAL); g->field_count = 0; g->fields = NULL; g->field_keys = NULL; ast_t* def = (ast_t*)ast_data(g->ast); if(ast_id(def) == TK_PRIMITIVE) return; ast_t* typeargs = ast_childidx(g->ast, 2); ast_t* typeparams = ast_childidx(def, 1); ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { g->field_count++; break; } default: {} } member = ast_sibling(member); } if(g->field_count == 0) return; g->fields = (ast_t**)calloc(g->field_count, sizeof(ast_t*)); g->field_keys = (token_id*)calloc(g->field_count, sizeof(token_id)); member = ast_child(members); size_t index = 0; while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { AST_GET_CHILDREN(member, name, type, init); g->fields[index] = reify(ast_type(member), typeparams, typeargs); // TODO: Are we sure the AST source file is correct? ast_setpos(g->fields[index], NULL, ast_line(name), ast_pos(name)); g->field_keys[index] = ast_id(member); index++; break; } default: {} } member = ast_sibling(member); } }