Commit 49ad51b2fe

Jacob Young <jacobly0@users.noreply.github.com>
2024-04-28 19:13:40
Builder: add `indirectbr` llvm instruction
1 parent 28383d4
Changed files (2)
src
codegen
src/codegen/llvm/Builder.zig
@@ -4157,6 +4157,7 @@ pub const Function = struct {
             @"icmp ugt",
             @"icmp ule",
             @"icmp ult",
+            indirectbr,
             insertelement,
             insertvalue,
             inttoptr,
@@ -4367,6 +4368,7 @@ pub const Function = struct {
                 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
                     .br,
                     .br_cond,
+                    .indirectbr,
                     .ret,
                     .@"ret void",
                     .@"switch",
@@ -4381,6 +4383,7 @@ pub const Function = struct {
                     .br,
                     .br_cond,
                     .fence,
+                    .indirectbr,
                     .ret,
                     .@"ret void",
                     .store,
@@ -4471,6 +4474,7 @@ pub const Function = struct {
                     .br,
                     .br_cond,
                     .fence,
+                    .indirectbr,
                     .ret,
                     .@"ret void",
                     .store,
@@ -4657,6 +4661,7 @@ pub const Function = struct {
                     .br,
                     .br_cond,
                     .fence,
+                    .indirectbr,
                     .ret,
                     .@"ret void",
                     .store,
@@ -4837,6 +4842,12 @@ pub const Function = struct {
             //case_blocks: [cases_len]Block.Index,
         };
 
+        pub const IndirectBr = struct {
+            addr: Value,
+            targets_len: u32,
+            //targets: [targets_len]Block.Index,
+        };
+
         pub const Binary = struct {
             lhs: Value,
             rhs: Value,
@@ -5294,10 +5305,27 @@ pub const WipFunction = struct {
         return .{ .index = 0, .instruction = instruction };
     }
 
+    pub fn indirectbr(
+        self: *WipFunction,
+        addr: Value,
+        targets: []const Block.Index,
+    ) Allocator.Error!Instruction.Index {
+        try self.ensureUnusedExtraCapacity(1, Instruction.IndirectBr, targets.len);
+        const instruction = try self.addInst(null, .{
+            .tag = .indirectbr,
+            .data = self.addExtraAssumeCapacity(Instruction.IndirectBr{
+                .addr = addr,
+                .targets_len = @intCast(targets.len),
+            }),
+        });
+        _ = self.extra.appendSliceAssumeCapacity(@ptrCast(targets));
+        for (targets) |target| target.ptr(self).branches += 1;
+        return instruction;
+    }
+
     pub fn @"unreachable"(self: *WipFunction) Allocator.Error!Instruction.Index {
         try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
-        const instruction = try self.addInst(null, .{ .tag = .@"unreachable", .data = undefined });
-        return instruction;
+        return try self.addInst(null, .{ .tag = .@"unreachable", .data = undefined });
     }
 
     pub fn un(
@@ -6299,8 +6327,7 @@ pub const WipFunction = struct {
             });
             names[@intFromEnum(new_block_index)] = try wip_name.map(current_block.name, "");
             for (current_block.instructions.items) |old_instruction_index| {
-                const new_instruction_index: Instruction.Index =
-                    @enumFromInt(function.instructions.len);
+                const new_instruction_index: Instruction.Index = @enumFromInt(function.instructions.len);
                 var instruction = self.instructions.get(@intFromEnum(old_instruction_index));
                 switch (instruction.tag) {
                     .add,
@@ -6509,6 +6536,15 @@ pub const WipFunction = struct {
                         });
                         wip_extra.appendMappedValues(indices, instructions);
                     },
+                    .indirectbr => {
+                        var extra = self.extraDataTrail(Instruction.IndirectBr, instruction.data);
+                        const targets = extra.trail.next(extra.data.targets_len, Block.Index, self);
+                        instruction.data = wip_extra.addExtra(Instruction.IndirectBr{
+                            .addr = instructions.map(extra.data.addr),
+                            .targets_len = extra.data.targets_len,
+                        });
+                        wip_extra.appendSlice(targets);
+                    },
                     .insertelement => {
                         const extra = self.extraData(Instruction.InsertElement, instruction.data);
                         instruction.data = wip_extra.addExtra(Instruction.InsertElement{
@@ -7555,10 +7591,10 @@ pub const Constant = enum(u32) {
                     .blockaddress => |tag| {
                         const extra = data.builder.constantExtraData(BlockAddress, item.data);
                         const function = extra.function.ptrConst(data.builder);
-                        try writer.print("{s}({}, %{d})", .{
+                        try writer.print("{s}({}, {})", .{
                             @tagName(tag),
                             function.global.fmt(data.builder),
-                            @intFromEnum(extra.block), // TODO
+                            extra.block.toInst(function).fmt(extra.function, data.builder),
                         });
                     },
                     .dso_local_equivalent,
@@ -9902,6 +9938,23 @@ pub fn printUnbuffered(
                             index.fmt(function_index, self),
                         });
                     },
+                    .indirectbr => |tag| {
+                        var extra =
+                            function.extraDataTrail(Function.Instruction.IndirectBr, instruction.data);
+                        const targets =
+                            extra.trail.next(extra.data.targets_len, Function.Block.Index, &function);
+                        try writer.print("  {s} {%}, [", .{
+                            @tagName(tag),
+                            extra.data.addr.fmt(function_index, self),
+                        });
+                        for (0.., targets) |target_index, target| {
+                            if (target_index > 0) try writer.writeAll(", ");
+                            try writer.print("{%}", .{
+                                target.toInst(&function).fmt(function_index, self),
+                            });
+                        }
+                        try writer.writeByte(']');
+                    },
                     .insertelement => |tag| {
                         const extra =
                             function.extraData(Function.Instruction.InsertElement, instruction.data);
@@ -14777,15 +14830,6 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                                 .indices = indices,
                             });
                         },
-                        .insertvalue => {
-                            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),
-                                .elem = adapter.getOffsetValueIndex(extra.data.elem),
-                                .indices = indices,
-                            });
-                        },
                         .extractelement => {
                             const extra = func.extraData(Function.Instruction.ExtractElement, data);
                             try function_block.writeAbbrev(FunctionBlock.ExtractElement{
@@ -14793,6 +14837,20 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                                 .index = adapter.getOffsetValueIndex(extra.index),
                             });
                         },
+                        .indirectbr => {
+                            var extra =
+                                func.extraDataTrail(Function.Instruction.IndirectBr, datas[instr_index]);
+                            const targets =
+                                extra.trail.next(extra.data.targets_len, Function.Block.Index, &func);
+                            try function_block.writeAbbrevAdapted(
+                                FunctionBlock.IndirectBr{
+                                    .ty = extra.data.addr.typeOf(@enumFromInt(func_index), self),
+                                    .addr = extra.data.addr,
+                                    .targets = targets,
+                                },
+                                adapter,
+                            );
+                        },
                         .insertelement => {
                             const extra = func.extraData(Function.Instruction.InsertElement, data);
                             try function_block.writeAbbrev(FunctionBlock.InsertElement{
@@ -14801,6 +14859,15 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                                 .index = adapter.getOffsetValueIndex(extra.index),
                             });
                         },
+                        .insertvalue => {
+                            var extra = func.extraDataTrail(Function.Instruction.InsertValue, datas[instr_index]);
+                            const indices = extra.trail.next(extra.data.indices_len, u32, &func);
+                            try function_block.writeAbbrev(FunctionBlock.InsertValue{
+                                .val = adapter.getOffsetValueIndex(extra.data.val),
+                                .elem = adapter.getOffsetValueIndex(extra.data.elem),
+                                .indices = indices,
+                            });
+                        },
                         .select => {
                             const extra = func.extraData(Function.Instruction.Select, data);
                             try function_block.writeAbbrev(FunctionBlock.Select{
src/codegen/llvm/ir.zig
@@ -19,6 +19,7 @@ const LineAbbrev = AbbrevOp{ .vbr = 8 };
 const ColumnAbbrev = AbbrevOp{ .vbr = 8 };
 
 const BlockAbbrev = AbbrevOp{ .vbr = 6 };
+const BlockArrayAbbrev = AbbrevOp{ .array_vbr = 6 };
 
 /// Unused tags are commented out so that they are omitted in the generated
 /// bitcode, which scans over this enum using reflection.
@@ -1294,6 +1295,7 @@ pub const FunctionBlock = struct {
         DebugLoc,
         DebugLocAgain,
         ColdOperandBundle,
+        IndirectBr,
     };
 
     pub const DeclareBlocks = struct {
@@ -1813,6 +1815,18 @@ pub const FunctionBlock = struct {
             .{ .literal = 0 },
         };
     };
+
+    pub const IndirectBr = struct {
+        pub const ops = [_]AbbrevOp{
+            .{ .literal = 31 },
+            .{ .fixed_runtime = Builder.Type },
+            ValueAbbrev,
+            BlockArrayAbbrev,
+        };
+        ty: Builder.Type,
+        addr: Builder.Value,
+        targets: []const Builder.Function.Block.Index,
+    };
 };
 
 pub const FunctionValueSymbolTable = struct {