Commit 72e00805a6

Andrew Kelley <andrew@ziglang.org>
2024-08-20 01:29:45
llvm.Builder: add support for more instruction metadata
mlugg: this is cherry-picked from Andrew's nosanitize branch (with Jacob's fixes squashed in) since I needed this for `unpredictable` and `prof` metadata. The nosanitize-specific changes are reverted in the next commit. Co-authored-by: Jacob Young <jacobly0@users.noreply.github.com>
1 parent f2d7096
Changed files (2)
src
codegen
src/codegen/llvm/Builder.zig
@@ -7697,6 +7697,7 @@ pub const MetadataString = enum(u32) {
 
 pub const Metadata = enum(u32) {
     none = 0,
+    empty_tuple = 1,
     _,
 
     const first_forward_reference = 1 << 29;
@@ -8355,7 +8356,7 @@ pub const Metadata = enum(u32) {
 };
 
 pub fn init(options: Options) Allocator.Error!Builder {
-    var self = Builder{
+    var self: Builder = .{
         .gpa = options.allocator,
         .strip = options.strip,
 
@@ -8458,6 +8459,7 @@ pub fn init(options: Options) Allocator.Error!Builder {
 
     try self.metadata_string_indices.append(self.gpa, 0);
     assert(try self.metadataString("") == .none);
+    assert(try self.debugTuple(&.{}) == .empty_tuple);
 
     return self;
 }
@@ -13759,7 +13761,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
             const MetadataKindBlock = ir.MetadataKindBlock;
             var metadata_kind_block = try module_block.enterSubBlock(MetadataKindBlock, true);
 
-            inline for (@typeInfo(ir.MetadataKind).Enum.fields) |field| {
+            inline for (@typeInfo(ir.FixedMetadataKind).Enum.fields) |field| {
                 try metadata_kind_block.writeAbbrev(MetadataKindBlock.Kind{
                     .id = field.value,
                     .name = field.name,
@@ -14046,7 +14048,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                                 else
                                     -%val << 1 | 1);
                             }
-                            try metadata_block.writeUnabbrev(MetadataBlock.Enumerator.id, record.items);
+                            try metadata_block.writeUnabbrev(@intFromEnum(MetadataBlock.Enumerator.id), record.items);
                             continue;
                         };
                         try metadata_block.writeAbbrevAdapted(MetadataBlock.Enumerator{
@@ -14177,7 +14179,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
 
                     try metadata_block.writeAbbrev(MetadataBlock.GlobalDeclAttachment{
                         .value = @enumFromInt(constant_adapter.getConstantIndex(global.toConst())),
-                        .kind = ir.MetadataKind.dbg,
+                        .kind = .dbg,
                         .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(global_ptr.dbg) - 1),
                     });
                 }
@@ -14220,20 +14222,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                 constant_adapter: ConstantAdapter,
                 metadata_adapter: MetadataAdapter,
                 func: *const Function,
-                instruction_index: u32 = 0,
-
-                pub fn init(
-                    const_adapter: ConstantAdapter,
-                    meta_adapter: MetadataAdapter,
-                    func: *const Function,
-                ) @This() {
-                    return .{
-                        .constant_adapter = const_adapter,
-                        .metadata_adapter = meta_adapter,
-                        .func = func,
-                        .instruction_index = 0,
-                    };
-                }
+                instruction_index: Function.Instruction.Index,
 
                 pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) {
                     _ = field_name;
@@ -14282,19 +14271,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                 }
 
                 pub fn offset(adapter: @This()) u32 {
-                    return @as(
-                        Function.Instruction.Index,
-                        @enumFromInt(adapter.instruction_index),
-                    ).valueIndex(adapter.func) + adapter.firstInstr();
+                    return adapter.instruction_index.valueIndex(adapter.func) + adapter.firstInstr();
                 }
 
                 fn firstInstr(adapter: @This()) u32 {
                     return adapter.constant_adapter.numConstants();
                 }
-
-                pub fn next(adapter: *@This()) void {
-                    adapter.instruction_index += 1;
-                }
             };
 
             for (self.functions.items, 0..) |func, func_index| {
@@ -14307,7 +14289,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
 
                 try function_block.writeAbbrev(FunctionBlock.DeclareBlocks{ .num_blocks = func.blocks.len });
 
-                var adapter = FunctionAdapter.init(constant_adapter, metadata_adapter, &func);
+                var adapter: FunctionAdapter = .{
+                    .constant_adapter = constant_adapter,
+                    .metadata_adapter = metadata_adapter,
+                    .func = &func,
+                    .instruction_index = @enumFromInt(0),
+                };
 
                 // Emit function level metadata block
                 if (!func.strip and func.debug_values.len > 0) {
@@ -14330,21 +14317,23 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                 var has_location = false;
 
                 var block_incoming_len: u32 = undefined;
-                for (0..func.instructions.len) |instr_index| {
-                    const tag = tags[instr_index];
-
+                for (tags, datas, 0..) |tag, data, instr_index| {
+                    adapter.instruction_index = @enumFromInt(instr_index);
                     record.clearRetainingCapacity();
 
                     switch (tag) {
-                        .block => block_incoming_len = datas[instr_index],
-                        .arg => {},
+                        .arg => continue,
+                        .block => {
+                            block_incoming_len = data;
+                            continue;
+                        },
                         .@"unreachable" => try function_block.writeAbbrev(FunctionBlock.Unreachable{}),
                         .call,
                         .@"musttail call",
                         .@"notail call",
                         .@"tail call",
                         => |kind| {
-                            var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]);
+                            var extra = func.extraDataTrail(Function.Instruction.Call, data);
 
                             const call_conv = extra.data.info.call_conv;
                             const args = extra.trail.next(extra.data.args_len, Value, &func);
@@ -14367,7 +14356,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .@"notail call fast",
                         .@"tail call fast",
                         => |kind| {
-                            var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]);
+                            var extra = func.extraDataTrail(Function.Instruction.Call, data);
 
                             const call_conv = extra.data.info.call_conv;
                             const args = extra.trail.next(extra.data.args_len, Value, &func);
@@ -14405,7 +14394,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .srem,
                         .ashr,
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Binary, data);
                             try function_block.writeAbbrev(FunctionBlock.Binary{
                                 .opcode = kind.toBinaryOpcode(),
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14417,7 +14406,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .@"lshr exact",
                         .@"ashr exact",
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Binary, data);
                             try function_block.writeAbbrev(FunctionBlock.BinaryExact{
                                 .opcode = kind.toBinaryOpcode(),
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14437,7 +14426,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .@"shl nuw",
                         .@"shl nuw nsw",
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Binary, data);
                             try function_block.writeAbbrev(FunctionBlock.BinaryNoWrap{
                                 .opcode = kind.toBinaryOpcode(),
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14468,7 +14457,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .@"frem fast",
                         .@"fsub fast",
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Binary, data);
                             try function_block.writeAbbrev(FunctionBlock.BinaryFast{
                                 .opcode = kind.toBinaryOpcode(),
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14479,7 +14468,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .alloca,
                         .@"alloca inalloca",
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Alloca, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Alloca, data);
                             const alignment = extra.info.alignment.toLlvm();
                             try function_block.writeAbbrev(FunctionBlock.Alloca{
                                 .inst_type = extra.type,
@@ -14508,7 +14497,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .sext,
                         .zext,
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Cast, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Cast, data);
                             try function_block.writeAbbrev(FunctionBlock.Cast{
                                 .val = adapter.getOffsetValueIndex(extra.val),
                                 .type_index = extra.type,
@@ -14542,7 +14531,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .@"icmp ule",
                         .@"icmp ult",
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Binary, data);
                             try function_block.writeAbbrev(FunctionBlock.Cmp{
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
                                 .rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14566,7 +14555,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .@"fcmp fast une",
                         .@"fcmp fast uno",
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Binary, data);
                             try function_block.writeAbbrev(FunctionBlock.CmpFast{
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
                                 .rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14575,14 +14564,14 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{
-                            .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
+                            .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
                         }),
                         .@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{
-                            .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
+                            .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
                             .fast_math = FastMath.fast,
                         }),
                         .extractvalue => {
-                            var extra = func.extraDataTrail(Function.Instruction.ExtractValue, datas[instr_index]);
+                            var extra = func.extraDataTrail(Function.Instruction.ExtractValue, data);
                             const indices = extra.trail.next(extra.data.indices_len, u32, &func);
                             try function_block.writeAbbrev(FunctionBlock.ExtractValue{
                                 .val = adapter.getOffsetValueIndex(extra.data.val),
@@ -14590,7 +14579,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .insertvalue => {
-                            var extra = func.extraDataTrail(Function.Instruction.InsertValue, datas[instr_index]);
+                            var extra = func.extraDataTrail(Function.Instruction.InsertValue, data);
                             const indices = extra.trail.next(extra.data.indices_len, u32, &func);
                             try function_block.writeAbbrev(FunctionBlock.InsertValue{
                                 .val = adapter.getOffsetValueIndex(extra.data.val),
@@ -14599,14 +14588,14 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .extractelement => {
-                            const extra = func.extraData(Function.Instruction.ExtractElement, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.ExtractElement, data);
                             try function_block.writeAbbrev(FunctionBlock.ExtractElement{
                                 .val = adapter.getOffsetValueIndex(extra.val),
                                 .index = adapter.getOffsetValueIndex(extra.index),
                             });
                         },
                         .insertelement => {
-                            const extra = func.extraData(Function.Instruction.InsertElement, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.InsertElement, data);
                             try function_block.writeAbbrev(FunctionBlock.InsertElement{
                                 .val = adapter.getOffsetValueIndex(extra.val),
                                 .elem = adapter.getOffsetValueIndex(extra.elem),
@@ -14614,7 +14603,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .select => {
-                            const extra = func.extraData(Function.Instruction.Select, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Select, data);
                             try function_block.writeAbbrev(FunctionBlock.Select{
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
                                 .rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14622,7 +14611,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .@"select fast" => {
-                            const extra = func.extraData(Function.Instruction.Select, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Select, data);
                             try function_block.writeAbbrev(FunctionBlock.SelectFast{
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
                                 .rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14631,7 +14620,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .shufflevector => {
-                            const extra = func.extraData(Function.Instruction.ShuffleVector, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.ShuffleVector, data);
                             try function_block.writeAbbrev(FunctionBlock.ShuffleVector{
                                 .lhs = adapter.getOffsetValueIndex(extra.lhs),
                                 .rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14641,7 +14630,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .getelementptr,
                         .@"getelementptr inbounds",
                         => |kind| {
-                            var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, datas[instr_index]);
+                            var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, data);
                             const indices = extra.trail.next(extra.data.indices_len, Value, &func);
                             try function_block.writeAbbrevAdapted(
                                 FunctionBlock.GetElementPtr{
@@ -14654,7 +14643,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             );
                         },
                         .load => {
-                            const extra = func.extraData(Function.Instruction.Load, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Load, data);
                             try function_block.writeAbbrev(FunctionBlock.Load{
                                 .ptr = adapter.getOffsetValueIndex(extra.ptr),
                                 .ty = extra.type,
@@ -14663,7 +14652,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .@"load atomic" => {
-                            const extra = func.extraData(Function.Instruction.Load, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Load, data);
                             try function_block.writeAbbrev(FunctionBlock.LoadAtomic{
                                 .ptr = adapter.getOffsetValueIndex(extra.ptr),
                                 .ty = extra.type,
@@ -14674,7 +14663,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .store => {
-                            const extra = func.extraData(Function.Instruction.Store, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Store, data);
                             try function_block.writeAbbrev(FunctionBlock.Store{
                                 .ptr = adapter.getOffsetValueIndex(extra.ptr),
                                 .val = adapter.getOffsetValueIndex(extra.val),
@@ -14683,7 +14672,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .@"store atomic" => {
-                            const extra = func.extraData(Function.Instruction.Store, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.Store, data);
                             try function_block.writeAbbrev(FunctionBlock.StoreAtomic{
                                 .ptr = adapter.getOffsetValueIndex(extra.ptr),
                                 .val = adapter.getOffsetValueIndex(extra.val),
@@ -14695,11 +14684,11 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         },
                         .br => {
                             try function_block.writeAbbrev(FunctionBlock.BrUnconditional{
-                                .block = datas[instr_index],
+                                .block = data,
                             });
                         },
                         .br_cond => {
-                            const extra = func.extraData(Function.Instruction.BrCond, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.BrCond, data);
                             try function_block.writeAbbrev(FunctionBlock.BrConditional{
                                 .then_block = @intFromEnum(extra.then),
                                 .else_block = @intFromEnum(extra.@"else"),
@@ -14707,7 +14696,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .@"switch" => {
-                            var extra = func.extraDataTrail(Function.Instruction.Switch, datas[instr_index]);
+                            var extra = func.extraDataTrail(Function.Instruction.Switch, data);
 
                             try record.ensureUnusedCapacity(self.gpa, 3 + extra.data.cases_len * 2);
 
@@ -14730,7 +14719,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             try function_block.writeUnabbrev(12, record.items);
                         },
                         .va_arg => {
-                            const extra = func.extraData(Function.Instruction.VaArg, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.VaArg, data);
                             try function_block.writeAbbrev(FunctionBlock.VaArg{
                                 .list_type = extra.list.typeOf(@enumFromInt(func_index), self),
                                 .list = adapter.getOffsetValueIndex(extra.list),
@@ -14740,7 +14729,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .phi,
                         .@"phi fast",
                         => |kind| {
-                            var extra = func.extraDataTrail(Function.Instruction.Phi, datas[instr_index]);
+                            var extra = func.extraDataTrail(Function.Instruction.Phi, data);
                             const vals = extra.trail.next(block_incoming_len, Value, &func);
                             const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &func);
 
@@ -14764,11 +14753,11 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             try function_block.writeUnabbrev(16, record.items);
                         },
                         .ret => try function_block.writeAbbrev(FunctionBlock.Ret{
-                            .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
+                            .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
                         }),
                         .@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}),
                         .atomicrmw => {
-                            const extra = func.extraData(Function.Instruction.AtomicRmw, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.AtomicRmw, data);
                             try function_block.writeAbbrev(FunctionBlock.AtomicRmw{
                                 .ptr = adapter.getOffsetValueIndex(extra.ptr),
                                 .val = adapter.getOffsetValueIndex(extra.val),
@@ -14782,7 +14771,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         .cmpxchg,
                         .@"cmpxchg weak",
                         => |kind| {
-                            const extra = func.extraData(Function.Instruction.CmpXchg, datas[instr_index]);
+                            const extra = func.extraData(Function.Instruction.CmpXchg, data);
 
                             try function_block.writeAbbrev(FunctionBlock.CmpXchg{
                                 .ptr = adapter.getOffsetValueIndex(extra.ptr),
@@ -14797,7 +14786,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             });
                         },
                         .fence => {
-                            const info: MemoryAccessInfo = @bitCast(datas[instr_index]);
+                            const info: MemoryAccessInfo = @bitCast(data);
                             try function_block.writeAbbrev(FunctionBlock.Fence{
                                 .ordering = info.success_ordering,
                                 .sync_scope = info.sync_scope,
@@ -14806,7 +14795,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                     }
 
                     if (!func.strip) {
-                        if (func.debug_locations.get(@enumFromInt(instr_index))) |debug_location| {
+                        if (func.debug_locations.get(adapter.instruction_index)) |debug_location| {
                             switch (debug_location) {
                                 .no_location => has_location = false,
                                 .location => |location| {
@@ -14823,8 +14812,6 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                             try function_block.writeAbbrev(FunctionBlock.DebugLocAgain{});
                         }
                     }
-
-                    adapter.next();
                 }
 
                 // VALUE_SYMTAB
@@ -14850,18 +14837,32 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                 }
 
                 // METADATA_ATTACHMENT_BLOCK
-                if (!func.strip) blk: {
-                    const dbg = func.global.ptrConst(self).dbg;
-
-                    if (dbg == .none) break :blk;
-
+                const any_nosanitize = true;
+                if (!func.strip or any_nosanitize) {
                     const MetadataAttachmentBlock = ir.MetadataAttachmentBlock;
                     var metadata_attach_block = try function_block.enterSubBlock(MetadataAttachmentBlock, false);
 
-                    try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentSingle{
-                        .kind = ir.MetadataKind.dbg,
-                        .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(dbg) - 1),
-                    });
+                    if (!func.strip) blk: {
+                        const dbg = func.global.ptrConst(self).dbg;
+                        if (dbg == .none) break :blk;
+                        try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentGlobalSingle{
+                            .kind = .dbg,
+                            .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(dbg) - 1),
+                        });
+                    }
+
+                    var instr_index: u32 = 0;
+                    for (func.instructions.items(.tag)) |instr_tag| switch (instr_tag) {
+                        .arg, .block => {},
+                        else => {
+                            try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentInstructionSingle{
+                                .inst = instr_index,
+                                .kind = .nosanitize,
+                                .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(.empty_tuple) - 1),
+                            });
+                            instr_index += 1;
+                        },
+                    };
 
                     try metadata_attach_block.end();
                 }
src/codegen/llvm/ir.zig
@@ -20,8 +20,142 @@ const ColumnAbbrev = AbbrevOp{ .vbr = 8 };
 
 const BlockAbbrev = AbbrevOp{ .vbr = 6 };
 
-pub const MetadataKind = enum(u1) {
+/// Unused tags are commented out so that they are omitted in the generated
+/// bitcode, which scans over this enum using reflection.
+pub const FixedMetadataKind = enum(u8) {
     dbg = 0,
+    //tbaa = 1,
+    //prof = 2,
+    //fpmath = 3,
+    //range = 4,
+    //@"tbaa.struct" = 5,
+    //@"invariant.load" = 6,
+    //@"alias.scope" = 7,
+    //@"noalias" = 8,
+    //nontemporal = 9,
+    //@"llvm.mem.parallel_loop_access" = 10,
+    //nonnull = 11,
+    //dereferenceable = 12,
+    //dereferenceable_or_null = 13,
+    //@"make.implicit" = 14,
+    //unpredictable = 15,
+    //@"invariant.group" = 16,
+    //@"align" = 17,
+    //@"llvm.loop" = 18,
+    //type = 19,
+    //section_prefix = 20,
+    //absolute_symbol = 21,
+    //associated = 22,
+    //callees = 23,
+    //irr_loop = 24,
+    //@"llvm.access.group" = 25,
+    //callback = 26,
+    //@"llvm.preserve.access.index" = 27,
+    //vcall_visibility = 28,
+    //noundef = 29,
+    //annotation = 30,
+    nosanitize = 31,
+    //func_sanitize = 32,
+    //exclude = 33,
+    //memprof = 34,
+    //callsite = 35,
+    //kcfi_type = 36,
+    //pcsections = 37,
+    //DIAssignID = 38,
+    //@"coro.outside.frame" = 39,
+};
+
+pub const MetadataCode = enum(u8) {
+    /// MDSTRING:      [values]
+    STRING_OLD = 1,
+    /// VALUE:         [type num, value num]
+    VALUE = 2,
+    /// NODE:          [n x md num]
+    NODE = 3,
+    /// STRING:        [values]
+    NAME = 4,
+    /// DISTINCT_NODE: [n x md num]
+    DISTINCT_NODE = 5,
+    /// [n x [id, name]]
+    KIND = 6,
+    /// [distinct, line, col, scope, inlined-at?]
+    LOCATION = 7,
+    /// OLD_NODE:      [n x (type num, value num)]
+    OLD_NODE = 8,
+    /// OLD_FN_NODE:   [n x (type num, value num)]
+    OLD_FN_NODE = 9,
+    /// NAMED_NODE:    [n x mdnodes]
+    NAMED_NODE = 10,
+    /// [m x [value, [n x [id, mdnode]]]
+    ATTACHMENT = 11,
+    /// [distinct, tag, vers, header, n x md num]
+    GENERIC_DEBUG = 12,
+    /// [distinct, count, lo]
+    SUBRANGE = 13,
+    /// [isUnsigned|distinct, value, name]
+    ENUMERATOR = 14,
+    /// [distinct, tag, name, size, align, enc]
+    BASIC_TYPE = 15,
+    /// [distinct, filename, directory, checksumkind, checksum]
+    FILE = 16,
+    /// [distinct, ...]
+    DERIVED_TYPE = 17,
+    /// [distinct, ...]
+    COMPOSITE_TYPE = 18,
+    /// [distinct, flags, types, cc]
+    SUBROUTINE_TYPE = 19,
+    /// [distinct, ...]
+    COMPILE_UNIT = 20,
+    /// [distinct, ...]
+    SUBPROGRAM = 21,
+    /// [distinct, scope, file, line, column]
+    LEXICAL_BLOCK = 22,
+    ///[distinct, scope, file, discriminator]
+    LEXICAL_BLOCK_FILE = 23,
+    /// [distinct, scope, file, name, line, exportSymbols]
+    NAMESPACE = 24,
+    /// [distinct, scope, name, type, ...]
+    TEMPLATE_TYPE = 25,
+    /// [distinct, scope, name, type, value, ...]
+    TEMPLATE_VALUE = 26,
+    /// [distinct, ...]
+    GLOBAL_VAR = 27,
+    /// [distinct, ...]
+    LOCAL_VAR = 28,
+    /// [distinct, n x element]
+    EXPRESSION = 29,
+    /// [distinct, name, file, line, ...]
+    OBJC_PROPERTY = 30,
+    /// [distinct, tag, scope, entity, line, name]
+    IMPORTED_ENTITY = 31,
+    /// [distinct, scope, name, ...]
+    MODULE = 32,
+    /// [distinct, macinfo, line, name, value]
+    MACRO = 33,
+    /// [distinct, macinfo, line, file, ...]
+    MACRO_FILE = 34,
+    /// [count, offset] blob([lengths][chars])
+    STRINGS = 35,
+    /// [valueid, n x [id, mdnode]]
+    GLOBAL_DECL_ATTACHMENT = 36,
+    /// [distinct, var, expr]
+    GLOBAL_VAR_EXPR = 37,
+    /// [offset]
+    INDEX_OFFSET = 38,
+    /// [bitpos]
+    INDEX = 39,
+    /// [distinct, scope, name, file, line]
+    LABEL = 40,
+    /// [distinct, name, size, align,...]
+    STRING_TYPE = 41,
+    /// [distinct, scope, name, variable,...]
+    COMMON_BLOCK = 44,
+    /// [distinct, count, lo, up, stride]
+    GENERIC_SUBRANGE = 45,
+    /// [n x [type num, value num]]
+    ARG_LIST = 46,
+    /// [distinct, ...]
+    ASSIGN_ID = 47,
 };
 
 pub const Identification = struct {
@@ -622,16 +756,29 @@ pub const MetadataAttachmentBlock = struct {
     pub const id = 16;
 
     pub const abbrevs = [_]type{
-        AttachmentSingle,
+        AttachmentGlobalSingle,
+        AttachmentInstructionSingle,
     };
 
-    pub const AttachmentSingle = struct {
+    pub const AttachmentGlobalSingle = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 11 },
+            .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
             .{ .fixed = 1 },
             MetadataAbbrev,
         };
-        kind: MetadataKind,
+        kind: FixedMetadataKind,
+        metadata: Builder.Metadata,
+    };
+
+    pub const AttachmentInstructionSingle = struct {
+        pub const ops = [_]AbbrevOp{
+            .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
+            ValueAbbrev,
+            .{ .fixed = 5 },
+            MetadataAbbrev,
+        };
+        inst: u32,
+        kind: FixedMetadataKind,
         metadata: Builder.Metadata,
     };
 };
@@ -666,7 +813,7 @@ pub const MetadataBlock = struct {
 
     pub const Strings = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 35 },
+            .{ .literal = @intFromEnum(MetadataCode.STRINGS) },
             .{ .vbr = 6 },
             .{ .vbr = 6 },
             .blob,
@@ -678,7 +825,7 @@ pub const MetadataBlock = struct {
 
     pub const File = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 16 },
+            .{ .literal = @intFromEnum(MetadataCode.FILE) },
             .{ .literal = 0 }, // is distinct
             MetadataAbbrev, // filename
             MetadataAbbrev, // directory
@@ -692,7 +839,7 @@ pub const MetadataBlock = struct {
 
     pub const CompileUnit = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 20 },
+            .{ .literal = @intFromEnum(MetadataCode.COMPILE_UNIT) },
             .{ .literal = 1 }, // is distinct
             .{ .literal = std.dwarf.LANG.C99 }, // source language
             MetadataAbbrev, // file
@@ -726,7 +873,7 @@ pub const MetadataBlock = struct {
 
     pub const Subprogram = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 21 },
+            .{ .literal = @intFromEnum(MetadataCode.SUBPROGRAM) },
             .{ .literal = 0b111 }, // is distinct | has sp flags | has flags
             MetadataAbbrev, // scope
             MetadataAbbrev, // name
@@ -763,7 +910,7 @@ pub const MetadataBlock = struct {
 
     pub const LexicalBlock = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 22 },
+            .{ .literal = @intFromEnum(MetadataCode.LEXICAL_BLOCK) },
             .{ .literal = 0 }, // is distinct
             MetadataAbbrev, // scope
             MetadataAbbrev, // file
@@ -779,7 +926,7 @@ pub const MetadataBlock = struct {
 
     pub const Location = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 7 },
+            .{ .literal = @intFromEnum(MetadataCode.LOCATION) },
             .{ .literal = 0 }, // is distinct
             LineAbbrev, // line
             ColumnAbbrev, // column
@@ -796,7 +943,7 @@ pub const MetadataBlock = struct {
 
     pub const BasicType = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 15 },
+            .{ .literal = @intFromEnum(MetadataCode.BASIC_TYPE) },
             .{ .literal = 0 }, // is distinct
             .{ .literal = std.dwarf.TAG.base_type }, // tag
             MetadataAbbrev, // name
@@ -813,7 +960,7 @@ pub const MetadataBlock = struct {
 
     pub const CompositeType = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 18 },
+            .{ .literal = @intFromEnum(MetadataCode.COMPOSITE_TYPE) },
             .{ .literal = 0 | 0x2 }, // is distinct | is not used in old type ref
             .{ .fixed = 32 }, // tag
             MetadataAbbrev, // name
@@ -852,7 +999,7 @@ pub const MetadataBlock = struct {
 
     pub const DerivedType = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 17 },
+            .{ .literal = @intFromEnum(MetadataCode.DERIVED_TYPE) },
             .{ .literal = 0 }, // is distinct
             .{ .fixed = 32 }, // tag
             MetadataAbbrev, // name
@@ -880,7 +1027,7 @@ pub const MetadataBlock = struct {
 
     pub const SubroutineType = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 19 },
+            .{ .literal = @intFromEnum(MetadataCode.SUBROUTINE_TYPE) },
             .{ .literal = 0 | 0x2 }, // is distinct | has no old type refs
             .{ .literal = 0 }, // flags
             MetadataAbbrev, // types
@@ -891,7 +1038,7 @@ pub const MetadataBlock = struct {
     };
 
     pub const Enumerator = struct {
-        pub const id = 14;
+        pub const id: MetadataCode = .ENUMERATOR;
 
         pub const Flags = packed struct(u3) {
             distinct: bool = false,
@@ -900,7 +1047,7 @@ pub const MetadataBlock = struct {
         };
 
         pub const ops = [_]AbbrevOp{
-            .{ .literal = Enumerator.id },
+            .{ .literal = @intFromEnum(Enumerator.id) },
             .{ .fixed = @bitSizeOf(Flags) }, // flags
             .{ .vbr = 6 }, // bit width
             MetadataAbbrev, // name
@@ -915,7 +1062,7 @@ pub const MetadataBlock = struct {
 
     pub const Subrange = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 13 },
+            .{ .literal = @intFromEnum(MetadataCode.SUBRANGE) },
             .{ .literal = 0b10 }, // is distinct | version
             MetadataAbbrev, // count
             MetadataAbbrev, // lower bound
@@ -929,7 +1076,7 @@ pub const MetadataBlock = struct {
 
     pub const Expression = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 29 },
+            .{ .literal = @intFromEnum(MetadataCode.EXPRESSION) },
             .{ .literal = 0 | (3 << 1) }, // is distinct | version
             MetadataArrayAbbrev, // elements
         };
@@ -939,7 +1086,7 @@ pub const MetadataBlock = struct {
 
     pub const Node = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 3 },
+            .{ .literal = @intFromEnum(MetadataCode.NODE) },
             MetadataArrayAbbrev, // elements
         };
 
@@ -948,7 +1095,7 @@ pub const MetadataBlock = struct {
 
     pub const LocalVar = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 28 },
+            .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
             .{ .literal = 0b10 }, // is distinct | has alignment
             MetadataAbbrev, // scope
             MetadataAbbrev, // name
@@ -970,7 +1117,7 @@ pub const MetadataBlock = struct {
 
     pub const Parameter = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 28 },
+            .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
             .{ .literal = 0b10 }, // is distinct | has alignment
             MetadataAbbrev, // scope
             MetadataAbbrev, // name
@@ -993,7 +1140,7 @@ pub const MetadataBlock = struct {
 
     pub const GlobalVar = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 27 },
+            .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR) },
             .{ .literal = 0b101 }, // is distinct | version
             MetadataAbbrev, // scope
             MetadataAbbrev, // name
@@ -1020,7 +1167,7 @@ pub const MetadataBlock = struct {
 
     pub const GlobalVarExpression = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 37 },
+            .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR_EXPR) },
             .{ .literal = 0 }, // is distinct
             MetadataAbbrev, // variable
             MetadataAbbrev, // expression
@@ -1032,7 +1179,7 @@ pub const MetadataBlock = struct {
 
     pub const Constant = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 2 },
+            .{ .literal = @intFromEnum(MetadataCode.VALUE) },
             MetadataAbbrev, // type
             MetadataAbbrev, // value
         };
@@ -1043,7 +1190,7 @@ pub const MetadataBlock = struct {
 
     pub const Name = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 4 },
+            .{ .literal = @intFromEnum(MetadataCode.NAME) },
             .{ .array_fixed = 8 }, // name
         };
 
@@ -1052,7 +1199,7 @@ pub const MetadataBlock = struct {
 
     pub const NamedNode = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 10 },
+            .{ .literal = @intFromEnum(MetadataCode.NAMED_NODE) },
             MetadataArrayAbbrev, // elements
         };
 
@@ -1061,14 +1208,14 @@ pub const MetadataBlock = struct {
 
     pub const GlobalDeclAttachment = struct {
         pub const ops = [_]AbbrevOp{
-            .{ .literal = 36 },
+            .{ .literal = @intFromEnum(MetadataCode.GLOBAL_DECL_ATTACHMENT) },
             ValueAbbrev, // value id
             .{ .fixed = 1 }, // kind
             MetadataAbbrev, // elements
         };
 
         value: Builder.Constant,
-        kind: MetadataKind,
+        kind: FixedMetadataKind,
         metadata: Builder.Metadata,
     };
 };