// Copyright (c) 2019-2025 Christoffer Lerno. All rights reserved. // Use of this source code is governed by the GNU LGPLv3.0 license // a copy of which can be found in the LICENSE file. #include "llvm_codegen_internal.h" static unsigned id_counter = 0; static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *type, LLVMMetadataRef scope); static inline LLVMMetadataRef llvm_get_debug_member(GenContext *c, Type *type, const char *name, unsigned offset, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags); static inline LLVMMetadataRef llvm_get_debug_struct(GenContext *c, Type *type, const char *external_name, LLVMMetadataRef *elements, unsigned element_count, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags); static LLVMMetadataRef llvm_debug_forward_comp(GenContext *c, Type *type, const char *external_name, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags); static LLVMMetadataRef llvm_debug_simple_type(GenContext *context, Type *type, int dwarf_code); static LLVMMetadataRef llvm_debug_func_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_structlike_type(GenContext *c, Type *type, LLVMMetadataRef scope); static LLVMMetadataRef llvm_debug_pointer_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_vector_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_typedef_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_array_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_errunion_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_slice_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_any_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope); static LLVMMetadataRef llvm_debug_raw_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope); INLINE LLVMMetadataRef llvm_create_debug_location_with_inline(GenContext *c, unsigned row, unsigned col, LLVMMetadataRef scope) { if (!c->debug.emit_expr_loc) col = 0; return LLVMDIBuilderCreateDebugLocation(c->context, row, col, scope, c->debug.block_stack->inline_loc ? c->debug.block_stack->inline_loc : NULL); } static inline LLVMMetadataRef llvm_get_debug_struct(GenContext *c, Type *type, const char *external_name, LLVMMetadataRef *elements, unsigned element_count, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags) { LLVMMetadataRef file = NULL; unsigned row = 0; size_t external_name_len = strlen(external_name); if (loc) { file = c->debug.file.debug_file; row = loc->row; if (!row) row = 1; } LLVMMetadataRef real = LLVMDIBuilderCreateStructType(c->debug.builder, scope, type->name ? type->name : "", type->name ? strlen(type->name) : 0, file, row, type_size(type) * 8, (uint32_t)(type_abi_alignment(type) * 8), flags, NULL, // Derived from elements, element_count, c->debug.runtime_version, NULL, // VTable external_name, external_name_len); if (type->backend_debug_type) { LLVMMetadataReplaceAllUsesWith(type->backend_debug_type, real); } return real; } static inline LLVMMetadataRef llvm_get_debug_member(GenContext *c, Type *type, const char *name, unsigned offset, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags) { ASSERT(name && scope); return LLVMDIBuilderCreateMemberType( c->debug.builder, scope, name, strlen(name), loc ? c->debug.file.debug_file : NULL, loc ? loc->row : 0, type_size(type) * 8, (uint32_t)(type_abi_alignment(type) * 8), offset * 8, flags, llvm_get_debug_type_internal(c, type, scope)); } LLVMMetadataRef llvm_debug_current_scope(GenContext *context) { if (context->debug.block_stack) return context->debug.block_stack->lexical_block; return context->debug.compile_unit; } void llvm_emit_debug_function(GenContext *c, Decl *decl) { if (!decl->func_decl.body) return; LLVMDIFlags flags = LLVMDIFlagZero; flags |= LLVMDIFlagPrototyped; if (decl->func_decl.signature.attrs.noreturn) flags |= LLVMDIFlagNoReturn; uint32_t row = decl->span.row; if (!row) row = 1; ASSERT(decl->name); ASSERT(c->debug.file.debug_file); LLVMMetadataRef debug_type = llvm_get_debug_type(c, decl->type); scratch_buffer_set_extern_decl_name(decl, true); c->debug.function = LLVMDIBuilderCreateFunction(c->debug.builder, c->debug.file.debug_file, decl->name, strlen(decl->name), scratch_buffer_to_string(), scratch_buffer.len, c->debug.file.debug_file, row, debug_type, decl_is_local(decl), true, row, flags, compiler.build.optlevel != OPTIMIZATION_NONE); LLVMSetSubprogram(decl->backend_ref, c->debug.function); } static void llvm_emit_debug_value(GenContext *c, LLVMValueRef value, LLVMMetadataRef debug_val, unsigned row, unsigned col, LLVMMetadataRef scope) { #if LLVM_VERSION_MAJOR < 19 LLVMDIBuilderInsertDbgValueAtEnd(c->debug.builder, value, debug_val, LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0), llvm_create_debug_location_with_inline(c, row, col, c->debug.function), LLVMGetInsertBlock(c->builder)); #else LLVMDIBuilderInsertDbgValueRecordAtEnd(c->debug.builder, value, debug_val, LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0), llvm_create_debug_location_with_inline(c, row, col, c->debug.function), LLVMGetInsertBlock(c->builder)); #endif } static void llvm_emit_debug_declare(GenContext *c, LLVMValueRef var, LLVMMetadataRef debug_var, unsigned row, unsigned col, LLVMMetadataRef scope) { #if LLVM_VERSION_MAJOR < 19 LLVMDIBuilderInsertDeclareAtEnd(c->debug.builder, var, debug_var, LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0), llvm_create_debug_location_with_inline(c, row, col, scope), LLVMGetInsertBlock(c->builder)); #else LLVMDIBuilderInsertDeclareRecordAtEnd(c->debug.builder, var, debug_var, LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0), llvm_create_debug_location_with_inline(c, row, col, scope), LLVMGetInsertBlock(c->builder)); #endif } void llvm_emit_debug_local_var(GenContext *c, Decl *decl) { ASSERT(llvm_is_local_eval(c)); EMIT_EXPR_LOC(c, decl); uint32_t row = decl->span.row; uint32_t col = decl->span.col; if (!row) row = 1; if (!col) col = 1; const char *name = decl->name; if (!name) name = ".temp"; LLVMMetadataRef scope = llvm_debug_current_scope(c); LLVMMetadataRef var = LLVMDIBuilderCreateAutoVariable( c->debug.builder, scope, name, strlen(name), c->debug.file.debug_file, row, llvm_get_debug_type(c, decl->type), compiler.build.optlevel != OPTIMIZATION_NONE, LLVMDIFlagZero, decl->alignment * 8); decl->var.backend_debug_ref = var; ASSERT(!decl->is_value); llvm_emit_debug_declare(c, decl->backend_ref, var, row, col, scope); } /** * Setup a debug parameter for a given index. * @param c * @param parameter * @param index */ void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index) { ASSERT(!llvm_is_global_eval(c)); const char *name = parameter->name ? parameter->name : ".anon"; bool always_preserve = false; unsigned row = parameter->span.row; if (row == 0) row = 1; unsigned col = parameter->span.col; if (col == 0) col = 1; parameter->var.backend_debug_ref = LLVMDIBuilderCreateParameterVariable( c->debug.builder, c->debug.function, name, strlen(name), index + 1, c->debug.file.debug_file, row, llvm_get_debug_type(c, parameter->type), always_preserve, LLVMDIFlagZero); if (parameter->is_value) { llvm_emit_debug_value(c, parameter->backend_value, parameter->var.backend_debug_ref, row, col, c->debug.function); return; } llvm_emit_debug_declare(c, parameter->backend_ref, parameter->var.backend_debug_ref, row, col, c->debug.function); } LLVMMetadataRef llvm_create_debug_location(GenContext *c, SourceSpan location) { LLVMMetadataRef scope = llvm_debug_current_scope(c); unsigned row = location.row; unsigned col = location.col; return llvm_create_debug_location_with_inline(c, row ? row : 1, col ? col : 1, scope); } void llvm_emit_debug_location(GenContext *c, SourceSpan location) { if (llvm_is_global_eval(c)) return; // Avoid re-emitting the same location. LLVMMetadataRef oldloc = LLVMGetCurrentDebugLocation2(c->builder); if (oldloc && c->last_emitted_loc.a == location.a) return; LLVMMetadataRef loc = c->last_loc = llvm_create_debug_location(c, location); if (!c->debug.emit_expr_loc) location.col = 0; c->last_emitted_loc.a = location.a; LLVMSetCurrentDebugLocation2(c->builder, loc); } static LLVMMetadataRef llvm_debug_forward_comp(GenContext *c, Type *type, const char *external_name, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags) { unsigned row = 0; if (loc) { row = loc->row; if (!row) row = 1; } return LLVMDIBuilderCreateReplaceableCompositeType(c->debug.builder, id_counter++, type->name, strlen(type->name), scope, c->debug.file.debug_file, row, c->debug.runtime_version, type_size(type) * 8, type_abi_alignment(type) * 8, flags, "temp", 4); } LLVMMetadataRef llvm_debug_create_macro(GenContext *c, Decl *macro) { SourceSpan location = macro->span; const char *name = macro->name; size_t namelen = strlen(name); LLVMMetadataRef file = llvm_get_debug_file(c, location.file_id); LLVMMetadataRef macro_type = NULL; return LLVMDIBuilderCreateFunction(c->debug.builder, file, name, namelen, name, namelen, file, location.row, macro_type, true, true, location.row, LLVMDIFlagZero, false); } DebugScope llvm_debug_create_lexical_scope(GenContext *context, SourceSpan location) { LLVMMetadataRef scope; LLVMMetadataRef inline_at; DebugScope *outline_at; if (context->debug.block_stack) { scope = context->debug.block_stack->lexical_block; inline_at = context->debug.block_stack->inline_loc; outline_at = context->debug.block_stack->outline_loc; } else { scope = context->debug.compile_unit; inline_at = NULL; outline_at = NULL; } unsigned row = location.row; unsigned col = location.col; LLVMMetadataRef debug_file = context->debug.file.debug_file; if (location.file_id != context->debug.file.file_id) { debug_file = llvm_get_debug_file(context, location.file_id); } LLVMMetadataRef block = LLVMDIBuilderCreateLexicalBlock(context->debug.builder, scope, debug_file, row ? row : 1, col ? col : 1); return (DebugScope) { .lexical_block = block, .inline_loc = inline_at, .outline_loc = outline_at }; } static LLVMMetadataRef llvm_debug_typeid_type(GenContext *context, Type *type) { return type->backend_debug_type = LLVMDIBuilderCreateBasicType(context->debug.builder, "typeid", strlen("typeid"), type_bit_size(type_voidptr), (LLVMDWARFTypeEncoding)DW_ATE_address, LLVMDIFlagZero); } static LLVMMetadataRef llvm_debug_simple_type(GenContext *context, Type *type, int dwarf_code) { return type->backend_debug_type = LLVMDIBuilderCreateBasicType(context->debug.builder, type->name, strlen(type->name), type->builtin.bitsize, (LLVMDWARFTypeEncoding)dwarf_code, LLVMDIFlagZero); } static LLVMMetadataRef llvm_debug_pointer_type(GenContext *c, Type *type) { LLVMMetadataRef inner = llvm_get_debug_type(c, type->pointer); if (type->backend_debug_type) return type->backend_debug_type; return LLVMDIBuilderCreatePointerType(c->debug.builder, inner, type_size(type) * 8, type_abi_alignment(type) * 8, 0, "", 0); } static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope) { Decl *decl = type->decl; LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, "temp_enum", &decl->span, scope, LLVMDIFlagZero); type->backend_debug_type = forward; Type *enum_real_type = decl->enums.type_info->type->canonical; LLVMMetadataRef *elements = NULL; Decl **enums = decl->enums.values; bool is_unsigned = type_is_unsigned(enum_real_type); FOREACH(Decl *, enum_constant, enums) { int64_t val = enum_constant->enum_constant.inner_ordinal; LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator( c->debug.builder, enum_constant->name, strlen(enum_constant->name), val, is_unsigned); vec_add(elements, debug_info); } unsigned row = decl->span.row; LLVMMetadataRef real = LLVMDIBuilderCreateEnumerationType(c->debug.builder, scope, type->decl->name, strlen(type->decl->name), c->debug.file.debug_file, row ? row : 1, type_size(type) * 8, type_abi_alignment(type) * 8, elements, vec_size(elements), llvm_get_debug_type(c, enum_real_type)); LLVMMetadataReplaceAllUsesWith(forward, real); return real; } static LLVMMetadataRef llvm_debug_raw_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope) { Decl *decl = type->decl; // FIXME TODO LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, "temp_enum", &decl->span, scope, LLVMDIFlagZero); type->backend_debug_type = forward; Type *enum_real_type = decl->enums.type_info->type->canonical; LLVMMetadataRef *elements = NULL; Decl **enums = decl->enums.values; bool is_unsigned = type_is_unsigned(enum_real_type); /*if () FOREACH(Decl *, enum_constant, enums) { // TODO, support other 128 if (type_size(enum_real_type) > 8) { TODO } LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator( c->debug.builder, enum_constant->name, strlen(enum_constant->name), enum_constant->enum_constant.const_value.low, is_unsigned); vec_add(elements, debug_info); }*/ unsigned row = decl->span.row; LLVMMetadataRef real = LLVMDIBuilderCreateEnumerationType(c->debug.builder, scope, type->decl->name, strlen(type->decl->name), c->debug.file.debug_file, row ? row : 1, type_size(type) * 8, type_abi_alignment(type) * 8, elements, vec_size(elements), llvm_get_debug_type(c, enum_real_type)); LLVMMetadataReplaceAllUsesWith(forward, real); return real; } static LLVMMetadataRef llvm_debug_structlike_type(GenContext *c, Type *type, LLVMMetadataRef scope) { Decl *decl = type->decl; LLVMDIFlags flags = 0; // Create a forward reference in case of recursive data. LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, "temp", &decl->span, scope, flags); type->backend_debug_type = forward; LLVMMetadataRef *elements = NULL; Decl **members = decl->strukt.members; unsigned count = vec_size(members); for (unsigned i = 0; i < count; i++) { Decl *member = members[i]; LLVMMetadataRef debug_info = llvm_get_debug_member(c, member->type, member->name ? member->name : "", member->offset, &member->span, forward, LLVMDIFlagZero); vec_add(elements, debug_info); } LLVMMetadataRef real; const char *extname = ""; unsigned extname_len = 0; if (decl->name) { scratch_buffer_set_extern_decl_name(decl, true); extname = scratch_buffer_to_string(); extname_len = scratch_buffer.len; } if (type->type_kind == TYPE_UNION) { unsigned row = decl->span.row; real = LLVMDIBuilderCreateUnionType(c->debug.builder, scope, decl->name ? decl->name : "", decl->name ? strlen(decl->name) : 0, c->debug.file.debug_file, row ? row : 1, type_size(type) * 8, type_abi_alignment(type) * 8, LLVMDIFlagZero, elements, vec_size(members), c->debug.runtime_version, extname, extname_len); LLVMMetadataReplaceAllUsesWith(forward, real); return real; } return llvm_get_debug_struct(c, type, extname, elements, vec_size(elements), &decl->span, scope, LLVMDIFlagZero); } static LLVMMetadataRef llvm_debug_slice_type(GenContext *c, Type *type) { LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, type->name, NULL, NULL, LLVMDIFlagZero); type->backend_debug_type = forward; LLVMMetadataRef elements[2] = { llvm_get_debug_member(c, type_get_ptr(type->array.base), "ptr", 0, NULL, forward, LLVMDIFlagZero), llvm_get_debug_member(c, type_usz, "len", type_size(type_voidptr), NULL, forward, LLVMDIFlagZero) }; return llvm_get_debug_struct(c, type, type->name, elements, 2, NULL, NULL, LLVMDIFlagZero); } static LLVMMetadataRef llvm_debug_any_type(GenContext *c, Type *type) { LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, type->name, NULL, NULL, LLVMDIFlagZero); type->backend_debug_type = forward; LLVMMetadataRef elements[2] = { llvm_get_debug_member(c, type_voidptr, "ptr", 0, NULL, forward, LLVMDIFlagZero), llvm_get_debug_member(c, type_typeid, "type", type_size(type_voidptr), NULL, forward, LLVMDIFlagZero) }; return llvm_get_debug_struct(c, type, type->name, elements, 2, NULL, NULL, LLVMDIFlagZero); } static LLVMMetadataRef llvm_debug_errunion_type(GenContext *c, Type *type) { return LLVMDIBuilderCreateTypedef(c->debug.builder, llvm_get_debug_type(c, type_iptr->canonical), type->name, strlen(type->name), NULL, 0, NULL, 0); } static LLVMMetadataRef llvm_debug_array_type(GenContext *c, Type *type) { LLVMMetadataRef *ranges = NULL; Type *current_type = type; while (current_type->canonical->type_kind == TYPE_ARRAY || current_type->canonical->type_kind == TYPE_FLEXIBLE_ARRAY) { vec_add(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->array.len)); current_type = current_type->canonical->array.base; } if (!current_type->backend_debug_type) { type->backend_debug_type = llvm_debug_forward_comp(c, type, type->name, NULL, NULL, LLVMDIFlagZero); } LLVMMetadataRef real = LLVMDIBuilderCreateArrayType( c->debug.builder, type_size(type) * 8, type_abi_alignment(current_type) * 8, llvm_get_debug_type(c, current_type), ranges, vec_size(ranges)); if (type->backend_debug_type) { LLVMMetadataReplaceAllUsesWith(type->backend_debug_type, real); } return real; } static LLVMMetadataRef llvm_debug_typedef_type(GenContext *c, Type *type) { Decl *decl = type->decl; // Is this a primitive typedef? If so, we create it without reference. if (decl->unit == compiler.context.core_unit) { return LLVMDIBuilderCreateTypedef(c->debug.builder, llvm_get_debug_type(c, type_lowering(type)), type->name, strlen(type->name), NULL, 0, NULL, 0); } Type *original_type = type->type_kind == TYPE_ALIAS ? type->canonical : decl->distinct->type; // Use forward references in case we haven't resolved the original type, since we could have this: if (!type->canonical->backend_debug_type) { type->backend_debug_type = llvm_debug_forward_comp(c, type, type->name, &decl->span, NULL, LLVMDIFlagZero); } unsigned row = decl->span.row; LLVMMetadataRef real = LLVMDIBuilderCreateTypedef(c->debug.builder, llvm_get_debug_type(c, original_type), decl->name, strlen(decl->name), c->debug.file.debug_file, row ? row : 1, c->debug.file.debug_file, type_abi_alignment(type) * 8); if (type->backend_debug_type) { LLVMMetadataReplaceAllUsesWith(type->backend_debug_type, real); type->backend_debug_type = real; } return real; } static LLVMMetadataRef llvm_debug_vector_type(GenContext *c, Type *type) { LLVMMetadataRef *ranges = NULL; Type *current_type = type; while (type_kind_is_any_vector(current_type->canonical->type_kind)) { vec_add(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->array.len)); current_type = current_type->canonical->array.base; } return LLVMDIBuilderCreateVectorType( c->debug.builder, type_size(type) * 8, type_abi_alignment(current_type) * 8, llvm_get_debug_type(c, current_type), ranges, vec_size(ranges)); } static LLVMMetadataRef llvm_debug_func_type(GenContext *c, Type *type) { FunctionPrototype *prototype = type_get_resolved_prototype(type); Signature *sig = prototype->raw_type->function.signature; // 1. Generate all the parameter types, this may cause this function to be called again! FOREACH(Decl *, param, sig->params) { llvm_get_debug_type(c, param->type); } // 2. We might be done! if (type->backend_debug_type) return type->backend_debug_type; // 3. Otherwise generate: static LLVMMetadataRef *buffer = NULL; vec_resize(buffer, 0); vec_add(buffer, llvm_get_debug_type(c, typeget(sig->rtype))); FOREACH(Decl *, param, sig->params) { vec_add(buffer, llvm_get_debug_type(c, param->type)); } if (prototype->raw_variadic) { vec_add(buffer, LLVMDIBuilderCreateUnspecifiedType(c->debug.builder, "", 0)); } return LLVMDIBuilderCreateSubroutineType(c->debug.builder, c->debug.file.debug_file, buffer, vec_size(buffer), 0); } static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *type, LLVMMetadataRef scope) { if (type->backend_debug_type) { return type->backend_debug_type; } // Consider special handling of UTF8 arrays. switch (type->type_kind) { case CT_TYPES: UNREACHABLE case TYPE_BITSTRUCT: case TYPE_OPTIONAL: return type->backend_debug_type = llvm_get_debug_type(c, type_lowering(type)); case TYPE_BOOL: return llvm_debug_simple_type(c, type, DW_ATE_boolean); case TYPE_I8: return llvm_debug_simple_type(c, type, DW_ATE_signed_char); // DW_ATE_UTF? case TYPE_U8: return llvm_debug_simple_type(c, type, DW_ATE_unsigned_char); case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: return llvm_debug_simple_type(c, type, DW_ATE_signed); case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128: return llvm_debug_simple_type(c, type, DW_ATE_unsigned); case TYPE_F16: case TYPE_BF16: case TYPE_F32: case TYPE_F64: case TYPE_F128: return llvm_debug_simple_type(c, type, DW_ATE_float); case VECTORS: return type->backend_debug_type = llvm_debug_vector_type(c, type); case TYPE_VOID: return NULL; case TYPE_TYPEID: return type->backend_debug_type = llvm_debug_typeid_type(c, type); case TYPE_POINTER: case TYPE_FUNC_PTR: return type->backend_debug_type = llvm_debug_pointer_type(c, type); case TYPE_ENUM: return type->backend_debug_type = llvm_debug_enum_type(c, type, scope); case TYPE_CONST_ENUM: return type->backend_debug_type = llvm_debug_raw_enum_type(c, type, scope); case TYPE_FUNC_RAW: return type->backend_debug_type = llvm_debug_func_type(c, type); case TYPE_STRUCT: case TYPE_UNION: return type->backend_debug_type = llvm_debug_structlike_type(c, type, scope); case TYPE_TYPEDEF: case TYPE_ALIAS: return type->backend_debug_type = llvm_debug_typedef_type(c, type); case TYPE_FLEXIBLE_ARRAY: case TYPE_ARRAY: return type->backend_debug_type = llvm_debug_array_type(c, type); case TYPE_SLICE: return type->backend_debug_type = llvm_debug_slice_type(c, type); case TYPE_ANYFAULT: return type->backend_debug_type = llvm_debug_errunion_type(c, type); case TYPE_INTERFACE: case TYPE_ANY: return type->backend_debug_type = llvm_debug_any_type(c, type); } UNREACHABLE } LLVMMetadataRef llvm_get_debug_type(GenContext *c, Type *type) { // All types should be generated in the outer scope. return llvm_get_debug_type_internal(c, type, c->debug.file.debug_file); }