authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-02-24 12:35:40+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-27 01:32:49-05:00
log5c44934e20fedb29b88616f51de70c92e5d4ba42
tree467f18b43b38aff31a089685fb2ba4f9cf4d7a8e
parentdea72d15da4fba909dc3ccb2e9dc5286372ac023

Move the compiler's LLVM bitcode builder to std.zig.llvm.


14 files changed, 18056 insertions(+), 18044 deletions(-)

CMakeLists.txt+5-4
......@@ -500,6 +500,11 @@ set(ZIG_STAGE2_SOURCES
500500 lib/std/zig/system/NativePaths.zig
501501 lib/std/zig/system/x86.zig
502502 lib/std/zig/tokenizer.zig
503 lib/std/zig/llvm.zig
504 lib/std/zig/llvm/BitcodeReader.zig
505 lib/std/zig/llvm/Builder.zig
506 lib/std/zig/llvm/bitcode_writer.zig
507 lib/std/zig/llvm/ir.zig
503508 src/Air.zig
504509 src/Builtin.zig
505510 src/Compilation.zig
......@@ -567,11 +572,7 @@ set(ZIG_STAGE2_SOURCES
567572 src/codegen/c.zig
568573 src/codegen/c/Type.zig
569574 src/codegen/llvm.zig
570 src/codegen/llvm/BitcodeReader.zig
571 src/codegen/llvm/Builder.zig
572575 src/codegen/llvm/bindings.zig
573 src/codegen/llvm/bitcode_writer.zig
574 src/codegen/llvm/ir.zig
575576 src/codegen/spirv.zig
576577 src/codegen/spirv/Assembler.zig
577578 src/codegen/spirv/Module.zig
lib/std/zig.zig+1
......@@ -24,6 +24,7 @@ pub const LibCInstallation = @import("zig/LibCInstallation.zig");
2424pub const WindowsSdk = @import("zig/WindowsSdk.zig");
2525pub const LibCDirs = @import("zig/LibCDirs.zig");
2626pub const target = @import("zig/target.zig");
27pub const llvm = @import("zig/llvm.zig");
2728
2829// Character literal parsing
2930pub const ParsedCharLiteral = string_literal.ParsedCharLiteral;
lib/std/zig/llvm.zig created+3
......@@ -0,0 +1,3 @@
1pub const BitcodeReader = @import("llvm/BitcodeReader.zig");
2pub const bitcode_writer = @import("llvm/bitcode_writer.zig");
3pub const Builder = @import("llvm/Builder.zig");
lib/std/zig/llvm/BitcodeReader.zig created+515
......@@ -0,0 +1,515 @@
1allocator: std.mem.Allocator,
2record_arena: std.heap.ArenaAllocator.State,
3reader: std.io.AnyReader,
4keep_names: bool,
5bit_buffer: u32,
6bit_offset: u5,
7stack: std.ArrayListUnmanaged(State),
8block_info: std.AutoHashMapUnmanaged(u32, Block.Info),
9
10pub const Item = union(enum) {
11 start_block: Block,
12 record: Record,
13 end_block: Block,
14};
15
16pub const Block = struct {
17 name: []const u8,
18 id: u32,
19 len: u32,
20
21 const block_info: u32 = 0;
22 const first_reserved: u32 = 1;
23 const last_standard: u32 = 7;
24
25 const Info = struct {
26 block_name: []const u8,
27 record_names: std.AutoHashMapUnmanaged(u32, []const u8),
28 abbrevs: Abbrev.Store,
29
30 const default: Info = .{
31 .block_name = &.{},
32 .record_names = .{},
33 .abbrevs = .{ .abbrevs = .{} },
34 };
35
36 const set_bid_id: u32 = 1;
37 const block_name_id: u32 = 2;
38 const set_record_name_id: u32 = 3;
39
40 fn deinit(info: *Info, allocator: std.mem.Allocator) void {
41 allocator.free(info.block_name);
42 var record_names_it = info.record_names.valueIterator();
43 while (record_names_it.next()) |record_name| allocator.free(record_name.*);
44 info.record_names.deinit(allocator);
45 info.abbrevs.deinit(allocator);
46 info.* = undefined;
47 }
48 };
49};
50
51pub const Record = struct {
52 name: []const u8,
53 id: u32,
54 operands: []const u64,
55 blob: []const u8,
56
57 fn toOwnedAbbrev(record: Record, allocator: std.mem.Allocator) !Abbrev {
58 var operands = std.ArrayList(Abbrev.Operand).init(allocator);
59 defer operands.deinit();
60
61 assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId());
62 var i: usize = 0;
63 while (i < record.operands.len) switch (record.operands[i]) {
64 Abbrev.Operand.literal_id => {
65 try operands.append(.{ .literal = record.operands[i + 1] });
66 i += 2;
67 },
68 @intFromEnum(Abbrev.Operand.Encoding.fixed) => {
69 try operands.append(.{ .encoding = .{ .fixed = @intCast(record.operands[i + 1]) } });
70 i += 2;
71 },
72 @intFromEnum(Abbrev.Operand.Encoding.vbr) => {
73 try operands.append(.{ .encoding = .{ .vbr = @intCast(record.operands[i + 1]) } });
74 i += 2;
75 },
76 @intFromEnum(Abbrev.Operand.Encoding.array) => {
77 try operands.append(.{ .encoding = .{ .array = 6 } });
78 i += 1;
79 },
80 @intFromEnum(Abbrev.Operand.Encoding.char6) => {
81 try operands.append(.{ .encoding = .char6 });
82 i += 1;
83 },
84 @intFromEnum(Abbrev.Operand.Encoding.blob) => {
85 try operands.append(.{ .encoding = .{ .blob = 6 } });
86 i += 1;
87 },
88 else => unreachable,
89 };
90
91 return .{ .operands = try operands.toOwnedSlice() };
92 }
93};
94
95pub const InitOptions = struct {
96 reader: std.io.AnyReader,
97 keep_names: bool = false,
98};
99pub fn init(allocator: std.mem.Allocator, options: InitOptions) BitcodeReader {
100 return .{
101 .allocator = allocator,
102 .record_arena = .{},
103 .reader = options.reader,
104 .keep_names = options.keep_names,
105 .bit_buffer = 0,
106 .bit_offset = 0,
107 .stack = .{},
108 .block_info = .{},
109 };
110}
111
112pub fn deinit(bc: *BitcodeReader) void {
113 var block_info_it = bc.block_info.valueIterator();
114 while (block_info_it.next()) |block_info| block_info.deinit(bc.allocator);
115 bc.block_info.deinit(bc.allocator);
116 for (bc.stack.items) |*state| state.deinit(bc.allocator);
117 bc.stack.deinit(bc.allocator);
118 bc.record_arena.promote(bc.allocator).deinit();
119 bc.* = undefined;
120}
121
122pub fn checkMagic(bc: *BitcodeReader, magic: *const [4]u8) !void {
123 var buffer: [4]u8 = undefined;
124 try bc.readBytes(&buffer);
125 if (!std.mem.eql(u8, &buffer, magic)) return error.InvalidMagic;
126
127 try bc.startBlock(null, 2);
128 try bc.block_info.put(bc.allocator, Block.block_info, Block.Info.default);
129}
130
131pub fn next(bc: *BitcodeReader) !?Item {
132 while (true) {
133 const record = (try bc.nextRecord()) orelse
134 return if (bc.stack.items.len > 1) error.EndOfStream else null;
135 switch (record.id) {
136 else => return .{ .record = record },
137 Abbrev.Builtin.end_block.toRecordId() => {
138 const block_id = bc.stack.items[bc.stack.items.len - 1].block_id.?;
139 try bc.endBlock();
140 return .{ .end_block = .{
141 .name = if (bc.block_info.get(block_id)) |block_info|
142 block_info.block_name
143 else
144 &.{},
145 .id = block_id,
146 .len = 0,
147 } };
148 },
149 Abbrev.Builtin.enter_subblock.toRecordId() => {
150 const block_id: u32 = @intCast(record.operands[0]);
151 switch (block_id) {
152 Block.block_info => try bc.parseBlockInfoBlock(),
153 Block.first_reserved...Block.last_standard => return error.UnsupportedBlockId,
154 else => {
155 try bc.startBlock(block_id, @intCast(record.operands[1]));
156 return .{ .start_block = .{
157 .name = if (bc.block_info.get(block_id)) |block_info|
158 block_info.block_name
159 else
160 &.{},
161 .id = block_id,
162 .len = @intCast(record.operands[2]),
163 } };
164 },
165 }
166 },
167 Abbrev.Builtin.define_abbrev.toRecordId() => try bc.stack.items[bc.stack.items.len - 1]
168 .abbrevs.addOwnedAbbrev(bc.allocator, try record.toOwnedAbbrev(bc.allocator)),
169 }
170 }
171}
172
173pub fn skipBlock(bc: *BitcodeReader, block: Block) !void {
174 assert(bc.bit_offset == 0);
175 try bc.reader.skipBytes(@as(u34, block.len) * 4, .{});
176 try bc.endBlock();
177}
178
179fn nextRecord(bc: *BitcodeReader) !?Record {
180 const state = &bc.stack.items[bc.stack.items.len - 1];
181 const abbrev_id = bc.readFixed(u32, state.abbrev_id_width) catch |err| switch (err) {
182 error.EndOfStream => return null,
183 else => |e| return e,
184 };
185 if (abbrev_id >= state.abbrevs.abbrevs.items.len) return error.InvalidAbbrevId;
186 const abbrev = state.abbrevs.abbrevs.items[abbrev_id];
187
188 var record_arena = bc.record_arena.promote(bc.allocator);
189 defer bc.record_arena = record_arena.state;
190 _ = record_arena.reset(.retain_capacity);
191
192 var operands = try std.ArrayList(u64).initCapacity(record_arena.allocator(), abbrev.operands.len);
193 var blob = std.ArrayList(u8).init(record_arena.allocator());
194 for (abbrev.operands, 0..) |abbrev_operand, abbrev_operand_i| switch (abbrev_operand) {
195 .literal => |value| operands.appendAssumeCapacity(value),
196 .encoding => |abbrev_encoding| switch (abbrev_encoding) {
197 .fixed => |width| operands.appendAssumeCapacity(try bc.readFixed(u64, width)),
198 .vbr => |width| operands.appendAssumeCapacity(try bc.readVbr(u64, width)),
199 .array => |len_width| {
200 assert(abbrev_operand_i + 2 == abbrev.operands.len);
201 const len: usize = @intCast(try bc.readVbr(u32, len_width));
202 try operands.ensureUnusedCapacity(len);
203 for (0..len) |_| switch (abbrev.operands[abbrev.operands.len - 1]) {
204 .literal => |elem_value| operands.appendAssumeCapacity(elem_value),
205 .encoding => |elem_encoding| switch (elem_encoding) {
206 .fixed => |elem_width| operands.appendAssumeCapacity(try bc.readFixed(u64, elem_width)),
207 .vbr => |elem_width| operands.appendAssumeCapacity(try bc.readVbr(u64, elem_width)),
208 .array, .blob => return error.InvalidArrayElement,
209 .char6 => operands.appendAssumeCapacity(try bc.readChar6()),
210 },
211 .align_32_bits, .block_len => return error.UnsupportedArrayElement,
212 .abbrev_op => switch (try bc.readFixed(u1, 1)) {
213 1 => try operands.appendSlice(&.{
214 Abbrev.Operand.literal_id,
215 try bc.readVbr(u64, 8),
216 }),
217 0 => {
218 const encoding: Abbrev.Operand.Encoding =
219 @enumFromInt(try bc.readFixed(u3, 3));
220 try operands.append(@intFromEnum(encoding));
221 switch (encoding) {
222 .fixed, .vbr => try operands.append(try bc.readVbr(u7, 5)),
223 .array, .char6, .blob => {},
224 _ => return error.UnsuportedAbbrevEncoding,
225 }
226 },
227 },
228 };
229 break;
230 },
231 .char6 => operands.appendAssumeCapacity(try bc.readChar6()),
232 .blob => |len_width| {
233 assert(abbrev_operand_i + 1 == abbrev.operands.len);
234 const len = std.math.cast(usize, try bc.readVbr(u32, len_width)) orelse
235 return error.Overflow;
236 bc.align32Bits();
237 try bc.readBytes(try blob.addManyAsSlice(len));
238 bc.align32Bits();
239 },
240 },
241 .align_32_bits => bc.align32Bits(),
242 .block_len => operands.appendAssumeCapacity(try bc.read32Bits()),
243 .abbrev_op => unreachable,
244 };
245 return .{
246 .name = name: {
247 if (operands.items.len < 1) break :name &.{};
248 const record_id = std.math.cast(u32, operands.items[0]) orelse break :name &.{};
249 if (state.block_id) |block_id| {
250 if (bc.block_info.get(block_id)) |block_info| {
251 break :name block_info.record_names.get(record_id) orelse break :name &.{};
252 }
253 }
254 break :name &.{};
255 },
256 .id = std.math.cast(u32, operands.items[0]) orelse return error.InvalidRecordId,
257 .operands = operands.items[1..],
258 .blob = blob.items,
259 };
260}
261
262fn startBlock(bc: *BitcodeReader, block_id: ?u32, new_abbrev_len: u6) !void {
263 const abbrevs = if (block_id) |id|
264 if (bc.block_info.get(id)) |block_info| block_info.abbrevs.abbrevs.items else &.{}
265 else
266 &.{};
267
268 const state = try bc.stack.addOne(bc.allocator);
269 state.* = .{
270 .block_id = block_id,
271 .abbrev_id_width = new_abbrev_len,
272 .abbrevs = .{ .abbrevs = .{} },
273 };
274 try state.abbrevs.abbrevs.ensureTotalCapacity(
275 bc.allocator,
276 @typeInfo(Abbrev.Builtin).@"enum".fields.len + abbrevs.len,
277 );
278
279 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.end_block));
280 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
281 .operands = &.{
282 .{ .literal = Abbrev.Builtin.end_block.toRecordId() },
283 .align_32_bits,
284 },
285 });
286 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.enter_subblock));
287 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
288 .operands = &.{
289 .{ .literal = Abbrev.Builtin.enter_subblock.toRecordId() },
290 .{ .encoding = .{ .vbr = 8 } }, // blockid
291 .{ .encoding = .{ .vbr = 4 } }, // newabbrevlen
292 .align_32_bits,
293 .block_len,
294 },
295 });
296 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.define_abbrev));
297 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
298 .operands = &.{
299 .{ .literal = Abbrev.Builtin.define_abbrev.toRecordId() },
300 .{ .encoding = .{ .array = 5 } }, // numabbrevops
301 .abbrev_op,
302 },
303 });
304 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.unabbrev_record));
305 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
306 .operands = &.{
307 .{ .encoding = .{ .vbr = 6 } }, // code
308 .{ .encoding = .{ .array = 6 } }, // numops
309 .{ .encoding = .{ .vbr = 6 } }, // ops
310 },
311 });
312 assert(state.abbrevs.abbrevs.items.len == @typeInfo(Abbrev.Builtin).@"enum".fields.len);
313 for (abbrevs) |abbrev| try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, abbrev);
314}
315
316fn endBlock(bc: *BitcodeReader) !void {
317 if (bc.stack.items.len == 0) return error.InvalidEndBlock;
318 bc.stack.items[bc.stack.items.len - 1].deinit(bc.allocator);
319 bc.stack.items.len -= 1;
320}
321
322fn parseBlockInfoBlock(bc: *BitcodeReader) !void {
323 var block_id: ?u32 = null;
324 while (true) {
325 const record = (try bc.nextRecord()) orelse return error.EndOfStream;
326 switch (record.id) {
327 Abbrev.Builtin.end_block.toRecordId() => break,
328 Abbrev.Builtin.define_abbrev.toRecordId() => {
329 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
330 return error.UnspecifiedBlockId);
331 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
332 try gop.value_ptr.abbrevs.addOwnedAbbrev(
333 bc.allocator,
334 try record.toOwnedAbbrev(bc.allocator),
335 );
336 },
337 Block.Info.set_bid_id => block_id = std.math.cast(u32, record.operands[0]) orelse
338 return error.Overflow,
339 Block.Info.block_name_id => if (bc.keep_names) {
340 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
341 return error.UnspecifiedBlockId);
342 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
343 const name = try bc.allocator.alloc(u8, record.operands.len);
344 errdefer bc.allocator.free(name);
345 for (name, record.operands) |*byte, operand|
346 byte.* = std.math.cast(u8, operand) orelse return error.InvalidName;
347 gop.value_ptr.block_name = name;
348 },
349 Block.Info.set_record_name_id => if (bc.keep_names) {
350 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
351 return error.UnspecifiedBlockId);
352 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
353 const name = try bc.allocator.alloc(u8, record.operands.len - 1);
354 errdefer bc.allocator.free(name);
355 for (name, record.operands[1..]) |*byte, operand|
356 byte.* = std.math.cast(u8, operand) orelse return error.InvalidName;
357 try gop.value_ptr.record_names.put(
358 bc.allocator,
359 std.math.cast(u32, record.operands[0]) orelse return error.Overflow,
360 name,
361 );
362 },
363 else => return error.UnsupportedBlockInfoRecord,
364 }
365 }
366}
367
368fn align32Bits(bc: *BitcodeReader) void {
369 bc.bit_offset = 0;
370}
371
372fn read32Bits(bc: *BitcodeReader) !u32 {
373 assert(bc.bit_offset == 0);
374 return bc.reader.readInt(u32, .little);
375}
376
377fn readBytes(bc: *BitcodeReader, bytes: []u8) !void {
378 assert(bc.bit_offset == 0);
379 try bc.reader.readNoEof(bytes);
380
381 const trailing_bytes = bytes.len % 4;
382 if (trailing_bytes > 0) {
383 var bit_buffer = [1]u8{0} ** 4;
384 try bc.reader.readNoEof(bit_buffer[trailing_bytes..]);
385 bc.bit_buffer = std.mem.readInt(u32, &bit_buffer, .little);
386 bc.bit_offset = @intCast(trailing_bytes * 8);
387 }
388}
389
390fn readFixed(bc: *BitcodeReader, comptime T: type, bits: u7) !T {
391 var result: T = 0;
392 var shift: std.math.Log2IntCeil(T) = 0;
393 var remaining = bits;
394 while (remaining > 0) {
395 if (bc.bit_offset == 0) bc.bit_buffer = try bc.read32Bits();
396 const chunk_len = @min(@as(u6, 32) - bc.bit_offset, remaining);
397 const chunk_mask = @as(u32, std.math.maxInt(u32)) >> @intCast(32 - chunk_len);
398 result |= @as(T, @intCast(bc.bit_buffer >> bc.bit_offset & chunk_mask)) << @intCast(shift);
399 shift += @intCast(chunk_len);
400 remaining -= chunk_len;
401 bc.bit_offset = @truncate(bc.bit_offset + chunk_len);
402 }
403 return result;
404}
405
406fn readVbr(bc: *BitcodeReader, comptime T: type, bits: u7) !T {
407 const chunk_bits: u6 = @intCast(bits - 1);
408 const chunk_msb = @as(u64, 1) << chunk_bits;
409
410 var result: u64 = 0;
411 var shift: u6 = 0;
412 while (true) {
413 const chunk = try bc.readFixed(u64, bits);
414 result |= (chunk & (chunk_msb - 1)) << shift;
415 if (chunk & chunk_msb == 0) break;
416 shift += chunk_bits;
417 }
418 return @intCast(result);
419}
420
421fn readChar6(bc: *BitcodeReader) !u8 {
422 return switch (try bc.readFixed(u6, 6)) {
423 0...25 => |c| @as(u8, c - 0) + 'a',
424 26...51 => |c| @as(u8, c - 26) + 'A',
425 52...61 => |c| @as(u8, c - 52) + '0',
426 62 => '.',
427 63 => '_',
428 };
429}
430
431const State = struct {
432 block_id: ?u32,
433 abbrev_id_width: u6,
434 abbrevs: Abbrev.Store,
435
436 fn deinit(state: *State, allocator: std.mem.Allocator) void {
437 state.abbrevs.deinit(allocator);
438 state.* = undefined;
439 }
440};
441
442const Abbrev = struct {
443 operands: []const Operand,
444
445 const Builtin = enum(u2) {
446 end_block,
447 enter_subblock,
448 define_abbrev,
449 unabbrev_record,
450
451 const first_record_id: u32 = std.math.maxInt(u32) - @typeInfo(Builtin).@"enum".fields.len + 1;
452 fn toRecordId(builtin: Builtin) u32 {
453 return first_record_id + @intFromEnum(builtin);
454 }
455 };
456
457 const Operand = union(enum) {
458 literal: u64,
459 encoding: union(Encoding) {
460 fixed: u7,
461 vbr: u6,
462 array: u3,
463 char6,
464 blob: u3,
465 },
466 align_32_bits,
467 block_len,
468 abbrev_op,
469
470 const literal_id = std.math.maxInt(u64);
471 const Encoding = enum(u3) {
472 fixed = 1,
473 vbr = 2,
474 array = 3,
475 char6 = 4,
476 blob = 5,
477 _,
478 };
479 };
480
481 const Store = struct {
482 abbrevs: std.ArrayListUnmanaged(Abbrev),
483
484 fn deinit(store: *Store, allocator: std.mem.Allocator) void {
485 for (store.abbrevs.items) |abbrev| allocator.free(abbrev.operands);
486 store.abbrevs.deinit(allocator);
487 store.* = undefined;
488 }
489
490 fn addAbbrev(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void {
491 try store.ensureUnusedCapacity(allocator, 1);
492 store.addAbbrevAssumeCapacity(abbrev);
493 }
494
495 fn addAbbrevAssumeCapacity(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void {
496 store.abbrevs.appendAssumeCapacity(.{
497 .operands = try allocator.dupe(Abbrev.Operand, abbrev.operands),
498 });
499 }
500
501 fn addOwnedAbbrev(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void {
502 try store.abbrevs.ensureUnusedCapacity(allocator, 1);
503 store.addOwnedAbbrevAssumeCapacity(abbrev);
504 }
505
506 fn addOwnedAbbrevAssumeCapacity(store: *Store, abbrev: Abbrev) void {
507 store.abbrevs.appendAssumeCapacity(abbrev);
508 }
509 };
510};
511
512const assert = std.debug.assert;
513const std = @import("../../std.zig");
514
515const BitcodeReader = @This();
lib/std/zig/llvm/Builder.zig created+15230
......@@ -0,0 +1,15230 @@
1gpa: Allocator,
2strip: bool,
3
4source_filename: String,
5data_layout: String,
6target_triple: String,
7module_asm: std.ArrayListUnmanaged(u8),
8
9string_map: std.AutoArrayHashMapUnmanaged(void, void),
10string_indices: std.ArrayListUnmanaged(u32),
11string_bytes: std.ArrayListUnmanaged(u8),
12
13types: std.AutoArrayHashMapUnmanaged(String, Type),
14next_unnamed_type: String,
15next_unique_type_id: std.AutoHashMapUnmanaged(String, u32),
16type_map: std.AutoArrayHashMapUnmanaged(void, void),
17type_items: std.ArrayListUnmanaged(Type.Item),
18type_extra: std.ArrayListUnmanaged(u32),
19
20attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void),
21attributes_map: std.AutoArrayHashMapUnmanaged(void, void),
22attributes_indices: std.ArrayListUnmanaged(u32),
23attributes_extra: std.ArrayListUnmanaged(u32),
24
25function_attributes_set: std.AutoArrayHashMapUnmanaged(FunctionAttributes, void),
26
27globals: std.AutoArrayHashMapUnmanaged(StrtabString, Global),
28next_unnamed_global: StrtabString,
29next_replaced_global: StrtabString,
30next_unique_global_id: std.AutoHashMapUnmanaged(StrtabString, u32),
31aliases: std.ArrayListUnmanaged(Alias),
32variables: std.ArrayListUnmanaged(Variable),
33functions: std.ArrayListUnmanaged(Function),
34
35strtab_string_map: std.AutoArrayHashMapUnmanaged(void, void),
36strtab_string_indices: std.ArrayListUnmanaged(u32),
37strtab_string_bytes: std.ArrayListUnmanaged(u8),
38
39constant_map: std.AutoArrayHashMapUnmanaged(void, void),
40constant_items: std.MultiArrayList(Constant.Item),
41constant_extra: std.ArrayListUnmanaged(u32),
42constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
43
44metadata_map: std.AutoArrayHashMapUnmanaged(void, void),
45metadata_items: std.MultiArrayList(Metadata.Item),
46metadata_extra: std.ArrayListUnmanaged(u32),
47metadata_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
48metadata_forward_references: std.ArrayListUnmanaged(Metadata),
49metadata_named: std.AutoArrayHashMapUnmanaged(MetadataString, struct {
50 len: u32,
51 index: Metadata.Item.ExtraIndex,
52}),
53
54metadata_string_map: std.AutoArrayHashMapUnmanaged(void, void),
55metadata_string_indices: std.ArrayListUnmanaged(u32),
56metadata_string_bytes: std.ArrayListUnmanaged(u8),
57
58pub const expected_args_len = 16;
59pub const expected_attrs_len = 16;
60pub const expected_fields_len = 32;
61pub const expected_gep_indices_len = 8;
62pub const expected_cases_len = 8;
63pub const expected_incoming_len = 8;
64
65pub const Options = struct {
66 allocator: Allocator,
67 strip: bool = true,
68 name: []const u8 = &.{},
69 target: std.Target = builtin.target,
70 triple: []const u8 = &.{},
71};
72
73pub const String = enum(u32) {
74 none = std.math.maxInt(u31),
75 empty,
76 _,
77
78 pub fn isAnon(self: String) bool {
79 assert(self != .none);
80 return self.toIndex() == null;
81 }
82
83 pub fn slice(self: String, builder: *const Builder) ?[]const u8 {
84 const index = self.toIndex() orelse return null;
85 const start = builder.string_indices.items[index];
86 const end = builder.string_indices.items[index + 1];
87 return builder.string_bytes.items[start..end];
88 }
89
90 const FormatData = struct {
91 string: String,
92 builder: *const Builder,
93 };
94 fn format(
95 data: FormatData,
96 comptime fmt_str: []const u8,
97 _: std.fmt.FormatOptions,
98 writer: anytype,
99 ) @TypeOf(writer).Error!void {
100 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_|
101 @compileError("invalid format string: '" ++ fmt_str ++ "'");
102 assert(data.string != .none);
103 const string_slice = data.string.slice(data.builder) orelse
104 return writer.print("{d}", .{@intFromEnum(data.string)});
105 if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_|
106 return writer.writeAll(string_slice);
107 try printEscapedString(
108 string_slice,
109 if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
110 .always_quote
111 else
112 .quote_unless_valid_identifier,
113 writer,
114 );
115 }
116 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
117 return .{ .data = .{ .string = self, .builder = builder } };
118 }
119
120 fn fromIndex(index: ?usize) String {
121 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
122 @intFromEnum(String.empty))));
123 }
124
125 fn toIndex(self: String) ?usize {
126 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;
127 }
128
129 const Adapter = struct {
130 builder: *const Builder,
131 pub fn hash(_: Adapter, key: []const u8) u32 {
132 return @truncate(std.hash.Wyhash.hash(0, key));
133 }
134 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
135 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).slice(ctx.builder).?);
136 }
137 };
138};
139
140pub const BinaryOpcode = enum(u4) {
141 add = 0,
142 sub = 1,
143 mul = 2,
144 udiv = 3,
145 sdiv = 4,
146 urem = 5,
147 srem = 6,
148 shl = 7,
149 lshr = 8,
150 ashr = 9,
151 @"and" = 10,
152 @"or" = 11,
153 xor = 12,
154};
155
156pub const CastOpcode = enum(u4) {
157 trunc = 0,
158 zext = 1,
159 sext = 2,
160 fptoui = 3,
161 fptosi = 4,
162 uitofp = 5,
163 sitofp = 6,
164 fptrunc = 7,
165 fpext = 8,
166 ptrtoint = 9,
167 inttoptr = 10,
168 bitcast = 11,
169 addrspacecast = 12,
170};
171
172pub const CmpPredicate = enum(u6) {
173 fcmp_false = 0,
174 fcmp_oeq = 1,
175 fcmp_ogt = 2,
176 fcmp_oge = 3,
177 fcmp_olt = 4,
178 fcmp_ole = 5,
179 fcmp_one = 6,
180 fcmp_ord = 7,
181 fcmp_uno = 8,
182 fcmp_ueq = 9,
183 fcmp_ugt = 10,
184 fcmp_uge = 11,
185 fcmp_ult = 12,
186 fcmp_ule = 13,
187 fcmp_une = 14,
188 fcmp_true = 15,
189 icmp_eq = 32,
190 icmp_ne = 33,
191 icmp_ugt = 34,
192 icmp_uge = 35,
193 icmp_ult = 36,
194 icmp_ule = 37,
195 icmp_sgt = 38,
196 icmp_sge = 39,
197 icmp_slt = 40,
198 icmp_sle = 41,
199};
200
201pub const Type = enum(u32) {
202 void,
203 half,
204 bfloat,
205 float,
206 double,
207 fp128,
208 x86_fp80,
209 ppc_fp128,
210 x86_amx,
211 x86_mmx,
212 label,
213 token,
214 metadata,
215
216 i1,
217 i8,
218 i16,
219 i29,
220 i32,
221 i64,
222 i80,
223 i128,
224 ptr,
225 @"ptr addrspace(4)",
226
227 none = std.math.maxInt(u32),
228 _,
229
230 pub const ptr_amdgpu_constant =
231 @field(Type, std.fmt.comptimePrint("ptr{ }", .{AddrSpace.amdgpu.constant}));
232
233 pub const Tag = enum(u4) {
234 simple,
235 function,
236 vararg_function,
237 integer,
238 pointer,
239 target,
240 vector,
241 scalable_vector,
242 small_array,
243 array,
244 structure,
245 packed_structure,
246 named_structure,
247 };
248
249 pub const Simple = enum(u5) {
250 void = 2,
251 half = 10,
252 bfloat = 23,
253 float = 3,
254 double = 4,
255 fp128 = 14,
256 x86_fp80 = 13,
257 ppc_fp128 = 15,
258 x86_amx = 24,
259 x86_mmx = 17,
260 label = 5,
261 token = 22,
262 metadata = 16,
263 };
264
265 pub const Function = struct {
266 ret: Type,
267 params_len: u32,
268 //params: [params_len]Value,
269
270 pub const Kind = enum { normal, vararg };
271 };
272
273 pub const Target = extern struct {
274 name: String,
275 types_len: u32,
276 ints_len: u32,
277 //types: [types_len]Type,
278 //ints: [ints_len]u32,
279 };
280
281 pub const Vector = extern struct {
282 len: u32,
283 child: Type,
284
285 fn length(self: Vector) u32 {
286 return self.len;
287 }
288
289 pub const Kind = enum { normal, scalable };
290 };
291
292 pub const Array = extern struct {
293 len_lo: u32,
294 len_hi: u32,
295 child: Type,
296
297 fn length(self: Array) u64 {
298 return @as(u64, self.len_hi) << 32 | self.len_lo;
299 }
300 };
301
302 pub const Structure = struct {
303 fields_len: u32,
304 //fields: [fields_len]Type,
305
306 pub const Kind = enum { normal, @"packed" };
307 };
308
309 pub const NamedStructure = struct {
310 id: String,
311 body: Type,
312 };
313
314 pub const Item = packed struct(u32) {
315 tag: Tag,
316 data: ExtraIndex,
317
318 pub const ExtraIndex = u28;
319 };
320
321 pub fn tag(self: Type, builder: *const Builder) Tag {
322 return builder.type_items.items[@intFromEnum(self)].tag;
323 }
324
325 pub fn unnamedTag(self: Type, builder: *const Builder) Tag {
326 const item = builder.type_items.items[@intFromEnum(self)];
327 return switch (item.tag) {
328 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
329 .unnamedTag(builder),
330 else => item.tag,
331 };
332 }
333
334 pub fn scalarTag(self: Type, builder: *const Builder) Tag {
335 const item = builder.type_items.items[@intFromEnum(self)];
336 return switch (item.tag) {
337 .vector, .scalable_vector => builder.typeExtraData(Type.Vector, item.data)
338 .child.tag(builder),
339 else => item.tag,
340 };
341 }
342
343 pub fn isFloatingPoint(self: Type) bool {
344 return switch (self) {
345 .half, .bfloat, .float, .double, .fp128, .x86_fp80, .ppc_fp128 => true,
346 else => false,
347 };
348 }
349
350 pub fn isInteger(self: Type, builder: *const Builder) bool {
351 return switch (self) {
352 .i1, .i8, .i16, .i29, .i32, .i64, .i80, .i128 => true,
353 else => switch (self.tag(builder)) {
354 .integer => true,
355 else => false,
356 },
357 };
358 }
359
360 pub fn isPointer(self: Type, builder: *const Builder) bool {
361 return switch (self) {
362 .ptr => true,
363 else => switch (self.tag(builder)) {
364 .pointer => true,
365 else => false,
366 },
367 };
368 }
369
370 pub fn pointerAddrSpace(self: Type, builder: *const Builder) AddrSpace {
371 switch (self) {
372 .ptr => return .default,
373 else => {
374 const item = builder.type_items.items[@intFromEnum(self)];
375 assert(item.tag == .pointer);
376 return @enumFromInt(item.data);
377 },
378 }
379 }
380
381 pub fn isFunction(self: Type, builder: *const Builder) bool {
382 return switch (self.tag(builder)) {
383 .function, .vararg_function => true,
384 else => false,
385 };
386 }
387
388 pub fn functionKind(self: Type, builder: *const Builder) Type.Function.Kind {
389 return switch (self.tag(builder)) {
390 .function => .normal,
391 .vararg_function => .vararg,
392 else => unreachable,
393 };
394 }
395
396 pub fn functionParameters(self: Type, builder: *const Builder) []const Type {
397 const item = builder.type_items.items[@intFromEnum(self)];
398 switch (item.tag) {
399 .function,
400 .vararg_function,
401 => {
402 var extra = builder.typeExtraDataTrail(Type.Function, item.data);
403 return extra.trail.next(extra.data.params_len, Type, builder);
404 },
405 else => unreachable,
406 }
407 }
408
409 pub fn functionReturn(self: Type, builder: *const Builder) Type {
410 const item = builder.type_items.items[@intFromEnum(self)];
411 switch (item.tag) {
412 .function,
413 .vararg_function,
414 => return builder.typeExtraData(Type.Function, item.data).ret,
415 else => unreachable,
416 }
417 }
418
419 pub fn isVector(self: Type, builder: *const Builder) bool {
420 return switch (self.tag(builder)) {
421 .vector, .scalable_vector => true,
422 else => false,
423 };
424 }
425
426 pub fn vectorKind(self: Type, builder: *const Builder) Type.Vector.Kind {
427 return switch (self.tag(builder)) {
428 .vector => .normal,
429 .scalable_vector => .scalable,
430 else => unreachable,
431 };
432 }
433
434 pub fn isStruct(self: Type, builder: *const Builder) bool {
435 return switch (self.tag(builder)) {
436 .structure, .packed_structure, .named_structure => true,
437 else => false,
438 };
439 }
440
441 pub fn structKind(self: Type, builder: *const Builder) Type.Structure.Kind {
442 return switch (self.unnamedTag(builder)) {
443 .structure => .normal,
444 .packed_structure => .@"packed",
445 else => unreachable,
446 };
447 }
448
449 pub fn isAggregate(self: Type, builder: *const Builder) bool {
450 return switch (self.tag(builder)) {
451 .small_array, .array, .structure, .packed_structure, .named_structure => true,
452 else => false,
453 };
454 }
455
456 pub fn scalarBits(self: Type, builder: *const Builder) u24 {
457 return switch (self) {
458 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,
459 .i1 => 1,
460 .i8 => 8,
461 .half, .bfloat, .i16 => 16,
462 .i29 => 29,
463 .float, .i32 => 32,
464 .double, .i64, .x86_mmx => 64,
465 .x86_fp80, .i80 => 80,
466 .fp128, .ppc_fp128, .i128 => 128,
467 .ptr, .@"ptr addrspace(4)" => @panic("TODO: query data layout"),
468 _ => {
469 const item = builder.type_items.items[@intFromEnum(self)];
470 return switch (item.tag) {
471 .simple,
472 .function,
473 .vararg_function,
474 => unreachable,
475 .integer => @intCast(item.data),
476 .pointer => @panic("TODO: query data layout"),
477 .target => unreachable,
478 .vector,
479 .scalable_vector,
480 => builder.typeExtraData(Type.Vector, item.data).child.scalarBits(builder),
481 .small_array,
482 .array,
483 .structure,
484 .packed_structure,
485 .named_structure,
486 => unreachable,
487 };
488 },
489 };
490 }
491
492 pub fn childType(self: Type, builder: *const Builder) Type {
493 const item = builder.type_items.items[@intFromEnum(self)];
494 return switch (item.tag) {
495 .vector,
496 .scalable_vector,
497 .small_array,
498 => builder.typeExtraData(Type.Vector, item.data).child,
499 .array => builder.typeExtraData(Type.Array, item.data).child,
500 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body,
501 else => unreachable,
502 };
503 }
504
505 pub fn scalarType(self: Type, builder: *const Builder) Type {
506 if (self.isFloatingPoint()) return self;
507 const item = builder.type_items.items[@intFromEnum(self)];
508 return switch (item.tag) {
509 .integer,
510 .pointer,
511 => self,
512 .vector,
513 .scalable_vector,
514 => builder.typeExtraData(Type.Vector, item.data).child,
515 else => unreachable,
516 };
517 }
518
519 pub fn changeScalar(self: Type, scalar: Type, builder: *Builder) Allocator.Error!Type {
520 try builder.ensureUnusedTypeCapacity(1, Type.Vector, 0);
521 return self.changeScalarAssumeCapacity(scalar, builder);
522 }
523
524 pub fn changeScalarAssumeCapacity(self: Type, scalar: Type, builder: *Builder) Type {
525 if (self.isFloatingPoint()) return scalar;
526 const item = builder.type_items.items[@intFromEnum(self)];
527 return switch (item.tag) {
528 .integer,
529 .pointer,
530 => scalar,
531 inline .vector,
532 .scalable_vector,
533 => |kind| builder.vectorTypeAssumeCapacity(
534 switch (kind) {
535 .vector => .normal,
536 .scalable_vector => .scalable,
537 else => unreachable,
538 },
539 builder.typeExtraData(Type.Vector, item.data).len,
540 scalar,
541 ),
542 else => unreachable,
543 };
544 }
545
546 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
547 const item = builder.type_items.items[@intFromEnum(self)];
548 return switch (item.tag) {
549 .vector,
550 .scalable_vector,
551 => builder.typeExtraData(Type.Vector, item.data).len,
552 else => unreachable,
553 };
554 }
555
556 pub fn changeLength(self: Type, len: u32, builder: *Builder) Allocator.Error!Type {
557 try builder.ensureUnusedTypeCapacity(1, Type.Array, 0);
558 return self.changeLengthAssumeCapacity(len, builder);
559 }
560
561 pub fn changeLengthAssumeCapacity(self: Type, len: u32, builder: *Builder) Type {
562 const item = builder.type_items.items[@intFromEnum(self)];
563 return switch (item.tag) {
564 inline .vector,
565 .scalable_vector,
566 => |kind| builder.vectorTypeAssumeCapacity(
567 switch (kind) {
568 .vector => .normal,
569 .scalable_vector => .scalable,
570 else => unreachable,
571 },
572 len,
573 builder.typeExtraData(Type.Vector, item.data).child,
574 ),
575 .small_array => builder.arrayTypeAssumeCapacity(
576 len,
577 builder.typeExtraData(Type.Vector, item.data).child,
578 ),
579 .array => builder.arrayTypeAssumeCapacity(
580 len,
581 builder.typeExtraData(Type.Array, item.data).child,
582 ),
583 else => unreachable,
584 };
585 }
586
587 pub fn aggregateLen(self: Type, builder: *const Builder) usize {
588 const item = builder.type_items.items[@intFromEnum(self)];
589 return switch (item.tag) {
590 .vector,
591 .scalable_vector,
592 .small_array,
593 => builder.typeExtraData(Type.Vector, item.data).len,
594 .array => @intCast(builder.typeExtraData(Type.Array, item.data).length()),
595 .structure,
596 .packed_structure,
597 => builder.typeExtraData(Type.Structure, item.data).fields_len,
598 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
599 .aggregateLen(builder),
600 else => unreachable,
601 };
602 }
603
604 pub fn structFields(self: Type, builder: *const Builder) []const Type {
605 const item = builder.type_items.items[@intFromEnum(self)];
606 switch (item.tag) {
607 .structure,
608 .packed_structure,
609 => {
610 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
611 return extra.trail.next(extra.data.fields_len, Type, builder);
612 },
613 .named_structure => return builder.typeExtraData(Type.NamedStructure, item.data).body
614 .structFields(builder),
615 else => unreachable,
616 }
617 }
618
619 pub fn childTypeAt(self: Type, indices: []const u32, builder: *const Builder) Type {
620 if (indices.len == 0) return self;
621 const item = builder.type_items.items[@intFromEnum(self)];
622 return switch (item.tag) {
623 .small_array => builder.typeExtraData(Type.Vector, item.data).child
624 .childTypeAt(indices[1..], builder),
625 .array => builder.typeExtraData(Type.Array, item.data).child
626 .childTypeAt(indices[1..], builder),
627 .structure,
628 .packed_structure,
629 => {
630 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
631 const fields = extra.trail.next(extra.data.fields_len, Type, builder);
632 return fields[indices[0]].childTypeAt(indices[1..], builder);
633 },
634 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
635 .childTypeAt(indices, builder),
636 else => unreachable,
637 };
638 }
639
640 pub fn targetLayoutType(self: Type, builder: *const Builder) Type {
641 _ = self;
642 _ = builder;
643 @panic("TODO: implement targetLayoutType");
644 }
645
646 pub fn isSized(self: Type, builder: *const Builder) Allocator.Error!bool {
647 var visited: IsSizedVisited = .{};
648 defer visited.deinit(builder.gpa);
649 const result = try self.isSizedVisited(&visited, builder);
650 return result;
651 }
652
653 const FormatData = struct {
654 type: Type,
655 builder: *const Builder,
656 };
657 fn format(
658 data: FormatData,
659 comptime fmt_str: []const u8,
660 fmt_opts: std.fmt.FormatOptions,
661 writer: anytype,
662 ) @TypeOf(writer).Error!void {
663 assert(data.type != .none);
664 if (comptime std.mem.eql(u8, fmt_str, "m")) {
665 const item = data.builder.type_items.items[@intFromEnum(data.type)];
666 switch (item.tag) {
667 .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) {
668 .void => "isVoid",
669 .half => "f16",
670 .bfloat => "bf16",
671 .float => "f32",
672 .double => "f64",
673 .fp128 => "f128",
674 .x86_fp80 => "f80",
675 .ppc_fp128 => "ppcf128",
676 .x86_amx => "x86amx",
677 .x86_mmx => "x86mmx",
678 .label, .token => unreachable,
679 .metadata => "Metadata",
680 }),
681 .function, .vararg_function => |kind| {
682 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
683 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
684 try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)});
685 for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)});
686 switch (kind) {
687 .function => {},
688 .vararg_function => try writer.writeAll("vararg"),
689 else => unreachable,
690 }
691 try writer.writeByte('f');
692 },
693 .integer => try writer.print("i{d}", .{item.data}),
694 .pointer => try writer.print("p{d}", .{item.data}),
695 .target => {
696 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
697 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
698 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
699 try writer.print("t{s}", .{extra.data.name.slice(data.builder).?});
700 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
701 for (ints) |int| try writer.print("_{d}", .{int});
702 try writer.writeByte('t');
703 },
704 .vector, .scalable_vector => |kind| {
705 const extra = data.builder.typeExtraData(Type.Vector, item.data);
706 try writer.print("{s}v{d}{m}", .{
707 switch (kind) {
708 .vector => "",
709 .scalable_vector => "nx",
710 else => unreachable,
711 },
712 extra.len,
713 extra.child.fmt(data.builder),
714 });
715 },
716 inline .small_array, .array => |kind| {
717 const extra = data.builder.typeExtraData(switch (kind) {
718 .small_array => Type.Vector,
719 .array => Type.Array,
720 else => unreachable,
721 }, item.data);
722 try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) });
723 },
724 .structure, .packed_structure => {
725 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
726 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
727 try writer.writeAll("sl_");
728 for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)});
729 try writer.writeByte('s');
730 },
731 .named_structure => {
732 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
733 try writer.writeAll("s_");
734 if (extra.id.slice(data.builder)) |id| try writer.writeAll(id);
735 },
736 }
737 return;
738 }
739 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
740 const item = data.builder.type_items.items[@intFromEnum(data.type)];
741 switch (item.tag) {
742 .simple => unreachable,
743 .function, .vararg_function => |kind| {
744 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
745 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
746 if (!comptime std.mem.eql(u8, fmt_str, ">"))
747 try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)});
748 if (!comptime std.mem.eql(u8, fmt_str, "<")) {
749 try writer.writeByte('(');
750 for (params, 0..) |param, index| {
751 if (index > 0) try writer.writeAll(", ");
752 try writer.print("{%}", .{param.fmt(data.builder)});
753 }
754 switch (kind) {
755 .function => {},
756 .vararg_function => {
757 if (params.len > 0) try writer.writeAll(", ");
758 try writer.writeAll("...");
759 },
760 else => unreachable,
761 }
762 try writer.writeByte(')');
763 }
764 },
765 .integer => try writer.print("i{d}", .{item.data}),
766 .pointer => try writer.print("ptr{ }", .{@as(AddrSpace, @enumFromInt(item.data))}),
767 .target => {
768 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
769 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
770 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
771 try writer.print(
772 \\target({"}
773 , .{extra.data.name.fmt(data.builder)});
774 for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)});
775 for (ints) |int| try writer.print(", {d}", .{int});
776 try writer.writeByte(')');
777 },
778 .vector, .scalable_vector => |kind| {
779 const extra = data.builder.typeExtraData(Type.Vector, item.data);
780 try writer.print("<{s}{d} x {%}>", .{
781 switch (kind) {
782 .vector => "",
783 .scalable_vector => "vscale x ",
784 else => unreachable,
785 },
786 extra.len,
787 extra.child.fmt(data.builder),
788 });
789 },
790 inline .small_array, .array => |kind| {
791 const extra = data.builder.typeExtraData(switch (kind) {
792 .small_array => Type.Vector,
793 .array => Type.Array,
794 else => unreachable,
795 }, item.data);
796 try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) });
797 },
798 .structure, .packed_structure => |kind| {
799 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
800 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
801 switch (kind) {
802 .structure => {},
803 .packed_structure => try writer.writeByte('<'),
804 else => unreachable,
805 }
806 try writer.writeAll("{ ");
807 for (fields, 0..) |field, index| {
808 if (index > 0) try writer.writeAll(", ");
809 try writer.print("{%}", .{field.fmt(data.builder)});
810 }
811 try writer.writeAll(" }");
812 switch (kind) {
813 .structure => {},
814 .packed_structure => try writer.writeByte('>'),
815 else => unreachable,
816 }
817 },
818 .named_structure => {
819 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
820 if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
821 extra.id.fmt(data.builder),
822 }) else switch (extra.body) {
823 .none => try writer.writeAll("opaque"),
824 else => try format(.{
825 .type = extra.body,
826 .builder = data.builder,
827 }, fmt_str, fmt_opts, writer),
828 }
829 },
830 }
831 }
832 pub fn fmt(self: Type, builder: *const Builder) std.fmt.Formatter(format) {
833 return .{ .data = .{ .type = self, .builder = builder } };
834 }
835
836 const IsSizedVisited = std.AutoHashMapUnmanaged(Type, void);
837 fn isSizedVisited(
838 self: Type,
839 visited: *IsSizedVisited,
840 builder: *const Builder,
841 ) Allocator.Error!bool {
842 return switch (self) {
843 .void,
844 .label,
845 .token,
846 .metadata,
847 => false,
848 .half,
849 .bfloat,
850 .float,
851 .double,
852 .fp128,
853 .x86_fp80,
854 .ppc_fp128,
855 .x86_amx,
856 .x86_mmx,
857 .i1,
858 .i8,
859 .i16,
860 .i29,
861 .i32,
862 .i64,
863 .i80,
864 .i128,
865 .ptr,
866 .@"ptr addrspace(4)",
867 => true,
868 .none => unreachable,
869 _ => {
870 const item = builder.type_items.items[@intFromEnum(self)];
871 return switch (item.tag) {
872 .simple => unreachable,
873 .function,
874 .vararg_function,
875 => false,
876 .integer,
877 .pointer,
878 => true,
879 .target => self.targetLayoutType(builder).isSizedVisited(visited, builder),
880 .vector,
881 .scalable_vector,
882 .small_array,
883 => builder.typeExtraData(Type.Vector, item.data)
884 .child.isSizedVisited(visited, builder),
885 .array => builder.typeExtraData(Type.Array, item.data)
886 .child.isSizedVisited(visited, builder),
887 .structure,
888 .packed_structure,
889 => {
890 if (try visited.fetchPut(builder.gpa, self, {})) |_| return false;
891
892 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
893 const fields = extra.trail.next(extra.data.fields_len, Type, builder);
894 for (fields) |field| {
895 if (field.isVector(builder) and field.vectorKind(builder) == .scalable)
896 return false;
897 if (!try field.isSizedVisited(visited, builder))
898 return false;
899 }
900 return true;
901 },
902 .named_structure => {
903 const body = builder.typeExtraData(Type.NamedStructure, item.data).body;
904 return body != .none and try body.isSizedVisited(visited, builder);
905 },
906 };
907 },
908 };
909 }
910};
911
912pub const Attribute = union(Kind) {
913 // Parameter Attributes
914 zeroext,
915 signext,
916 inreg,
917 byval: Type,
918 byref: Type,
919 preallocated: Type,
920 inalloca: Type,
921 sret: Type,
922 elementtype: Type,
923 @"align": Alignment,
924 @"noalias",
925 nocapture,
926 nofree,
927 nest,
928 returned,
929 nonnull,
930 dereferenceable: u32,
931 dereferenceable_or_null: u32,
932 swiftself,
933 swiftasync,
934 swifterror,
935 immarg,
936 noundef,
937 nofpclass: FpClass,
938 alignstack: Alignment,
939 allocalign,
940 allocptr,
941 readnone,
942 readonly,
943 writeonly,
944
945 // Function Attributes
946 //alignstack: Alignment,
947 allockind: AllocKind,
948 allocsize: AllocSize,
949 alwaysinline,
950 builtin,
951 cold,
952 convergent,
953 disable_sanitizer_information,
954 fn_ret_thunk_extern,
955 hot,
956 inlinehint,
957 jumptable,
958 memory: Memory,
959 minsize,
960 naked,
961 nobuiltin,
962 nocallback,
963 noduplicate,
964 //nofree,
965 noimplicitfloat,
966 @"noinline",
967 nomerge,
968 nonlazybind,
969 noprofile,
970 skipprofile,
971 noredzone,
972 noreturn,
973 norecurse,
974 willreturn,
975 nosync,
976 nounwind,
977 nosanitize_bounds,
978 nosanitize_coverage,
979 null_pointer_is_valid,
980 optforfuzzing,
981 optnone,
982 optsize,
983 //preallocated: Type,
984 returns_twice,
985 safestack,
986 sanitize_address,
987 sanitize_memory,
988 sanitize_thread,
989 sanitize_hwaddress,
990 sanitize_memtag,
991 speculative_load_hardening,
992 speculatable,
993 ssp,
994 sspstrong,
995 sspreq,
996 strictfp,
997 uwtable: UwTable,
998 nocf_check,
999 shadowcallstack,
1000 mustprogress,
1001 vscale_range: VScaleRange,
1002
1003 // Global Attributes
1004 no_sanitize_address,
1005 no_sanitize_hwaddress,
1006 //sanitize_memtag,
1007 sanitize_address_dyninit,
1008
1009 string: struct { kind: String, value: String },
1010 none: noreturn,
1011
1012 pub const Index = enum(u32) {
1013 _,
1014
1015 pub fn getKind(self: Index, builder: *const Builder) Kind {
1016 return self.toStorage(builder).kind;
1017 }
1018
1019 pub fn toAttribute(self: Index, builder: *const Builder) Attribute {
1020 @setEvalBranchQuota(2_000);
1021 const storage = self.toStorage(builder);
1022 if (storage.kind.toString()) |kind| return .{ .string = .{
1023 .kind = kind,
1024 .value = @enumFromInt(storage.value),
1025 } } else return switch (storage.kind) {
1026 inline .zeroext,
1027 .signext,
1028 .inreg,
1029 .byval,
1030 .byref,
1031 .preallocated,
1032 .inalloca,
1033 .sret,
1034 .elementtype,
1035 .@"align",
1036 .@"noalias",
1037 .nocapture,
1038 .nofree,
1039 .nest,
1040 .returned,
1041 .nonnull,
1042 .dereferenceable,
1043 .dereferenceable_or_null,
1044 .swiftself,
1045 .swiftasync,
1046 .swifterror,
1047 .immarg,
1048 .noundef,
1049 .nofpclass,
1050 .alignstack,
1051 .allocalign,
1052 .allocptr,
1053 .readnone,
1054 .readonly,
1055 .writeonly,
1056 //.alignstack,
1057 .allockind,
1058 .allocsize,
1059 .alwaysinline,
1060 .builtin,
1061 .cold,
1062 .convergent,
1063 .disable_sanitizer_information,
1064 .fn_ret_thunk_extern,
1065 .hot,
1066 .inlinehint,
1067 .jumptable,
1068 .memory,
1069 .minsize,
1070 .naked,
1071 .nobuiltin,
1072 .nocallback,
1073 .noduplicate,
1074 //.nofree,
1075 .noimplicitfloat,
1076 .@"noinline",
1077 .nomerge,
1078 .nonlazybind,
1079 .noprofile,
1080 .skipprofile,
1081 .noredzone,
1082 .noreturn,
1083 .norecurse,
1084 .willreturn,
1085 .nosync,
1086 .nounwind,
1087 .nosanitize_bounds,
1088 .nosanitize_coverage,
1089 .null_pointer_is_valid,
1090 .optforfuzzing,
1091 .optnone,
1092 .optsize,
1093 //.preallocated,
1094 .returns_twice,
1095 .safestack,
1096 .sanitize_address,
1097 .sanitize_memory,
1098 .sanitize_thread,
1099 .sanitize_hwaddress,
1100 .sanitize_memtag,
1101 .speculative_load_hardening,
1102 .speculatable,
1103 .ssp,
1104 .sspstrong,
1105 .sspreq,
1106 .strictfp,
1107 .uwtable,
1108 .nocf_check,
1109 .shadowcallstack,
1110 .mustprogress,
1111 .vscale_range,
1112 .no_sanitize_address,
1113 .no_sanitize_hwaddress,
1114 .sanitize_address_dyninit,
1115 => |kind| {
1116 const field = comptime blk: {
1117 @setEvalBranchQuota(10_000);
1118 for (@typeInfo(Attribute).@"union".fields) |field| {
1119 if (std.mem.eql(u8, field.name, @tagName(kind))) break :blk field;
1120 }
1121 unreachable;
1122 };
1123 comptime assert(std.mem.eql(u8, @tagName(kind), field.name));
1124 return @unionInit(Attribute, field.name, switch (field.type) {
1125 void => {},
1126 u32 => storage.value,
1127 Alignment, String, Type, UwTable => @enumFromInt(storage.value),
1128 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
1129 else => @compileError("bad payload type: " ++ field.name ++ ": " ++
1130 @typeName(field.type)),
1131 });
1132 },
1133 .string, .none => unreachable,
1134 _ => unreachable,
1135 };
1136 }
1137
1138 const FormatData = struct {
1139 attribute_index: Index,
1140 builder: *const Builder,
1141 };
1142 fn format(
1143 data: FormatData,
1144 comptime fmt_str: []const u8,
1145 _: std.fmt.FormatOptions,
1146 writer: anytype,
1147 ) @TypeOf(writer).Error!void {
1148 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
1149 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1150 const attribute = data.attribute_index.toAttribute(data.builder);
1151 switch (attribute) {
1152 .zeroext,
1153 .signext,
1154 .inreg,
1155 .@"noalias",
1156 .nocapture,
1157 .nofree,
1158 .nest,
1159 .returned,
1160 .nonnull,
1161 .swiftself,
1162 .swiftasync,
1163 .swifterror,
1164 .immarg,
1165 .noundef,
1166 .allocalign,
1167 .allocptr,
1168 .readnone,
1169 .readonly,
1170 .writeonly,
1171 .alwaysinline,
1172 .builtin,
1173 .cold,
1174 .convergent,
1175 .disable_sanitizer_information,
1176 .fn_ret_thunk_extern,
1177 .hot,
1178 .inlinehint,
1179 .jumptable,
1180 .minsize,
1181 .naked,
1182 .nobuiltin,
1183 .nocallback,
1184 .noduplicate,
1185 .noimplicitfloat,
1186 .@"noinline",
1187 .nomerge,
1188 .nonlazybind,
1189 .noprofile,
1190 .skipprofile,
1191 .noredzone,
1192 .noreturn,
1193 .norecurse,
1194 .willreturn,
1195 .nosync,
1196 .nounwind,
1197 .nosanitize_bounds,
1198 .nosanitize_coverage,
1199 .null_pointer_is_valid,
1200 .optforfuzzing,
1201 .optnone,
1202 .optsize,
1203 .returns_twice,
1204 .safestack,
1205 .sanitize_address,
1206 .sanitize_memory,
1207 .sanitize_thread,
1208 .sanitize_hwaddress,
1209 .sanitize_memtag,
1210 .speculative_load_hardening,
1211 .speculatable,
1212 .ssp,
1213 .sspstrong,
1214 .sspreq,
1215 .strictfp,
1216 .nocf_check,
1217 .shadowcallstack,
1218 .mustprogress,
1219 .no_sanitize_address,
1220 .no_sanitize_hwaddress,
1221 .sanitize_address_dyninit,
1222 => try writer.print(" {s}", .{@tagName(attribute)}),
1223 .byval,
1224 .byref,
1225 .preallocated,
1226 .inalloca,
1227 .sret,
1228 .elementtype,
1229 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1230 .@"align" => |alignment| try writer.print("{ }", .{alignment}),
1231 .dereferenceable,
1232 .dereferenceable_or_null,
1233 => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
1234 .nofpclass => |fpclass| {
1235 const Int = @typeInfo(FpClass).@"struct".backing_integer.?;
1236 try writer.print(" {s}(", .{@tagName(attribute)});
1237 var any = false;
1238 var remaining: Int = @bitCast(fpclass);
1239 inline for (@typeInfo(FpClass).@"struct".decls) |decl| {
1240 const pattern: Int = @bitCast(@field(FpClass, decl.name));
1241 if (remaining & pattern == pattern) {
1242 if (!any) {
1243 try writer.writeByte(' ');
1244 any = true;
1245 }
1246 try writer.writeAll(decl.name);
1247 remaining &= ~pattern;
1248 }
1249 }
1250 try writer.writeByte(')');
1251 },
1252 .alignstack => |alignment| try writer.print(
1253 if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
1254 " {s}={d}"
1255 else
1256 " {s}({d})",
1257 .{ @tagName(attribute), alignment.toByteUnits() orelse return },
1258 ),
1259 .allockind => |allockind| {
1260 try writer.print(" {s}(\"", .{@tagName(attribute)});
1261 var any = false;
1262 inline for (@typeInfo(AllocKind).@"struct".fields) |field| {
1263 if (comptime std.mem.eql(u8, field.name, "_")) continue;
1264 if (@field(allockind, field.name)) {
1265 if (!any) {
1266 try writer.writeByte(',');
1267 any = true;
1268 }
1269 try writer.writeAll(field.name);
1270 }
1271 }
1272 try writer.writeAll("\")");
1273 },
1274 .allocsize => |allocsize| {
1275 try writer.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size });
1276 if (allocsize.num_elems != AllocSize.none)
1277 try writer.print(",{d}", .{allocsize.num_elems});
1278 try writer.writeByte(')');
1279 },
1280 .memory => |memory| {
1281 try writer.print(" {s}(", .{@tagName(attribute)});
1282 var any = memory.other != .none or
1283 (memory.argmem == .none and memory.inaccessiblemem == .none);
1284 if (any) try writer.writeAll(@tagName(memory.other));
1285 inline for (.{ "argmem", "inaccessiblemem" }) |kind| {
1286 if (@field(memory, kind) != memory.other) {
1287 if (any) try writer.writeAll(", ");
1288 try writer.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) });
1289 any = true;
1290 }
1291 }
1292 try writer.writeByte(')');
1293 },
1294 .uwtable => |uwtable| if (uwtable != .none) {
1295 try writer.print(" {s}", .{@tagName(attribute)});
1296 if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
1297 },
1298 .vscale_range => |vscale_range| try writer.print(" {s}({d},{d})", .{
1299 @tagName(attribute),
1300 vscale_range.min.toByteUnits().?,
1301 vscale_range.max.toByteUnits() orelse 0,
1302 }),
1303 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
1304 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
1305 if (string_attr.value != .empty)
1306 try writer.print("={\"}", .{string_attr.value.fmt(data.builder)});
1307 },
1308 .none => unreachable,
1309 }
1310 }
1311 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
1312 return .{ .data = .{ .attribute_index = self, .builder = builder } };
1313 }
1314
1315 fn toStorage(self: Index, builder: *const Builder) Storage {
1316 return builder.attributes.keys()[@intFromEnum(self)];
1317 }
1318 };
1319
1320 pub const Kind = enum(u32) {
1321 // Parameter Attributes
1322 zeroext = 34,
1323 signext = 24,
1324 inreg = 5,
1325 byval = 3,
1326 byref = 69,
1327 preallocated = 65,
1328 inalloca = 38,
1329 sret = 29, // TODO: ?
1330 elementtype = 77,
1331 @"align" = 1,
1332 @"noalias" = 9,
1333 nocapture = 11,
1334 nofree = 62,
1335 nest = 8,
1336 returned = 22,
1337 nonnull = 39,
1338 dereferenceable = 41,
1339 dereferenceable_or_null = 42,
1340 swiftself = 46,
1341 swiftasync = 75,
1342 swifterror = 47,
1343 immarg = 60,
1344 noundef = 68,
1345 nofpclass = 87,
1346 alignstack = 25,
1347 allocalign = 80,
1348 allocptr = 81,
1349 readnone = 20,
1350 readonly = 21,
1351 writeonly = 52,
1352
1353 // Function Attributes
1354 //alignstack,
1355 allockind = 82,
1356 allocsize = 51,
1357 alwaysinline = 2,
1358 builtin = 35,
1359 cold = 36,
1360 convergent = 43,
1361 disable_sanitizer_information = 78,
1362 fn_ret_thunk_extern = 84,
1363 hot = 72,
1364 inlinehint = 4,
1365 jumptable = 40,
1366 memory = 86,
1367 minsize = 6,
1368 naked = 7,
1369 nobuiltin = 10,
1370 nocallback = 71,
1371 noduplicate = 12,
1372 //nofree,
1373 noimplicitfloat = 13,
1374 @"noinline" = 14,
1375 nomerge = 66,
1376 nonlazybind = 15,
1377 noprofile = 73,
1378 skipprofile = 85,
1379 noredzone = 16,
1380 noreturn = 17,
1381 norecurse = 48,
1382 willreturn = 61,
1383 nosync = 63,
1384 nounwind = 18,
1385 nosanitize_bounds = 79,
1386 nosanitize_coverage = 76,
1387 null_pointer_is_valid = 67,
1388 optforfuzzing = 57,
1389 optnone = 37,
1390 optsize = 19,
1391 //preallocated,
1392 returns_twice = 23,
1393 safestack = 44,
1394 sanitize_address = 30,
1395 sanitize_memory = 32,
1396 sanitize_thread = 31,
1397 sanitize_hwaddress = 55,
1398 sanitize_memtag = 64,
1399 speculative_load_hardening = 59,
1400 speculatable = 53,
1401 ssp = 26,
1402 sspstrong = 28,
1403 sspreq = 27,
1404 strictfp = 54,
1405 uwtable = 33,
1406 nocf_check = 56,
1407 shadowcallstack = 58,
1408 mustprogress = 70,
1409 vscale_range = 74,
1410
1411 // Global Attributes
1412 no_sanitize_address = 100,
1413 no_sanitize_hwaddress = 101,
1414 //sanitize_memtag,
1415 sanitize_address_dyninit = 102,
1416
1417 string = std.math.maxInt(u31),
1418 none = std.math.maxInt(u32),
1419 _,
1420
1421 pub const len = @typeInfo(Kind).@"enum".fields.len - 2;
1422
1423 pub fn fromString(str: String) Kind {
1424 assert(!str.isAnon());
1425 const kind: Kind = @enumFromInt(@intFromEnum(str));
1426 assert(kind != .none);
1427 return kind;
1428 }
1429
1430 fn toString(self: Kind) ?String {
1431 assert(self != .none);
1432 const str: String = @enumFromInt(@intFromEnum(self));
1433 return if (str.isAnon()) null else str;
1434 }
1435 };
1436
1437 pub const FpClass = packed struct(u32) {
1438 signaling_nan: bool = false,
1439 quiet_nan: bool = false,
1440 negative_infinity: bool = false,
1441 negative_normal: bool = false,
1442 negative_subnormal: bool = false,
1443 negative_zero: bool = false,
1444 positive_zero: bool = false,
1445 positive_subnormal: bool = false,
1446 positive_normal: bool = false,
1447 positive_infinity: bool = false,
1448 _: u22 = 0,
1449
1450 pub const all = FpClass{
1451 .signaling_nan = true,
1452 .quiet_nan = true,
1453 .negative_infinity = true,
1454 .negative_normal = true,
1455 .negative_subnormal = true,
1456 .negative_zero = true,
1457 .positive_zero = true,
1458 .positive_subnormal = true,
1459 .positive_normal = true,
1460 .positive_infinity = true,
1461 };
1462
1463 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
1464 pub const snan = FpClass{ .signaling_nan = true };
1465 pub const qnan = FpClass{ .quiet_nan = true };
1466
1467 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
1468 pub const ninf = FpClass{ .negative_infinity = true };
1469 pub const pinf = FpClass{ .positive_infinity = true };
1470
1471 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
1472 pub const nzero = FpClass{ .negative_zero = true };
1473 pub const pzero = FpClass{ .positive_zero = true };
1474
1475 pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
1476 pub const nsub = FpClass{ .negative_subnormal = true };
1477 pub const psub = FpClass{ .positive_subnormal = true };
1478
1479 pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
1480 pub const nnorm = FpClass{ .negative_normal = true };
1481 pub const pnorm = FpClass{ .positive_normal = true };
1482 };
1483
1484 pub const AllocKind = packed struct(u32) {
1485 alloc: bool,
1486 realloc: bool,
1487 free: bool,
1488 uninitialized: bool,
1489 zeroed: bool,
1490 aligned: bool,
1491 _: u26 = 0,
1492 };
1493
1494 pub const AllocSize = packed struct(u32) {
1495 elem_size: u16,
1496 num_elems: u16,
1497
1498 pub const none = std.math.maxInt(u16);
1499
1500 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
1501 return .{ .num_elems = switch (self.num_elems) {
1502 else => self.num_elems,
1503 none => std.math.maxInt(u32),
1504 }, .elem_size = self.elem_size };
1505 }
1506 };
1507
1508 pub const Memory = packed struct(u32) {
1509 argmem: Effect = .none,
1510 inaccessiblemem: Effect = .none,
1511 other: Effect = .none,
1512 _: u26 = 0,
1513
1514 pub const Effect = enum(u2) { none, read, write, readwrite };
1515
1516 fn all(effect: Effect) Memory {
1517 return .{ .argmem = effect, .inaccessiblemem = effect, .other = effect };
1518 }
1519 };
1520
1521 pub const UwTable = enum(u32) {
1522 none,
1523 sync,
1524 @"async",
1525
1526 pub const default = UwTable.@"async";
1527 };
1528
1529 pub const VScaleRange = packed struct(u32) {
1530 min: Alignment,
1531 max: Alignment,
1532 _: u20 = 0,
1533
1534 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {
1535 return .{
1536 .max = @intCast(self.max.toByteUnits() orelse 0),
1537 .min = @intCast(self.min.toByteUnits().?),
1538 };
1539 }
1540 };
1541
1542 pub fn getKind(self: Attribute) Kind {
1543 return switch (self) {
1544 else => self,
1545 .string => |string_attr| Kind.fromString(string_attr.kind),
1546 };
1547 }
1548
1549 const Storage = extern struct {
1550 kind: Kind,
1551 value: u32,
1552 };
1553
1554 fn toStorage(self: Attribute) Storage {
1555 return switch (self) {
1556 inline else => |value, tag| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
1557 void => 0,
1558 u32 => value,
1559 Alignment, String, Type, UwTable => @intFromEnum(value),
1560 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
1561 else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))),
1562 } },
1563 .string => |string_attr| .{
1564 .kind = Kind.fromString(string_attr.kind),
1565 .value = @intFromEnum(string_attr.value),
1566 },
1567 .none => unreachable,
1568 };
1569 }
1570};
1571
1572pub const Attributes = enum(u32) {
1573 none,
1574 _,
1575
1576 pub fn slice(self: Attributes, builder: *const Builder) []const Attribute.Index {
1577 const start = builder.attributes_indices.items[@intFromEnum(self)];
1578 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1579 return @ptrCast(builder.attributes_extra.items[start..end]);
1580 }
1581
1582 const FormatData = struct {
1583 attributes: Attributes,
1584 builder: *const Builder,
1585 };
1586 fn format(
1587 data: FormatData,
1588 comptime fmt_str: []const u8,
1589 fmt_opts: std.fmt.FormatOptions,
1590 writer: anytype,
1591 ) @TypeOf(writer).Error!void {
1592 for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{
1593 .attribute_index = attribute_index,
1594 .builder = data.builder,
1595 }, fmt_str, fmt_opts, writer);
1596 }
1597 pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) {
1598 return .{ .data = .{ .attributes = self, .builder = builder } };
1599 }
1600};
1601
1602pub const FunctionAttributes = enum(u32) {
1603 none,
1604 _,
1605
1606 const function_index = 0;
1607 const return_index = 1;
1608 const params_index = 2;
1609
1610 pub const Wip = struct {
1611 maps: Maps = .{},
1612
1613 const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index);
1614 const Maps = std.ArrayListUnmanaged(Map);
1615
1616 pub fn deinit(self: *Wip, builder: *const Builder) void {
1617 for (self.maps.items) |*map| map.deinit(builder.gpa);
1618 self.maps.deinit(builder.gpa);
1619 self.* = undefined;
1620 }
1621
1622 pub fn addFnAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1623 try self.addAttr(function_index, attribute, builder);
1624 }
1625
1626 pub fn addFnAttrIndex(
1627 self: *Wip,
1628 attribute_index: Attribute.Index,
1629 builder: *const Builder,
1630 ) Allocator.Error!void {
1631 try self.addAttrIndex(function_index, attribute_index, builder);
1632 }
1633
1634 pub fn removeFnAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1635 return self.removeAttr(function_index, attribute_kind);
1636 }
1637
1638 pub fn addRetAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1639 try self.addAttr(return_index, attribute, builder);
1640 }
1641
1642 pub fn addRetAttrIndex(
1643 self: *Wip,
1644 attribute_index: Attribute.Index,
1645 builder: *const Builder,
1646 ) Allocator.Error!void {
1647 try self.addAttrIndex(return_index, attribute_index, builder);
1648 }
1649
1650 pub fn removeRetAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1651 return self.removeAttr(return_index, attribute_kind);
1652 }
1653
1654 pub fn addParamAttr(
1655 self: *Wip,
1656 param_index: usize,
1657 attribute: Attribute,
1658 builder: *Builder,
1659 ) Allocator.Error!void {
1660 try self.addAttr(params_index + param_index, attribute, builder);
1661 }
1662
1663 pub fn addParamAttrIndex(
1664 self: *Wip,
1665 param_index: usize,
1666 attribute_index: Attribute.Index,
1667 builder: *const Builder,
1668 ) Allocator.Error!void {
1669 try self.addAttrIndex(params_index + param_index, attribute_index, builder);
1670 }
1671
1672 pub fn removeParamAttr(
1673 self: *Wip,
1674 param_index: usize,
1675 attribute_kind: Attribute.Kind,
1676 ) Allocator.Error!bool {
1677 return self.removeAttr(params_index + param_index, attribute_kind);
1678 }
1679
1680 pub fn finish(self: *const Wip, builder: *Builder) Allocator.Error!FunctionAttributes {
1681 const attributes = try builder.gpa.alloc(Attributes, self.maps.items.len);
1682 defer builder.gpa.free(attributes);
1683 for (attributes, self.maps.items) |*attribute, map|
1684 attribute.* = try builder.attrs(map.values());
1685 return builder.fnAttrs(attributes);
1686 }
1687
1688 fn addAttr(
1689 self: *Wip,
1690 index: usize,
1691 attribute: Attribute,
1692 builder: *Builder,
1693 ) Allocator.Error!void {
1694 const map = try self.getOrPutMap(builder.gpa, index);
1695 try map.put(builder.gpa, attribute.getKind(), try builder.attr(attribute));
1696 }
1697
1698 fn addAttrIndex(
1699 self: *Wip,
1700 index: usize,
1701 attribute_index: Attribute.Index,
1702 builder: *const Builder,
1703 ) Allocator.Error!void {
1704 const map = try self.getOrPutMap(builder.gpa, index);
1705 try map.put(builder.gpa, attribute_index.getKind(builder), attribute_index);
1706 }
1707
1708 fn removeAttr(self: *Wip, index: usize, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1709 const map = self.getMap(index) orelse return false;
1710 return map.swapRemove(attribute_kind);
1711 }
1712
1713 fn getOrPutMap(self: *Wip, allocator: Allocator, index: usize) Allocator.Error!*Map {
1714 if (index >= self.maps.items.len)
1715 try self.maps.appendNTimes(allocator, .{}, index + 1 - self.maps.items.len);
1716 return &self.maps.items[index];
1717 }
1718
1719 fn getMap(self: *Wip, index: usize) ?*Map {
1720 return if (index >= self.maps.items.len) null else &self.maps.items[index];
1721 }
1722
1723 fn ensureTotalLength(self: *Wip, new_len: usize) Allocator.Error!void {
1724 try self.maps.appendNTimes(
1725 .{},
1726 std.math.sub(usize, new_len, self.maps.items.len) catch return,
1727 );
1728 }
1729 };
1730
1731 pub fn func(self: FunctionAttributes, builder: *const Builder) Attributes {
1732 return self.get(function_index, builder);
1733 }
1734
1735 pub fn ret(self: FunctionAttributes, builder: *const Builder) Attributes {
1736 return self.get(return_index, builder);
1737 }
1738
1739 pub fn param(self: FunctionAttributes, param_index: usize, builder: *const Builder) Attributes {
1740 return self.get(params_index + param_index, builder);
1741 }
1742
1743 pub fn toWip(self: FunctionAttributes, builder: *const Builder) Allocator.Error!Wip {
1744 var wip: Wip = .{};
1745 errdefer wip.deinit(builder);
1746 const attributes_slice = self.slice(builder);
1747 try wip.maps.ensureTotalCapacityPrecise(builder.gpa, attributes_slice.len);
1748 for (attributes_slice) |attributes| {
1749 const map = wip.maps.addOneAssumeCapacity();
1750 map.* = .{};
1751 const attribute_slice = attributes.slice(builder);
1752 try map.ensureTotalCapacity(builder.gpa, attribute_slice.len);
1753 for (attributes.slice(builder)) |attribute|
1754 map.putAssumeCapacityNoClobber(attribute.getKind(builder), attribute);
1755 }
1756 return wip;
1757 }
1758
1759 fn get(self: FunctionAttributes, index: usize, builder: *const Builder) Attributes {
1760 const attribute_slice = self.slice(builder);
1761 return if (index < attribute_slice.len) attribute_slice[index] else .none;
1762 }
1763
1764 fn slice(self: FunctionAttributes, builder: *const Builder) []const Attributes {
1765 const start = builder.attributes_indices.items[@intFromEnum(self)];
1766 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1767 return @ptrCast(builder.attributes_extra.items[start..end]);
1768 }
1769};
1770
1771pub const Linkage = enum(u4) {
1772 private = 9,
1773 internal = 3,
1774 weak = 1,
1775 weak_odr = 10,
1776 linkonce = 4,
1777 linkonce_odr = 11,
1778 available_externally = 12,
1779 appending = 2,
1780 common = 8,
1781 extern_weak = 7,
1782 external = 0,
1783
1784 pub fn format(
1785 self: Linkage,
1786 comptime _: []const u8,
1787 _: std.fmt.FormatOptions,
1788 writer: anytype,
1789 ) @TypeOf(writer).Error!void {
1790 if (self != .external) try writer.print(" {s}", .{@tagName(self)});
1791 }
1792
1793 fn formatOptional(
1794 data: ?Linkage,
1795 comptime _: []const u8,
1796 _: std.fmt.FormatOptions,
1797 writer: anytype,
1798 ) @TypeOf(writer).Error!void {
1799 if (data) |linkage| try writer.print(" {s}", .{@tagName(linkage)});
1800 }
1801 pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(formatOptional) {
1802 return .{ .data = self };
1803 }
1804};
1805
1806pub const Preemption = enum {
1807 dso_preemptable,
1808 dso_local,
1809 implicit_dso_local,
1810
1811 pub fn format(
1812 self: Preemption,
1813 comptime _: []const u8,
1814 _: std.fmt.FormatOptions,
1815 writer: anytype,
1816 ) @TypeOf(writer).Error!void {
1817 if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)});
1818 }
1819};
1820
1821pub const Visibility = enum(u2) {
1822 default = 0,
1823 hidden = 1,
1824 protected = 2,
1825
1826 pub fn format(
1827 self: Visibility,
1828 comptime _: []const u8,
1829 _: std.fmt.FormatOptions,
1830 writer: anytype,
1831 ) @TypeOf(writer).Error!void {
1832 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1833 }
1834};
1835
1836pub const DllStorageClass = enum(u2) {
1837 default = 0,
1838 dllimport = 1,
1839 dllexport = 2,
1840
1841 pub fn format(
1842 self: DllStorageClass,
1843 comptime _: []const u8,
1844 _: std.fmt.FormatOptions,
1845 writer: anytype,
1846 ) @TypeOf(writer).Error!void {
1847 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1848 }
1849};
1850
1851pub const ThreadLocal = enum(u3) {
1852 default = 0,
1853 generaldynamic = 1,
1854 localdynamic = 2,
1855 initialexec = 3,
1856 localexec = 4,
1857
1858 pub fn format(
1859 self: ThreadLocal,
1860 comptime prefix: []const u8,
1861 _: std.fmt.FormatOptions,
1862 writer: anytype,
1863 ) @TypeOf(writer).Error!void {
1864 if (self == .default) return;
1865 try writer.print("{s}thread_local", .{prefix});
1866 if (self != .generaldynamic) try writer.print("({s})", .{@tagName(self)});
1867 }
1868};
1869
1870pub const Mutability = enum { global, constant };
1871
1872pub const UnnamedAddr = enum(u2) {
1873 default = 0,
1874 unnamed_addr = 1,
1875 local_unnamed_addr = 2,
1876
1877 pub fn format(
1878 self: UnnamedAddr,
1879 comptime _: []const u8,
1880 _: std.fmt.FormatOptions,
1881 writer: anytype,
1882 ) @TypeOf(writer).Error!void {
1883 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1884 }
1885};
1886
1887pub const AddrSpace = enum(u24) {
1888 default,
1889 _,
1890
1891 // See llvm/lib/Target/X86/X86.h
1892 pub const x86 = struct {
1893 pub const gs: AddrSpace = @enumFromInt(256);
1894 pub const fs: AddrSpace = @enumFromInt(257);
1895 pub const ss: AddrSpace = @enumFromInt(258);
1896
1897 pub const ptr32_sptr: AddrSpace = @enumFromInt(270);
1898 pub const ptr32_uptr: AddrSpace = @enumFromInt(271);
1899 pub const ptr64: AddrSpace = @enumFromInt(272);
1900 };
1901 pub const x86_64 = x86;
1902
1903 // See llvm/lib/Target/AVR/AVR.h
1904 pub const avr = struct {
1905 pub const data: AddrSpace = @enumFromInt(0);
1906 pub const program: AddrSpace = @enumFromInt(1);
1907 pub const program1: AddrSpace = @enumFromInt(2);
1908 pub const program2: AddrSpace = @enumFromInt(3);
1909 pub const program3: AddrSpace = @enumFromInt(4);
1910 pub const program4: AddrSpace = @enumFromInt(5);
1911 pub const program5: AddrSpace = @enumFromInt(6);
1912 };
1913
1914 // See llvm/lib/Target/NVPTX/NVPTX.h
1915 pub const nvptx = struct {
1916 pub const generic: AddrSpace = @enumFromInt(0);
1917 pub const global: AddrSpace = @enumFromInt(1);
1918 pub const constant: AddrSpace = @enumFromInt(2);
1919 pub const shared: AddrSpace = @enumFromInt(3);
1920 pub const param: AddrSpace = @enumFromInt(4);
1921 pub const local: AddrSpace = @enumFromInt(5);
1922 };
1923
1924 // See llvm/lib/Target/AMDGPU/AMDGPU.h
1925 pub const amdgpu = struct {
1926 pub const flat: AddrSpace = @enumFromInt(0);
1927 pub const global: AddrSpace = @enumFromInt(1);
1928 pub const region: AddrSpace = @enumFromInt(2);
1929 pub const local: AddrSpace = @enumFromInt(3);
1930 pub const constant: AddrSpace = @enumFromInt(4);
1931 pub const private: AddrSpace = @enumFromInt(5);
1932 pub const constant_32bit: AddrSpace = @enumFromInt(6);
1933 pub const buffer_fat_pointer: AddrSpace = @enumFromInt(7);
1934 pub const buffer_resource: AddrSpace = @enumFromInt(8);
1935 pub const buffer_strided_pointer: AddrSpace = @enumFromInt(9);
1936 pub const param_d: AddrSpace = @enumFromInt(6);
1937 pub const param_i: AddrSpace = @enumFromInt(7);
1938 pub const constant_buffer_0: AddrSpace = @enumFromInt(8);
1939 pub const constant_buffer_1: AddrSpace = @enumFromInt(9);
1940 pub const constant_buffer_2: AddrSpace = @enumFromInt(10);
1941 pub const constant_buffer_3: AddrSpace = @enumFromInt(11);
1942 pub const constant_buffer_4: AddrSpace = @enumFromInt(12);
1943 pub const constant_buffer_5: AddrSpace = @enumFromInt(13);
1944 pub const constant_buffer_6: AddrSpace = @enumFromInt(14);
1945 pub const constant_buffer_7: AddrSpace = @enumFromInt(15);
1946 pub const constant_buffer_8: AddrSpace = @enumFromInt(16);
1947 pub const constant_buffer_9: AddrSpace = @enumFromInt(17);
1948 pub const constant_buffer_10: AddrSpace = @enumFromInt(18);
1949 pub const constant_buffer_11: AddrSpace = @enumFromInt(19);
1950 pub const constant_buffer_12: AddrSpace = @enumFromInt(20);
1951 pub const constant_buffer_13: AddrSpace = @enumFromInt(21);
1952 pub const constant_buffer_14: AddrSpace = @enumFromInt(22);
1953 pub const constant_buffer_15: AddrSpace = @enumFromInt(23);
1954 pub const streamout_register: AddrSpace = @enumFromInt(128);
1955 };
1956
1957 pub const spirv = struct {
1958 pub const function: AddrSpace = @enumFromInt(0);
1959 pub const cross_workgroup: AddrSpace = @enumFromInt(1);
1960 pub const uniform_constant: AddrSpace = @enumFromInt(2);
1961 pub const workgroup: AddrSpace = @enumFromInt(3);
1962 pub const generic: AddrSpace = @enumFromInt(4);
1963 pub const device_only_intel: AddrSpace = @enumFromInt(5);
1964 pub const host_only_intel: AddrSpace = @enumFromInt(6);
1965 pub const input: AddrSpace = @enumFromInt(7);
1966 };
1967
1968 // See llvm/include/llvm/CodeGen/WasmAddressSpaces.h
1969 pub const wasm = struct {
1970 pub const default: AddrSpace = @enumFromInt(0);
1971 pub const variable: AddrSpace = @enumFromInt(1);
1972 pub const externref: AddrSpace = @enumFromInt(10);
1973 pub const funcref: AddrSpace = @enumFromInt(20);
1974 };
1975
1976 pub fn format(
1977 self: AddrSpace,
1978 comptime prefix: []const u8,
1979 _: std.fmt.FormatOptions,
1980 writer: anytype,
1981 ) @TypeOf(writer).Error!void {
1982 if (self != .default) try writer.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) });
1983 }
1984};
1985
1986pub const ExternallyInitialized = enum {
1987 default,
1988 externally_initialized,
1989
1990 pub fn format(
1991 self: ExternallyInitialized,
1992 comptime _: []const u8,
1993 _: std.fmt.FormatOptions,
1994 writer: anytype,
1995 ) @TypeOf(writer).Error!void {
1996 if (self == .default) return;
1997 try writer.writeByte(' ');
1998 try writer.writeAll(@tagName(self));
1999 }
2000};
2001
2002pub const Alignment = enum(u6) {
2003 default = std.math.maxInt(u6),
2004 _,
2005
2006 pub fn fromByteUnits(bytes: u64) Alignment {
2007 if (bytes == 0) return .default;
2008 assert(std.math.isPowerOfTwo(bytes));
2009 assert(bytes <= 1 << 32);
2010 return @enumFromInt(@ctz(bytes));
2011 }
2012
2013 pub fn toByteUnits(self: Alignment) ?u64 {
2014 return if (self == .default) null else @as(u64, 1) << @intFromEnum(self);
2015 }
2016
2017 pub fn toLlvm(self: Alignment) u6 {
2018 return if (self == .default) 0 else (@intFromEnum(self) + 1);
2019 }
2020
2021 pub fn format(
2022 self: Alignment,
2023 comptime prefix: []const u8,
2024 _: std.fmt.FormatOptions,
2025 writer: anytype,
2026 ) @TypeOf(writer).Error!void {
2027 try writer.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return });
2028 }
2029};
2030
2031pub const CallConv = enum(u10) {
2032 ccc,
2033
2034 fastcc = 8,
2035 coldcc,
2036 ghccc,
2037
2038 webkit_jscc = 12,
2039 anyregcc,
2040 preserve_mostcc,
2041 preserve_allcc,
2042 swiftcc,
2043 cxx_fast_tlscc,
2044 tailcc,
2045 cfguard_checkcc,
2046 swifttailcc,
2047
2048 x86_stdcallcc = 64,
2049 x86_fastcallcc,
2050 arm_apcscc,
2051 arm_aapcscc,
2052 arm_aapcs_vfpcc,
2053 msp430_intrcc,
2054 x86_thiscallcc,
2055 ptx_kernel,
2056 ptx_device,
2057
2058 spir_func = 75,
2059 spir_kernel,
2060 intel_ocl_bicc,
2061 x86_64_sysvcc,
2062 win64cc,
2063 x86_vectorcallcc,
2064 hhvmcc,
2065 hhvm_ccc,
2066 x86_intrcc,
2067 avr_intrcc,
2068 avr_signalcc,
2069 avr_builtincc,
2070
2071 amdgpu_vs = 87,
2072 amdgpu_gs,
2073 amdgpu_ps,
2074 amdgpu_cs,
2075 amdgpu_kernel,
2076 x86_regcallcc,
2077 amdgpu_hs,
2078 msp430_builtincc,
2079
2080 amdgpu_ls = 95,
2081 amdgpu_es,
2082 aarch64_vector_pcs,
2083 aarch64_sve_vector_pcs,
2084
2085 amdgpu_gfx = 100,
2086
2087 m68k_intrcc,
2088
2089 aarch64_sme_preservemost_from_x0 = 102,
2090 aarch64_sme_preservemost_from_x2,
2091
2092 m68k_rtdcc = 106,
2093
2094 riscv_vectorcallcc = 110,
2095
2096 _,
2097
2098 pub const default = CallConv.ccc;
2099
2100 pub fn format(
2101 self: CallConv,
2102 comptime _: []const u8,
2103 _: std.fmt.FormatOptions,
2104 writer: anytype,
2105 ) @TypeOf(writer).Error!void {
2106 switch (self) {
2107 default => {},
2108 .fastcc,
2109 .coldcc,
2110 .ghccc,
2111 .webkit_jscc,
2112 .anyregcc,
2113 .preserve_mostcc,
2114 .preserve_allcc,
2115 .swiftcc,
2116 .cxx_fast_tlscc,
2117 .tailcc,
2118 .cfguard_checkcc,
2119 .swifttailcc,
2120 .x86_stdcallcc,
2121 .x86_fastcallcc,
2122 .arm_apcscc,
2123 .arm_aapcscc,
2124 .arm_aapcs_vfpcc,
2125 .msp430_intrcc,
2126 .x86_thiscallcc,
2127 .ptx_kernel,
2128 .ptx_device,
2129 .spir_func,
2130 .spir_kernel,
2131 .intel_ocl_bicc,
2132 .x86_64_sysvcc,
2133 .win64cc,
2134 .x86_vectorcallcc,
2135 .hhvmcc,
2136 .hhvm_ccc,
2137 .x86_intrcc,
2138 .avr_intrcc,
2139 .avr_signalcc,
2140 .avr_builtincc,
2141 .amdgpu_vs,
2142 .amdgpu_gs,
2143 .amdgpu_ps,
2144 .amdgpu_cs,
2145 .amdgpu_kernel,
2146 .x86_regcallcc,
2147 .amdgpu_hs,
2148 .msp430_builtincc,
2149 .amdgpu_ls,
2150 .amdgpu_es,
2151 .aarch64_vector_pcs,
2152 .aarch64_sve_vector_pcs,
2153 .amdgpu_gfx,
2154 .m68k_intrcc,
2155 .aarch64_sme_preservemost_from_x0,
2156 .aarch64_sme_preservemost_from_x2,
2157 .m68k_rtdcc,
2158 .riscv_vectorcallcc,
2159 => try writer.print(" {s}", .{@tagName(self)}),
2160 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
2161 }
2162 }
2163};
2164
2165pub const StrtabString = enum(u32) {
2166 none = std.math.maxInt(u31),
2167 empty,
2168 _,
2169
2170 pub fn isAnon(self: StrtabString) bool {
2171 assert(self != .none);
2172 return self.toIndex() == null;
2173 }
2174
2175 pub fn slice(self: StrtabString, builder: *const Builder) ?[]const u8 {
2176 const index = self.toIndex() orelse return null;
2177 const start = builder.strtab_string_indices.items[index];
2178 const end = builder.strtab_string_indices.items[index + 1];
2179 return builder.strtab_string_bytes.items[start..end];
2180 }
2181
2182 const FormatData = struct {
2183 string: StrtabString,
2184 builder: *const Builder,
2185 };
2186 fn format(
2187 data: FormatData,
2188 comptime fmt_str: []const u8,
2189 _: std.fmt.FormatOptions,
2190 writer: anytype,
2191 ) @TypeOf(writer).Error!void {
2192 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_|
2193 @compileError("invalid format string: '" ++ fmt_str ++ "'");
2194 assert(data.string != .none);
2195 const string_slice = data.string.slice(data.builder) orelse
2196 return writer.print("{d}", .{@intFromEnum(data.string)});
2197 if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_|
2198 return writer.writeAll(string_slice);
2199 try printEscapedString(
2200 string_slice,
2201 if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
2202 .always_quote
2203 else
2204 .quote_unless_valid_identifier,
2205 writer,
2206 );
2207 }
2208 pub fn fmt(self: StrtabString, builder: *const Builder) std.fmt.Formatter(format) {
2209 return .{ .data = .{ .string = self, .builder = builder } };
2210 }
2211
2212 fn fromIndex(index: ?usize) StrtabString {
2213 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
2214 @intFromEnum(StrtabString.empty))));
2215 }
2216
2217 fn toIndex(self: StrtabString) ?usize {
2218 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(StrtabString.empty)) catch null;
2219 }
2220
2221 const Adapter = struct {
2222 builder: *const Builder,
2223 pub fn hash(_: Adapter, key: []const u8) u32 {
2224 return @truncate(std.hash.Wyhash.hash(0, key));
2225 }
2226 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
2227 return std.mem.eql(u8, lhs_key, StrtabString.fromIndex(rhs_index).slice(ctx.builder).?);
2228 }
2229 };
2230};
2231
2232pub fn strtabString(self: *Builder, bytes: []const u8) Allocator.Error!StrtabString {
2233 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, bytes.len);
2234 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
2235 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
2236
2237 const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self });
2238 if (!gop.found_existing) {
2239 self.strtab_string_bytes.appendSliceAssumeCapacity(bytes);
2240 self.strtab_string_indices.appendAssumeCapacity(@intCast(self.strtab_string_bytes.items.len));
2241 }
2242 return StrtabString.fromIndex(gop.index);
2243}
2244
2245pub fn strtabStringIfExists(self: *const Builder, bytes: []const u8) ?StrtabString {
2246 return StrtabString.fromIndex(
2247 self.strtab_string_map.getIndexAdapted(bytes, StrtabString.Adapter{ .builder = self }) orelse return null,
2248 );
2249}
2250
2251pub fn strtabStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allocator.Error!StrtabString {
2252 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
2253 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, @intCast(std.fmt.count(fmt_str, fmt_args)));
2254 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
2255 return self.strtabStringFmtAssumeCapacity(fmt_str, fmt_args);
2256}
2257
2258pub fn strtabStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) StrtabString {
2259 self.strtab_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
2260 return self.trailingStrtabStringAssumeCapacity();
2261}
2262
2263pub fn trailingStrtabString(self: *Builder) Allocator.Error!StrtabString {
2264 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
2265 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
2266 return self.trailingStrtabStringAssumeCapacity();
2267}
2268
2269pub fn trailingStrtabStringAssumeCapacity(self: *Builder) StrtabString {
2270 const start = self.strtab_string_indices.getLast();
2271 const bytes: []const u8 = self.strtab_string_bytes.items[start..];
2272 const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self });
2273 if (gop.found_existing) {
2274 self.strtab_string_bytes.shrinkRetainingCapacity(start);
2275 } else {
2276 self.strtab_string_indices.appendAssumeCapacity(@intCast(self.strtab_string_bytes.items.len));
2277 }
2278 return StrtabString.fromIndex(gop.index);
2279}
2280
2281pub const Global = struct {
2282 linkage: Linkage = .external,
2283 preemption: Preemption = .dso_preemptable,
2284 visibility: Visibility = .default,
2285 dll_storage_class: DllStorageClass = .default,
2286 unnamed_addr: UnnamedAddr = .default,
2287 addr_space: AddrSpace = .default,
2288 externally_initialized: ExternallyInitialized = .default,
2289 type: Type,
2290 partition: String = .none,
2291 dbg: Metadata = .none,
2292 kind: union(enum) {
2293 alias: Alias.Index,
2294 variable: Variable.Index,
2295 function: Function.Index,
2296 replaced: Global.Index,
2297 },
2298
2299 pub const Index = enum(u32) {
2300 none = std.math.maxInt(u32),
2301 _,
2302
2303 pub fn unwrap(self: Index, builder: *const Builder) Index {
2304 var cur = self;
2305 while (true) {
2306 const replacement = cur.getReplacement(builder);
2307 if (replacement == .none) return cur;
2308 cur = replacement;
2309 }
2310 }
2311
2312 pub fn eql(self: Index, other: Index, builder: *const Builder) bool {
2313 return self.unwrap(builder) == other.unwrap(builder);
2314 }
2315
2316 pub fn ptr(self: Index, builder: *Builder) *Global {
2317 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
2318 }
2319
2320 pub fn ptrConst(self: Index, builder: *const Builder) *const Global {
2321 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
2322 }
2323
2324 pub fn name(self: Index, builder: *const Builder) StrtabString {
2325 return builder.globals.keys()[@intFromEnum(self.unwrap(builder))];
2326 }
2327
2328 pub fn strtab(self: Index, builder: *const Builder) struct {
2329 offset: u32,
2330 size: u32,
2331 } {
2332 const name_index = self.name(builder).toIndex() orelse return .{
2333 .offset = 0,
2334 .size = 0,
2335 };
2336
2337 return .{
2338 .offset = builder.strtab_string_indices.items[name_index],
2339 .size = builder.strtab_string_indices.items[name_index + 1] -
2340 builder.strtab_string_indices.items[name_index],
2341 };
2342 }
2343
2344 pub fn typeOf(self: Index, builder: *const Builder) Type {
2345 return self.ptrConst(builder).type;
2346 }
2347
2348 pub fn toConst(self: Index) Constant {
2349 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
2350 }
2351
2352 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
2353 self.ptr(builder).linkage = linkage;
2354 self.updateDsoLocal(builder);
2355 }
2356
2357 pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
2358 self.ptr(builder).visibility = visibility;
2359 self.updateDsoLocal(builder);
2360 }
2361
2362 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2363 self.ptr(builder).dll_storage_class = class;
2364 }
2365
2366 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
2367 self.ptr(builder).unnamed_addr = unnamed_addr;
2368 }
2369
2370 pub fn setDebugMetadata(self: Index, dbg: Metadata, builder: *Builder) void {
2371 self.ptr(builder).dbg = dbg;
2372 }
2373
2374 const FormatData = struct {
2375 global: Index,
2376 builder: *const Builder,
2377 };
2378 fn format(
2379 data: FormatData,
2380 comptime _: []const u8,
2381 _: std.fmt.FormatOptions,
2382 writer: anytype,
2383 ) @TypeOf(writer).Error!void {
2384 try writer.print("@{}", .{
2385 data.global.unwrap(data.builder).name(data.builder).fmt(data.builder),
2386 });
2387 }
2388 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
2389 return .{ .data = .{ .global = self, .builder = builder } };
2390 }
2391
2392 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
2393 try builder.ensureUnusedGlobalCapacity(new_name);
2394 self.renameAssumeCapacity(new_name, builder);
2395 }
2396
2397 pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
2398 try builder.ensureUnusedGlobalCapacity(.empty);
2399 self.takeNameAssumeCapacity(other, builder);
2400 }
2401
2402 pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
2403 try builder.ensureUnusedGlobalCapacity(.empty);
2404 self.replaceAssumeCapacity(other, builder);
2405 }
2406
2407 pub fn delete(self: Index, builder: *Builder) void {
2408 self.ptr(builder).kind = .{ .replaced = .none };
2409 }
2410
2411 fn updateDsoLocal(self: Index, builder: *Builder) void {
2412 const self_ptr = self.ptr(builder);
2413 switch (self_ptr.linkage) {
2414 .private, .internal => {
2415 self_ptr.visibility = .default;
2416 self_ptr.dll_storage_class = .default;
2417 self_ptr.preemption = .implicit_dso_local;
2418 },
2419 .extern_weak => if (self_ptr.preemption == .implicit_dso_local) {
2420 self_ptr.preemption = .dso_local;
2421 },
2422 else => switch (self_ptr.visibility) {
2423 .default => if (self_ptr.preemption == .implicit_dso_local) {
2424 self_ptr.preemption = .dso_local;
2425 },
2426 else => self_ptr.preemption = .implicit_dso_local,
2427 },
2428 }
2429 }
2430
2431 fn renameAssumeCapacity(self: Index, new_name: StrtabString, builder: *Builder) void {
2432 const old_name = self.name(builder);
2433 if (new_name == old_name) return;
2434 const index = @intFromEnum(self.unwrap(builder));
2435 _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]);
2436 builder.globals.swapRemoveAt(index);
2437 if (!old_name.isAnon()) return;
2438 builder.next_unnamed_global = @enumFromInt(@intFromEnum(builder.next_unnamed_global) - 1);
2439 if (builder.next_unnamed_global == old_name) return;
2440 builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder);
2441 }
2442
2443 fn takeNameAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
2444 const other_name = other.name(builder);
2445 other.renameAssumeCapacity(.empty, builder);
2446 self.renameAssumeCapacity(other_name, builder);
2447 }
2448
2449 fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
2450 if (self.eql(other, builder)) return;
2451 builder.next_replaced_global = @enumFromInt(@intFromEnum(builder.next_replaced_global) - 1);
2452 self.renameAssumeCapacity(builder.next_replaced_global, builder);
2453 self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
2454 }
2455
2456 fn getReplacement(self: Index, builder: *const Builder) Index {
2457 return switch (builder.globals.values()[@intFromEnum(self)].kind) {
2458 .replaced => |replacement| replacement,
2459 else => .none,
2460 };
2461 }
2462 };
2463};
2464
2465pub const Alias = struct {
2466 global: Global.Index,
2467 thread_local: ThreadLocal = .default,
2468 aliasee: Constant = .no_init,
2469
2470 pub const Index = enum(u32) {
2471 none = std.math.maxInt(u32),
2472 _,
2473
2474 pub fn ptr(self: Index, builder: *Builder) *Alias {
2475 return &builder.aliases.items[@intFromEnum(self)];
2476 }
2477
2478 pub fn ptrConst(self: Index, builder: *const Builder) *const Alias {
2479 return &builder.aliases.items[@intFromEnum(self)];
2480 }
2481
2482 pub fn name(self: Index, builder: *const Builder) StrtabString {
2483 return self.ptrConst(builder).global.name(builder);
2484 }
2485
2486 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
2487 return self.ptrConst(builder).global.rename(new_name, builder);
2488 }
2489
2490 pub fn typeOf(self: Index, builder: *const Builder) Type {
2491 return self.ptrConst(builder).global.typeOf(builder);
2492 }
2493
2494 pub fn toConst(self: Index, builder: *const Builder) Constant {
2495 return self.ptrConst(builder).global.toConst();
2496 }
2497
2498 pub fn toValue(self: Index, builder: *const Builder) Value {
2499 return self.toConst(builder).toValue();
2500 }
2501
2502 pub fn getAliasee(self: Index, builder: *const Builder) Global.Index {
2503 const aliasee = self.ptrConst(builder).aliasee.getBase(builder);
2504 assert(aliasee != .none);
2505 return aliasee;
2506 }
2507
2508 pub fn setAliasee(self: Index, aliasee: Constant, builder: *Builder) void {
2509 self.ptr(builder).aliasee = aliasee;
2510 }
2511 };
2512};
2513
2514pub const Variable = struct {
2515 global: Global.Index,
2516 thread_local: ThreadLocal = .default,
2517 mutability: Mutability = .global,
2518 init: Constant = .no_init,
2519 section: String = .none,
2520 alignment: Alignment = .default,
2521
2522 pub const Index = enum(u32) {
2523 none = std.math.maxInt(u32),
2524 _,
2525
2526 pub fn ptr(self: Index, builder: *Builder) *Variable {
2527 return &builder.variables.items[@intFromEnum(self)];
2528 }
2529
2530 pub fn ptrConst(self: Index, builder: *const Builder) *const Variable {
2531 return &builder.variables.items[@intFromEnum(self)];
2532 }
2533
2534 pub fn name(self: Index, builder: *const Builder) StrtabString {
2535 return self.ptrConst(builder).global.name(builder);
2536 }
2537
2538 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
2539 return self.ptrConst(builder).global.rename(new_name, builder);
2540 }
2541
2542 pub fn typeOf(self: Index, builder: *const Builder) Type {
2543 return self.ptrConst(builder).global.typeOf(builder);
2544 }
2545
2546 pub fn toConst(self: Index, builder: *const Builder) Constant {
2547 return self.ptrConst(builder).global.toConst();
2548 }
2549
2550 pub fn toValue(self: Index, builder: *const Builder) Value {
2551 return self.toConst(builder).toValue();
2552 }
2553
2554 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
2555 return self.ptrConst(builder).global.setLinkage(linkage, builder);
2556 }
2557
2558 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2559 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
2560 }
2561
2562 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
2563 return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
2564 }
2565
2566 pub fn setThreadLocal(self: Index, thread_local: ThreadLocal, builder: *Builder) void {
2567 self.ptr(builder).thread_local = thread_local;
2568 }
2569
2570 pub fn setMutability(self: Index, mutability: Mutability, builder: *Builder) void {
2571 self.ptr(builder).mutability = mutability;
2572 }
2573
2574 pub fn setInitializer(
2575 self: Index,
2576 initializer: Constant,
2577 builder: *Builder,
2578 ) Allocator.Error!void {
2579 if (initializer != .no_init) {
2580 const variable = self.ptrConst(builder);
2581 const global = variable.global.ptr(builder);
2582 const initializer_type = initializer.typeOf(builder);
2583 global.type = initializer_type;
2584 }
2585 self.ptr(builder).init = initializer;
2586 }
2587
2588 pub fn setSection(self: Index, section: String, builder: *Builder) void {
2589 self.ptr(builder).section = section;
2590 }
2591
2592 pub fn setAlignment(self: Index, alignment: Alignment, builder: *Builder) void {
2593 self.ptr(builder).alignment = alignment;
2594 }
2595
2596 pub fn getAlignment(self: Index, builder: *Builder) Alignment {
2597 return self.ptr(builder).alignment;
2598 }
2599
2600 pub fn setGlobalVariableExpression(self: Index, expression: Metadata, builder: *Builder) void {
2601 self.ptrConst(builder).global.setDebugMetadata(expression, builder);
2602 }
2603 };
2604};
2605
2606pub const Intrinsic = enum {
2607 // Variable Argument Handling
2608 va_start,
2609 va_end,
2610 va_copy,
2611
2612 // Code Generator
2613 returnaddress,
2614 addressofreturnaddress,
2615 sponentry,
2616 frameaddress,
2617 prefetch,
2618 @"thread.pointer",
2619
2620 // Standard C/C++ Library
2621 abs,
2622 smax,
2623 smin,
2624 umax,
2625 umin,
2626 memcpy,
2627 @"memcpy.inline",
2628 memmove,
2629 memset,
2630 @"memset.inline",
2631 sqrt,
2632 powi,
2633 sin,
2634 cos,
2635 pow,
2636 exp,
2637 exp10,
2638 exp2,
2639 ldexp,
2640 frexp,
2641 log,
2642 log10,
2643 log2,
2644 fma,
2645 fabs,
2646 minnum,
2647 maxnum,
2648 minimum,
2649 maximum,
2650 copysign,
2651 floor,
2652 ceil,
2653 trunc,
2654 rint,
2655 nearbyint,
2656 round,
2657 roundeven,
2658 lround,
2659 llround,
2660 lrint,
2661 llrint,
2662
2663 // Bit Manipulation
2664 bitreverse,
2665 bswap,
2666 ctpop,
2667 ctlz,
2668 cttz,
2669 fshl,
2670 fshr,
2671
2672 // Arithmetic with Overflow
2673 @"sadd.with.overflow",
2674 @"uadd.with.overflow",
2675 @"ssub.with.overflow",
2676 @"usub.with.overflow",
2677 @"smul.with.overflow",
2678 @"umul.with.overflow",
2679
2680 // Saturation Arithmetic
2681 @"sadd.sat",
2682 @"uadd.sat",
2683 @"ssub.sat",
2684 @"usub.sat",
2685 @"sshl.sat",
2686 @"ushl.sat",
2687
2688 // Fixed Point Arithmetic
2689 @"smul.fix",
2690 @"umul.fix",
2691 @"smul.fix.sat",
2692 @"umul.fix.sat",
2693 @"sdiv.fix",
2694 @"udiv.fix",
2695 @"sdiv.fix.sat",
2696 @"udiv.fix.sat",
2697
2698 // Specialised Arithmetic
2699 canonicalize,
2700 fmuladd,
2701
2702 // Vector Reduction
2703 @"vector.reduce.add",
2704 @"vector.reduce.fadd",
2705 @"vector.reduce.mul",
2706 @"vector.reduce.fmul",
2707 @"vector.reduce.and",
2708 @"vector.reduce.or",
2709 @"vector.reduce.xor",
2710 @"vector.reduce.smax",
2711 @"vector.reduce.smin",
2712 @"vector.reduce.umax",
2713 @"vector.reduce.umin",
2714 @"vector.reduce.fmax",
2715 @"vector.reduce.fmin",
2716 @"vector.reduce.fmaximum",
2717 @"vector.reduce.fminimum",
2718 @"vector.insert",
2719 @"vector.extract",
2720
2721 // Floating-Point Test
2722 @"is.fpclass",
2723
2724 // General
2725 @"var.annotation",
2726 @"ptr.annotation",
2727 annotation,
2728 @"codeview.annotation",
2729 trap,
2730 debugtrap,
2731 ubsantrap,
2732 stackprotector,
2733 stackguard,
2734 objectsize,
2735 expect,
2736 @"expect.with.probability",
2737 assume,
2738 @"ssa.copy",
2739 @"type.test",
2740 @"type.checked.load",
2741 @"type.checked.load.relative",
2742 @"arithmetic.fence",
2743 donothing,
2744 @"load.relative",
2745 sideeffect,
2746 @"is.constant",
2747 ptrmask,
2748 @"threadlocal.address",
2749 vscale,
2750
2751 // Debug
2752 @"dbg.declare",
2753 @"dbg.value",
2754
2755 // AMDGPU
2756 @"amdgcn.workitem.id.x",
2757 @"amdgcn.workitem.id.y",
2758 @"amdgcn.workitem.id.z",
2759 @"amdgcn.workgroup.id.x",
2760 @"amdgcn.workgroup.id.y",
2761 @"amdgcn.workgroup.id.z",
2762 @"amdgcn.dispatch.ptr",
2763
2764 // NVPTX
2765 @"nvvm.read.ptx.sreg.tid.x",
2766 @"nvvm.read.ptx.sreg.tid.y",
2767 @"nvvm.read.ptx.sreg.tid.z",
2768 @"nvvm.read.ptx.sreg.ntid.x",
2769 @"nvvm.read.ptx.sreg.ntid.y",
2770 @"nvvm.read.ptx.sreg.ntid.z",
2771 @"nvvm.read.ptx.sreg.ctaid.x",
2772 @"nvvm.read.ptx.sreg.ctaid.y",
2773 @"nvvm.read.ptx.sreg.ctaid.z",
2774
2775 // WebAssembly
2776 @"wasm.memory.size",
2777 @"wasm.memory.grow",
2778
2779 const Signature = struct {
2780 ret_len: u8,
2781 params: []const Parameter,
2782 attrs: []const Attribute = &.{},
2783
2784 const Parameter = struct {
2785 kind: Kind,
2786 attrs: []const Attribute = &.{},
2787
2788 const Kind = union(enum) {
2789 type: Type,
2790 overloaded,
2791 matches: u8,
2792 matches_scalar: u8,
2793 matches_changed_scalar: struct {
2794 index: u8,
2795 scalar: Type,
2796 },
2797 };
2798 };
2799 };
2800
2801 const signatures = std.enums.EnumArray(Intrinsic, Signature).init(.{
2802 .va_start = .{
2803 .ret_len = 0,
2804 .params = &.{
2805 .{ .kind = .overloaded },
2806 },
2807 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2808 },
2809 .va_end = .{
2810 .ret_len = 0,
2811 .params = &.{
2812 .{ .kind = .overloaded },
2813 },
2814 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2815 },
2816 .va_copy = .{
2817 .ret_len = 0,
2818 .params = &.{
2819 .{ .kind = .overloaded },
2820 .{ .kind = .{ .matches = 0 } },
2821 },
2822 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2823 },
2824
2825 .returnaddress = .{
2826 .ret_len = 1,
2827 .params = &.{
2828 .{ .kind = .{ .type = .ptr } },
2829 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2830 },
2831 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2832 },
2833 .addressofreturnaddress = .{
2834 .ret_len = 1,
2835 .params = &.{
2836 .{ .kind = .overloaded },
2837 },
2838 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2839 },
2840 .sponentry = .{
2841 .ret_len = 1,
2842 .params = &.{
2843 .{ .kind = .overloaded },
2844 },
2845 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2846 },
2847 .frameaddress = .{
2848 .ret_len = 1,
2849 .params = &.{
2850 .{ .kind = .overloaded },
2851 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2852 },
2853 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2854 },
2855 .prefetch = .{
2856 .ret_len = 0,
2857 .params = &.{
2858 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .readonly } },
2859 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2860 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2861 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2862 },
2863 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.readwrite) } },
2864 },
2865 .@"thread.pointer" = .{
2866 .ret_len = 1,
2867 .params = &.{
2868 .{ .kind = .{ .type = .ptr } },
2869 },
2870 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2871 },
2872
2873 .abs = .{
2874 .ret_len = 1,
2875 .params = &.{
2876 .{ .kind = .overloaded },
2877 .{ .kind = .{ .matches = 0 } },
2878 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2879 },
2880 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2881 },
2882 .smax = .{
2883 .ret_len = 1,
2884 .params = &.{
2885 .{ .kind = .overloaded },
2886 .{ .kind = .{ .matches = 0 } },
2887 .{ .kind = .{ .matches = 0 } },
2888 },
2889 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2890 },
2891 .smin = .{
2892 .ret_len = 1,
2893 .params = &.{
2894 .{ .kind = .overloaded },
2895 .{ .kind = .{ .matches = 0 } },
2896 .{ .kind = .{ .matches = 0 } },
2897 },
2898 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2899 },
2900 .umax = .{
2901 .ret_len = 1,
2902 .params = &.{
2903 .{ .kind = .overloaded },
2904 .{ .kind = .{ .matches = 0 } },
2905 .{ .kind = .{ .matches = 0 } },
2906 },
2907 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2908 },
2909 .umin = .{
2910 .ret_len = 1,
2911 .params = &.{
2912 .{ .kind = .overloaded },
2913 .{ .kind = .{ .matches = 0 } },
2914 .{ .kind = .{ .matches = 0 } },
2915 },
2916 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2917 },
2918 .memcpy = .{
2919 .ret_len = 0,
2920 .params = &.{
2921 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
2922 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
2923 .{ .kind = .overloaded },
2924 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2925 },
2926 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
2927 },
2928 .@"memcpy.inline" = .{
2929 .ret_len = 0,
2930 .params = &.{
2931 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
2932 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
2933 .{ .kind = .overloaded },
2934 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2935 },
2936 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
2937 },
2938 .memmove = .{
2939 .ret_len = 0,
2940 .params = &.{
2941 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
2942 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .readonly } },
2943 .{ .kind = .overloaded },
2944 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2945 },
2946 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
2947 },
2948 .memset = .{
2949 .ret_len = 0,
2950 .params = &.{
2951 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
2952 .{ .kind = .{ .type = .i8 } },
2953 .{ .kind = .overloaded },
2954 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2955 },
2956 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
2957 },
2958 .@"memset.inline" = .{
2959 .ret_len = 0,
2960 .params = &.{
2961 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
2962 .{ .kind = .{ .type = .i8 } },
2963 .{ .kind = .overloaded },
2964 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2965 },
2966 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
2967 },
2968 .sqrt = .{
2969 .ret_len = 1,
2970 .params = &.{
2971 .{ .kind = .overloaded },
2972 .{ .kind = .{ .matches = 0 } },
2973 },
2974 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2975 },
2976 .powi = .{
2977 .ret_len = 1,
2978 .params = &.{
2979 .{ .kind = .overloaded },
2980 .{ .kind = .{ .matches = 0 } },
2981 .{ .kind = .overloaded },
2982 },
2983 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2984 },
2985 .sin = .{
2986 .ret_len = 1,
2987 .params = &.{
2988 .{ .kind = .overloaded },
2989 .{ .kind = .{ .matches = 0 } },
2990 },
2991 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2992 },
2993 .cos = .{
2994 .ret_len = 1,
2995 .params = &.{
2996 .{ .kind = .overloaded },
2997 .{ .kind = .{ .matches = 0 } },
2998 },
2999 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3000 },
3001 .pow = .{
3002 .ret_len = 1,
3003 .params = &.{
3004 .{ .kind = .overloaded },
3005 .{ .kind = .{ .matches = 0 } },
3006 .{ .kind = .{ .matches = 0 } },
3007 },
3008 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3009 },
3010 .exp = .{
3011 .ret_len = 1,
3012 .params = &.{
3013 .{ .kind = .overloaded },
3014 .{ .kind = .{ .matches = 0 } },
3015 },
3016 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3017 },
3018 .exp2 = .{
3019 .ret_len = 1,
3020 .params = &.{
3021 .{ .kind = .overloaded },
3022 .{ .kind = .{ .matches = 0 } },
3023 },
3024 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3025 },
3026 .exp10 = .{
3027 .ret_len = 1,
3028 .params = &.{
3029 .{ .kind = .overloaded },
3030 .{ .kind = .{ .matches = 0 } },
3031 },
3032 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3033 },
3034 .ldexp = .{
3035 .ret_len = 1,
3036 .params = &.{
3037 .{ .kind = .overloaded },
3038 .{ .kind = .{ .matches = 0 } },
3039 .{ .kind = .overloaded },
3040 },
3041 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3042 },
3043 .frexp = .{
3044 .ret_len = 2,
3045 .params = &.{
3046 .{ .kind = .overloaded },
3047 .{ .kind = .overloaded },
3048 .{ .kind = .{ .matches = 0 } },
3049 },
3050 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3051 },
3052 .log = .{
3053 .ret_len = 1,
3054 .params = &.{
3055 .{ .kind = .overloaded },
3056 .{ .kind = .{ .matches = 0 } },
3057 },
3058 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3059 },
3060 .log10 = .{
3061 .ret_len = 1,
3062 .params = &.{
3063 .{ .kind = .overloaded },
3064 .{ .kind = .{ .matches = 0 } },
3065 },
3066 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3067 },
3068 .log2 = .{
3069 .ret_len = 1,
3070 .params = &.{
3071 .{ .kind = .overloaded },
3072 .{ .kind = .{ .matches = 0 } },
3073 },
3074 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3075 },
3076 .fma = .{
3077 .ret_len = 1,
3078 .params = &.{
3079 .{ .kind = .overloaded },
3080 .{ .kind = .{ .matches = 0 } },
3081 .{ .kind = .{ .matches = 0 } },
3082 .{ .kind = .{ .matches = 0 } },
3083 },
3084 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3085 },
3086 .fabs = .{
3087 .ret_len = 1,
3088 .params = &.{
3089 .{ .kind = .overloaded },
3090 .{ .kind = .{ .matches = 0 } },
3091 },
3092 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3093 },
3094 .minnum = .{
3095 .ret_len = 1,
3096 .params = &.{
3097 .{ .kind = .overloaded },
3098 .{ .kind = .{ .matches = 0 } },
3099 .{ .kind = .{ .matches = 0 } },
3100 },
3101 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3102 },
3103 .maxnum = .{
3104 .ret_len = 1,
3105 .params = &.{
3106 .{ .kind = .overloaded },
3107 .{ .kind = .{ .matches = 0 } },
3108 .{ .kind = .{ .matches = 0 } },
3109 },
3110 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3111 },
3112 .minimum = .{
3113 .ret_len = 1,
3114 .params = &.{
3115 .{ .kind = .overloaded },
3116 .{ .kind = .{ .matches = 0 } },
3117 .{ .kind = .{ .matches = 0 } },
3118 },
3119 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3120 },
3121 .maximum = .{
3122 .ret_len = 1,
3123 .params = &.{
3124 .{ .kind = .overloaded },
3125 .{ .kind = .{ .matches = 0 } },
3126 .{ .kind = .{ .matches = 0 } },
3127 },
3128 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3129 },
3130 .copysign = .{
3131 .ret_len = 1,
3132 .params = &.{
3133 .{ .kind = .overloaded },
3134 .{ .kind = .{ .matches = 0 } },
3135 .{ .kind = .{ .matches = 0 } },
3136 },
3137 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3138 },
3139 .floor = .{
3140 .ret_len = 1,
3141 .params = &.{
3142 .{ .kind = .overloaded },
3143 .{ .kind = .{ .matches = 0 } },
3144 },
3145 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3146 },
3147 .ceil = .{
3148 .ret_len = 1,
3149 .params = &.{
3150 .{ .kind = .overloaded },
3151 .{ .kind = .{ .matches = 0 } },
3152 },
3153 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3154 },
3155 .trunc = .{
3156 .ret_len = 1,
3157 .params = &.{
3158 .{ .kind = .overloaded },
3159 .{ .kind = .{ .matches = 0 } },
3160 },
3161 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3162 },
3163 .rint = .{
3164 .ret_len = 1,
3165 .params = &.{
3166 .{ .kind = .overloaded },
3167 .{ .kind = .{ .matches = 0 } },
3168 },
3169 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3170 },
3171 .nearbyint = .{
3172 .ret_len = 1,
3173 .params = &.{
3174 .{ .kind = .overloaded },
3175 .{ .kind = .{ .matches = 0 } },
3176 },
3177 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3178 },
3179 .round = .{
3180 .ret_len = 1,
3181 .params = &.{
3182 .{ .kind = .overloaded },
3183 .{ .kind = .{ .matches = 0 } },
3184 },
3185 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3186 },
3187 .roundeven = .{
3188 .ret_len = 1,
3189 .params = &.{
3190 .{ .kind = .overloaded },
3191 .{ .kind = .{ .matches = 0 } },
3192 },
3193 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3194 },
3195 .lround = .{
3196 .ret_len = 1,
3197 .params = &.{
3198 .{ .kind = .overloaded },
3199 .{ .kind = .overloaded },
3200 },
3201 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3202 },
3203 .llround = .{
3204 .ret_len = 1,
3205 .params = &.{
3206 .{ .kind = .overloaded },
3207 .{ .kind = .overloaded },
3208 },
3209 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3210 },
3211 .lrint = .{
3212 .ret_len = 1,
3213 .params = &.{
3214 .{ .kind = .overloaded },
3215 .{ .kind = .overloaded },
3216 },
3217 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3218 },
3219 .llrint = .{
3220 .ret_len = 1,
3221 .params = &.{
3222 .{ .kind = .overloaded },
3223 .{ .kind = .overloaded },
3224 },
3225 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3226 },
3227
3228 .bitreverse = .{
3229 .ret_len = 1,
3230 .params = &.{
3231 .{ .kind = .overloaded },
3232 .{ .kind = .{ .matches = 0 } },
3233 },
3234 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3235 },
3236 .bswap = .{
3237 .ret_len = 1,
3238 .params = &.{
3239 .{ .kind = .overloaded },
3240 .{ .kind = .{ .matches = 0 } },
3241 },
3242 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3243 },
3244 .ctpop = .{
3245 .ret_len = 1,
3246 .params = &.{
3247 .{ .kind = .overloaded },
3248 .{ .kind = .{ .matches = 0 } },
3249 },
3250 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3251 },
3252 .ctlz = .{
3253 .ret_len = 1,
3254 .params = &.{
3255 .{ .kind = .overloaded },
3256 .{ .kind = .{ .matches = 0 } },
3257 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3258 },
3259 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3260 },
3261 .cttz = .{
3262 .ret_len = 1,
3263 .params = &.{
3264 .{ .kind = .overloaded },
3265 .{ .kind = .{ .matches = 0 } },
3266 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3267 },
3268 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3269 },
3270 .fshl = .{
3271 .ret_len = 1,
3272 .params = &.{
3273 .{ .kind = .overloaded },
3274 .{ .kind = .{ .matches = 0 } },
3275 .{ .kind = .{ .matches = 0 } },
3276 .{ .kind = .{ .matches = 0 } },
3277 },
3278 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3279 },
3280 .fshr = .{
3281 .ret_len = 1,
3282 .params = &.{
3283 .{ .kind = .overloaded },
3284 .{ .kind = .{ .matches = 0 } },
3285 .{ .kind = .{ .matches = 0 } },
3286 .{ .kind = .{ .matches = 0 } },
3287 },
3288 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3289 },
3290
3291 .@"sadd.with.overflow" = .{
3292 .ret_len = 2,
3293 .params = &.{
3294 .{ .kind = .overloaded },
3295 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3296 .{ .kind = .{ .matches = 0 } },
3297 .{ .kind = .{ .matches = 0 } },
3298 },
3299 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3300 },
3301 .@"uadd.with.overflow" = .{
3302 .ret_len = 2,
3303 .params = &.{
3304 .{ .kind = .overloaded },
3305 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3306 .{ .kind = .{ .matches = 0 } },
3307 .{ .kind = .{ .matches = 0 } },
3308 },
3309 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3310 },
3311 .@"ssub.with.overflow" = .{
3312 .ret_len = 2,
3313 .params = &.{
3314 .{ .kind = .overloaded },
3315 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3316 .{ .kind = .{ .matches = 0 } },
3317 .{ .kind = .{ .matches = 0 } },
3318 },
3319 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3320 },
3321 .@"usub.with.overflow" = .{
3322 .ret_len = 2,
3323 .params = &.{
3324 .{ .kind = .overloaded },
3325 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3326 .{ .kind = .{ .matches = 0 } },
3327 .{ .kind = .{ .matches = 0 } },
3328 },
3329 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3330 },
3331 .@"smul.with.overflow" = .{
3332 .ret_len = 2,
3333 .params = &.{
3334 .{ .kind = .overloaded },
3335 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3336 .{ .kind = .{ .matches = 0 } },
3337 .{ .kind = .{ .matches = 0 } },
3338 },
3339 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3340 },
3341 .@"umul.with.overflow" = .{
3342 .ret_len = 2,
3343 .params = &.{
3344 .{ .kind = .overloaded },
3345 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3346 .{ .kind = .{ .matches = 0 } },
3347 .{ .kind = .{ .matches = 0 } },
3348 },
3349 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3350 },
3351
3352 .@"sadd.sat" = .{
3353 .ret_len = 1,
3354 .params = &.{
3355 .{ .kind = .overloaded },
3356 .{ .kind = .{ .matches = 0 } },
3357 .{ .kind = .{ .matches = 0 } },
3358 },
3359 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3360 },
3361 .@"uadd.sat" = .{
3362 .ret_len = 1,
3363 .params = &.{
3364 .{ .kind = .overloaded },
3365 .{ .kind = .{ .matches = 0 } },
3366 .{ .kind = .{ .matches = 0 } },
3367 },
3368 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3369 },
3370 .@"ssub.sat" = .{
3371 .ret_len = 1,
3372 .params = &.{
3373 .{ .kind = .overloaded },
3374 .{ .kind = .{ .matches = 0 } },
3375 .{ .kind = .{ .matches = 0 } },
3376 },
3377 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3378 },
3379 .@"usub.sat" = .{
3380 .ret_len = 1,
3381 .params = &.{
3382 .{ .kind = .overloaded },
3383 .{ .kind = .{ .matches = 0 } },
3384 .{ .kind = .{ .matches = 0 } },
3385 },
3386 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3387 },
3388 .@"sshl.sat" = .{
3389 .ret_len = 1,
3390 .params = &.{
3391 .{ .kind = .overloaded },
3392 .{ .kind = .{ .matches = 0 } },
3393 .{ .kind = .{ .matches = 0 } },
3394 },
3395 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3396 },
3397 .@"ushl.sat" = .{
3398 .ret_len = 1,
3399 .params = &.{
3400 .{ .kind = .overloaded },
3401 .{ .kind = .{ .matches = 0 } },
3402 .{ .kind = .{ .matches = 0 } },
3403 },
3404 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3405 },
3406
3407 .@"smul.fix" = .{
3408 .ret_len = 1,
3409 .params = &.{
3410 .{ .kind = .overloaded },
3411 .{ .kind = .{ .matches = 0 } },
3412 .{ .kind = .{ .matches = 0 } },
3413 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3414 },
3415 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3416 },
3417 .@"umul.fix" = .{
3418 .ret_len = 1,
3419 .params = &.{
3420 .{ .kind = .overloaded },
3421 .{ .kind = .{ .matches = 0 } },
3422 .{ .kind = .{ .matches = 0 } },
3423 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3424 },
3425 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3426 },
3427 .@"smul.fix.sat" = .{
3428 .ret_len = 1,
3429 .params = &.{
3430 .{ .kind = .overloaded },
3431 .{ .kind = .{ .matches = 0 } },
3432 .{ .kind = .{ .matches = 0 } },
3433 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3434 },
3435 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3436 },
3437 .@"umul.fix.sat" = .{
3438 .ret_len = 1,
3439 .params = &.{
3440 .{ .kind = .overloaded },
3441 .{ .kind = .{ .matches = 0 } },
3442 .{ .kind = .{ .matches = 0 } },
3443 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3444 },
3445 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3446 },
3447 .@"sdiv.fix" = .{
3448 .ret_len = 1,
3449 .params = &.{
3450 .{ .kind = .overloaded },
3451 .{ .kind = .{ .matches = 0 } },
3452 .{ .kind = .{ .matches = 0 } },
3453 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3454 },
3455 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3456 },
3457 .@"udiv.fix" = .{
3458 .ret_len = 1,
3459 .params = &.{
3460 .{ .kind = .overloaded },
3461 .{ .kind = .{ .matches = 0 } },
3462 .{ .kind = .{ .matches = 0 } },
3463 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3464 },
3465 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3466 },
3467 .@"sdiv.fix.sat" = .{
3468 .ret_len = 1,
3469 .params = &.{
3470 .{ .kind = .overloaded },
3471 .{ .kind = .{ .matches = 0 } },
3472 .{ .kind = .{ .matches = 0 } },
3473 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3474 },
3475 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3476 },
3477 .@"udiv.fix.sat" = .{
3478 .ret_len = 1,
3479 .params = &.{
3480 .{ .kind = .overloaded },
3481 .{ .kind = .{ .matches = 0 } },
3482 .{ .kind = .{ .matches = 0 } },
3483 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3484 },
3485 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3486 },
3487
3488 .canonicalize = .{
3489 .ret_len = 1,
3490 .params = &.{
3491 .{ .kind = .overloaded },
3492 .{ .kind = .{ .matches = 0 } },
3493 },
3494 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3495 },
3496 .fmuladd = .{
3497 .ret_len = 1,
3498 .params = &.{
3499 .{ .kind = .overloaded },
3500 .{ .kind = .{ .matches = 0 } },
3501 .{ .kind = .{ .matches = 0 } },
3502 .{ .kind = .{ .matches = 0 } },
3503 },
3504 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3505 },
3506
3507 .@"vector.reduce.add" = .{
3508 .ret_len = 1,
3509 .params = &.{
3510 .{ .kind = .{ .matches_scalar = 1 } },
3511 .{ .kind = .overloaded },
3512 },
3513 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3514 },
3515 .@"vector.reduce.fadd" = .{
3516 .ret_len = 1,
3517 .params = &.{
3518 .{ .kind = .{ .matches_scalar = 2 } },
3519 .{ .kind = .{ .matches_scalar = 2 } },
3520 .{ .kind = .overloaded },
3521 },
3522 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3523 },
3524 .@"vector.reduce.mul" = .{
3525 .ret_len = 1,
3526 .params = &.{
3527 .{ .kind = .{ .matches_scalar = 1 } },
3528 .{ .kind = .overloaded },
3529 },
3530 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3531 },
3532 .@"vector.reduce.fmul" = .{
3533 .ret_len = 1,
3534 .params = &.{
3535 .{ .kind = .{ .matches_scalar = 2 } },
3536 .{ .kind = .{ .matches_scalar = 2 } },
3537 .{ .kind = .overloaded },
3538 },
3539 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3540 },
3541 .@"vector.reduce.and" = .{
3542 .ret_len = 1,
3543 .params = &.{
3544 .{ .kind = .{ .matches_scalar = 1 } },
3545 .{ .kind = .overloaded },
3546 },
3547 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3548 },
3549 .@"vector.reduce.or" = .{
3550 .ret_len = 1,
3551 .params = &.{
3552 .{ .kind = .{ .matches_scalar = 1 } },
3553 .{ .kind = .overloaded },
3554 },
3555 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3556 },
3557 .@"vector.reduce.xor" = .{
3558 .ret_len = 1,
3559 .params = &.{
3560 .{ .kind = .{ .matches_scalar = 1 } },
3561 .{ .kind = .overloaded },
3562 },
3563 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3564 },
3565 .@"vector.reduce.smax" = .{
3566 .ret_len = 1,
3567 .params = &.{
3568 .{ .kind = .{ .matches_scalar = 1 } },
3569 .{ .kind = .overloaded },
3570 },
3571 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3572 },
3573 .@"vector.reduce.smin" = .{
3574 .ret_len = 1,
3575 .params = &.{
3576 .{ .kind = .{ .matches_scalar = 1 } },
3577 .{ .kind = .overloaded },
3578 },
3579 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3580 },
3581 .@"vector.reduce.umax" = .{
3582 .ret_len = 1,
3583 .params = &.{
3584 .{ .kind = .{ .matches_scalar = 1 } },
3585 .{ .kind = .overloaded },
3586 },
3587 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3588 },
3589 .@"vector.reduce.umin" = .{
3590 .ret_len = 1,
3591 .params = &.{
3592 .{ .kind = .{ .matches_scalar = 1 } },
3593 .{ .kind = .overloaded },
3594 },
3595 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3596 },
3597 .@"vector.reduce.fmax" = .{
3598 .ret_len = 1,
3599 .params = &.{
3600 .{ .kind = .{ .matches_scalar = 1 } },
3601 .{ .kind = .overloaded },
3602 },
3603 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3604 },
3605 .@"vector.reduce.fmin" = .{
3606 .ret_len = 1,
3607 .params = &.{
3608 .{ .kind = .{ .matches_scalar = 1 } },
3609 .{ .kind = .overloaded },
3610 },
3611 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3612 },
3613 .@"vector.reduce.fmaximum" = .{
3614 .ret_len = 1,
3615 .params = &.{
3616 .{ .kind = .{ .matches_scalar = 1 } },
3617 .{ .kind = .overloaded },
3618 },
3619 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3620 },
3621 .@"vector.reduce.fminimum" = .{
3622 .ret_len = 1,
3623 .params = &.{
3624 .{ .kind = .{ .matches_scalar = 1 } },
3625 .{ .kind = .overloaded },
3626 },
3627 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3628 },
3629 .@"vector.insert" = .{
3630 .ret_len = 1,
3631 .params = &.{
3632 .{ .kind = .overloaded },
3633 .{ .kind = .{ .matches = 0 } },
3634 .{ .kind = .overloaded },
3635 .{ .kind = .{ .type = .i64 } },
3636 },
3637 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3638 },
3639 .@"vector.extract" = .{
3640 .ret_len = 1,
3641 .params = &.{
3642 .{ .kind = .overloaded },
3643 .{ .kind = .overloaded },
3644 .{ .kind = .{ .type = .i64 } },
3645 },
3646 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3647 },
3648
3649 .@"is.fpclass" = .{
3650 .ret_len = 1,
3651 .params = &.{
3652 .{ .kind = .{ .matches_changed_scalar = .{ .index = 1, .scalar = .i1 } } },
3653 .{ .kind = .overloaded },
3654 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3655 },
3656 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3657 },
3658
3659 .@"var.annotation" = .{
3660 .ret_len = 0,
3661 .params = &.{
3662 .{ .kind = .overloaded },
3663 .{ .kind = .overloaded },
3664 .{ .kind = .{ .matches = 1 } },
3665 .{ .kind = .{ .type = .i32 } },
3666 .{ .kind = .{ .matches = 1 } },
3667 },
3668 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3669 },
3670 .@"ptr.annotation" = .{
3671 .ret_len = 1,
3672 .params = &.{
3673 .{ .kind = .overloaded },
3674 .{ .kind = .{ .matches = 0 } },
3675 .{ .kind = .overloaded },
3676 .{ .kind = .{ .matches = 2 } },
3677 .{ .kind = .{ .type = .i32 } },
3678 .{ .kind = .{ .matches = 2 } },
3679 },
3680 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3681 },
3682 .annotation = .{
3683 .ret_len = 1,
3684 .params = &.{
3685 .{ .kind = .overloaded },
3686 .{ .kind = .{ .matches = 0 } },
3687 .{ .kind = .overloaded },
3688 .{ .kind = .{ .matches = 2 } },
3689 .{ .kind = .{ .type = .i32 } },
3690 },
3691 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3692 },
3693 .@"codeview.annotation" = .{
3694 .ret_len = 0,
3695 .params = &.{
3696 .{ .kind = .{ .type = .metadata } },
3697 },
3698 .attrs = &.{ .nocallback, .noduplicate, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3699 },
3700 .trap = .{
3701 .ret_len = 0,
3702 .params = &.{},
3703 .attrs = &.{ .cold, .noreturn, .nounwind, .{ .memory = .{ .inaccessiblemem = .write } } },
3704 },
3705 .debugtrap = .{
3706 .ret_len = 0,
3707 .params = &.{},
3708 .attrs = &.{.nounwind},
3709 },
3710 .ubsantrap = .{
3711 .ret_len = 0,
3712 .params = &.{
3713 .{ .kind = .{ .type = .i8 }, .attrs = &.{.immarg} },
3714 },
3715 .attrs = &.{ .cold, .noreturn, .nounwind },
3716 },
3717 .stackprotector = .{
3718 .ret_len = 0,
3719 .params = &.{
3720 .{ .kind = .{ .type = .ptr } },
3721 .{ .kind = .{ .type = .ptr } },
3722 },
3723 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
3724 },
3725 .stackguard = .{
3726 .ret_len = 1,
3727 .params = &.{
3728 .{ .kind = .{ .type = .ptr } },
3729 },
3730 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
3731 },
3732 .objectsize = .{
3733 .ret_len = 1,
3734 .params = &.{
3735 .{ .kind = .overloaded },
3736 .{ .kind = .overloaded },
3737 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3738 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3739 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3740 },
3741 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3742 },
3743 .expect = .{
3744 .ret_len = 1,
3745 .params = &.{
3746 .{ .kind = .overloaded },
3747 .{ .kind = .{ .matches = 0 } },
3748 .{ .kind = .{ .matches = 0 } },
3749 },
3750 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3751 },
3752 .@"expect.with.probability" = .{
3753 .ret_len = 1,
3754 .params = &.{
3755 .{ .kind = .overloaded },
3756 .{ .kind = .{ .matches = 0 } },
3757 .{ .kind = .{ .matches = 0 } },
3758 .{ .kind = .{ .type = .double }, .attrs = &.{.immarg} },
3759 },
3760 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3761 },
3762 .assume = .{
3763 .ret_len = 0,
3764 .params = &.{
3765 .{ .kind = .{ .type = .i1 }, .attrs = &.{.noundef} },
3766 },
3767 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .write } } },
3768 },
3769 .@"ssa.copy" = .{
3770 .ret_len = 1,
3771 .params = &.{
3772 .{ .kind = .overloaded },
3773 .{ .kind = .{ .matches = 0 }, .attrs = &.{.returned} },
3774 },
3775 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3776 },
3777 .@"type.test" = .{
3778 .ret_len = 1,
3779 .params = &.{
3780 .{ .kind = .{ .type = .i1 } },
3781 .{ .kind = .{ .type = .ptr } },
3782 .{ .kind = .{ .type = .metadata } },
3783 },
3784 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3785 },
3786 .@"type.checked.load" = .{
3787 .ret_len = 2,
3788 .params = &.{
3789 .{ .kind = .{ .type = .ptr } },
3790 .{ .kind = .{ .type = .i1 } },
3791 .{ .kind = .{ .type = .ptr } },
3792 .{ .kind = .{ .type = .i32 } },
3793 .{ .kind = .{ .type = .metadata } },
3794 },
3795 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3796 },
3797 .@"type.checked.load.relative" = .{
3798 .ret_len = 2,
3799 .params = &.{
3800 .{ .kind = .{ .type = .ptr } },
3801 .{ .kind = .{ .type = .i1 } },
3802 .{ .kind = .{ .type = .ptr } },
3803 .{ .kind = .{ .type = .i32 } },
3804 .{ .kind = .{ .type = .metadata } },
3805 },
3806 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3807 },
3808 .@"arithmetic.fence" = .{
3809 .ret_len = 1,
3810 .params = &.{
3811 .{ .kind = .overloaded },
3812 .{ .kind = .{ .matches = 0 } },
3813 },
3814 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3815 },
3816 .donothing = .{
3817 .ret_len = 0,
3818 .params = &.{},
3819 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3820 },
3821 .@"load.relative" = .{
3822 .ret_len = 1,
3823 .params = &.{
3824 .{ .kind = .{ .type = .ptr } },
3825 .{ .kind = .{ .type = .ptr } },
3826 .{ .kind = .overloaded },
3827 },
3828 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .argmem = .read } } },
3829 },
3830 .sideeffect = .{
3831 .ret_len = 0,
3832 .params = &.{},
3833 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3834 },
3835 .@"is.constant" = .{
3836 .ret_len = 1,
3837 .params = &.{
3838 .{ .kind = .{ .type = .i1 } },
3839 .{ .kind = .overloaded },
3840 },
3841 .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3842 },
3843 .ptrmask = .{
3844 .ret_len = 1,
3845 .params = &.{
3846 .{ .kind = .overloaded },
3847 .{ .kind = .{ .matches = 0 } },
3848 .{ .kind = .overloaded },
3849 },
3850 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3851 },
3852 .@"threadlocal.address" = .{
3853 .ret_len = 1,
3854 .params = &.{
3855 .{ .kind = .overloaded, .attrs = &.{.nonnull} },
3856 .{ .kind = .{ .matches = 0 }, .attrs = &.{.nonnull} },
3857 },
3858 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3859 },
3860 .vscale = .{
3861 .ret_len = 1,
3862 .params = &.{
3863 .{ .kind = .overloaded },
3864 },
3865 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3866 },
3867
3868 .@"dbg.declare" = .{
3869 .ret_len = 0,
3870 .params = &.{
3871 .{ .kind = .{ .type = .metadata } },
3872 .{ .kind = .{ .type = .metadata } },
3873 .{ .kind = .{ .type = .metadata } },
3874 },
3875 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3876 },
3877 .@"dbg.value" = .{
3878 .ret_len = 0,
3879 .params = &.{
3880 .{ .kind = .{ .type = .metadata } },
3881 .{ .kind = .{ .type = .metadata } },
3882 .{ .kind = .{ .type = .metadata } },
3883 },
3884 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3885 },
3886
3887 .@"amdgcn.workitem.id.x" = .{
3888 .ret_len = 1,
3889 .params = &.{
3890 .{ .kind = .{ .type = .i32 } },
3891 },
3892 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3893 },
3894 .@"amdgcn.workitem.id.y" = .{
3895 .ret_len = 1,
3896 .params = &.{
3897 .{ .kind = .{ .type = .i32 } },
3898 },
3899 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3900 },
3901 .@"amdgcn.workitem.id.z" = .{
3902 .ret_len = 1,
3903 .params = &.{
3904 .{ .kind = .{ .type = .i32 } },
3905 },
3906 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3907 },
3908 .@"amdgcn.workgroup.id.x" = .{
3909 .ret_len = 1,
3910 .params = &.{
3911 .{ .kind = .{ .type = .i32 } },
3912 },
3913 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3914 },
3915 .@"amdgcn.workgroup.id.y" = .{
3916 .ret_len = 1,
3917 .params = &.{
3918 .{ .kind = .{ .type = .i32 } },
3919 },
3920 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3921 },
3922 .@"amdgcn.workgroup.id.z" = .{
3923 .ret_len = 1,
3924 .params = &.{
3925 .{ .kind = .{ .type = .i32 } },
3926 },
3927 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3928 },
3929 .@"amdgcn.dispatch.ptr" = .{
3930 .ret_len = 1,
3931 .params = &.{
3932 .{
3933 .kind = .{ .type = Type.ptr_amdgpu_constant },
3934 .attrs = &.{.{ .@"align" = Builder.Alignment.fromByteUnits(4) }},
3935 },
3936 },
3937 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3938 },
3939
3940 .@"nvvm.read.ptx.sreg.tid.x" = .{
3941 .ret_len = 1,
3942 .params = &.{
3943 .{ .kind = .{ .type = .i32 } },
3944 },
3945 .attrs = &.{ .nounwind, .readnone },
3946 },
3947 .@"nvvm.read.ptx.sreg.tid.y" = .{
3948 .ret_len = 1,
3949 .params = &.{
3950 .{ .kind = .{ .type = .i32 } },
3951 },
3952 .attrs = &.{ .nounwind, .readnone },
3953 },
3954 .@"nvvm.read.ptx.sreg.tid.z" = .{
3955 .ret_len = 1,
3956 .params = &.{
3957 .{ .kind = .{ .type = .i32 } },
3958 },
3959 .attrs = &.{ .nounwind, .readnone },
3960 },
3961
3962 .@"nvvm.read.ptx.sreg.ntid.x" = .{
3963 .ret_len = 1,
3964 .params = &.{
3965 .{ .kind = .{ .type = .i32 } },
3966 },
3967 .attrs = &.{ .nounwind, .readnone },
3968 },
3969 .@"nvvm.read.ptx.sreg.ntid.y" = .{
3970 .ret_len = 1,
3971 .params = &.{
3972 .{ .kind = .{ .type = .i32 } },
3973 },
3974 .attrs = &.{ .nounwind, .readnone },
3975 },
3976 .@"nvvm.read.ptx.sreg.ntid.z" = .{
3977 .ret_len = 1,
3978 .params = &.{
3979 .{ .kind = .{ .type = .i32 } },
3980 },
3981 .attrs = &.{ .nounwind, .readnone },
3982 },
3983
3984 .@"nvvm.read.ptx.sreg.ctaid.x" = .{
3985 .ret_len = 1,
3986 .params = &.{
3987 .{ .kind = .{ .type = .i32 } },
3988 },
3989 .attrs = &.{ .nounwind, .readnone },
3990 },
3991 .@"nvvm.read.ptx.sreg.ctaid.y" = .{
3992 .ret_len = 1,
3993 .params = &.{
3994 .{ .kind = .{ .type = .i32 } },
3995 },
3996 .attrs = &.{ .nounwind, .readnone },
3997 },
3998 .@"nvvm.read.ptx.sreg.ctaid.z" = .{
3999 .ret_len = 1,
4000 .params = &.{
4001 .{ .kind = .{ .type = .i32 } },
4002 },
4003 .attrs = &.{ .nounwind, .readnone },
4004 },
4005
4006 .@"wasm.memory.size" = .{
4007 .ret_len = 1,
4008 .params = &.{
4009 .{ .kind = .overloaded },
4010 .{ .kind = .{ .type = .i32 } },
4011 },
4012 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
4013 },
4014 .@"wasm.memory.grow" = .{
4015 .ret_len = 1,
4016 .params = &.{
4017 .{ .kind = .overloaded },
4018 .{ .kind = .{ .type = .i32 } },
4019 .{ .kind = .{ .matches = 0 } },
4020 },
4021 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
4022 },
4023 });
4024};
4025
4026pub const Function = struct {
4027 global: Global.Index,
4028 call_conv: CallConv = CallConv.default,
4029 attributes: FunctionAttributes = .none,
4030 section: String = .none,
4031 alignment: Alignment = .default,
4032 blocks: []const Block = &.{},
4033 instructions: std.MultiArrayList(Instruction) = .{},
4034 names: [*]const String = &[0]String{},
4035 value_indices: [*]const u32 = &[0]u32{},
4036 strip: bool,
4037 debug_locations: std.AutoHashMapUnmanaged(Instruction.Index, DebugLocation) = .empty,
4038 debug_values: []const Instruction.Index = &.{},
4039 extra: []const u32 = &.{},
4040
4041 pub const Index = enum(u32) {
4042 none = std.math.maxInt(u32),
4043 _,
4044
4045 pub fn ptr(self: Index, builder: *Builder) *Function {
4046 return &builder.functions.items[@intFromEnum(self)];
4047 }
4048
4049 pub fn ptrConst(self: Index, builder: *const Builder) *const Function {
4050 return &builder.functions.items[@intFromEnum(self)];
4051 }
4052
4053 pub fn name(self: Index, builder: *const Builder) StrtabString {
4054 return self.ptrConst(builder).global.name(builder);
4055 }
4056
4057 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
4058 return self.ptrConst(builder).global.rename(new_name, builder);
4059 }
4060
4061 pub fn typeOf(self: Index, builder: *const Builder) Type {
4062 return self.ptrConst(builder).global.typeOf(builder);
4063 }
4064
4065 pub fn toConst(self: Index, builder: *const Builder) Constant {
4066 return self.ptrConst(builder).global.toConst();
4067 }
4068
4069 pub fn toValue(self: Index, builder: *const Builder) Value {
4070 return self.toConst(builder).toValue();
4071 }
4072
4073 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
4074 return self.ptrConst(builder).global.setLinkage(linkage, builder);
4075 }
4076
4077 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
4078 return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
4079 }
4080
4081 pub fn setCallConv(self: Index, call_conv: CallConv, builder: *Builder) void {
4082 self.ptr(builder).call_conv = call_conv;
4083 }
4084
4085 pub fn setAttributes(
4086 self: Index,
4087 new_function_attributes: FunctionAttributes,
4088 builder: *Builder,
4089 ) void {
4090 self.ptr(builder).attributes = new_function_attributes;
4091 }
4092
4093 pub fn setSection(self: Index, section: String, builder: *Builder) void {
4094 self.ptr(builder).section = section;
4095 }
4096
4097 pub fn setAlignment(self: Index, alignment: Alignment, builder: *Builder) void {
4098 self.ptr(builder).alignment = alignment;
4099 }
4100
4101 pub fn setSubprogram(self: Index, subprogram: Metadata, builder: *Builder) void {
4102 self.ptrConst(builder).global.setDebugMetadata(subprogram, builder);
4103 }
4104 };
4105
4106 pub const Block = struct {
4107 instruction: Instruction.Index,
4108
4109 pub const Index = WipFunction.Block.Index;
4110 };
4111
4112 pub const Instruction = struct {
4113 tag: Tag,
4114 data: u32,
4115
4116 pub const Tag = enum(u8) {
4117 add,
4118 @"add nsw",
4119 @"add nuw",
4120 @"add nuw nsw",
4121 addrspacecast,
4122 alloca,
4123 @"alloca inalloca",
4124 @"and",
4125 arg,
4126 ashr,
4127 @"ashr exact",
4128 atomicrmw,
4129 bitcast,
4130 block,
4131 br,
4132 br_cond,
4133 call,
4134 @"call fast",
4135 cmpxchg,
4136 @"cmpxchg weak",
4137 extractelement,
4138 extractvalue,
4139 fadd,
4140 @"fadd fast",
4141 @"fcmp false",
4142 @"fcmp fast false",
4143 @"fcmp fast oeq",
4144 @"fcmp fast oge",
4145 @"fcmp fast ogt",
4146 @"fcmp fast ole",
4147 @"fcmp fast olt",
4148 @"fcmp fast one",
4149 @"fcmp fast ord",
4150 @"fcmp fast true",
4151 @"fcmp fast ueq",
4152 @"fcmp fast uge",
4153 @"fcmp fast ugt",
4154 @"fcmp fast ule",
4155 @"fcmp fast ult",
4156 @"fcmp fast une",
4157 @"fcmp fast uno",
4158 @"fcmp oeq",
4159 @"fcmp oge",
4160 @"fcmp ogt",
4161 @"fcmp ole",
4162 @"fcmp olt",
4163 @"fcmp one",
4164 @"fcmp ord",
4165 @"fcmp true",
4166 @"fcmp ueq",
4167 @"fcmp uge",
4168 @"fcmp ugt",
4169 @"fcmp ule",
4170 @"fcmp ult",
4171 @"fcmp une",
4172 @"fcmp uno",
4173 fdiv,
4174 @"fdiv fast",
4175 fence,
4176 fmul,
4177 @"fmul fast",
4178 fneg,
4179 @"fneg fast",
4180 fpext,
4181 fptosi,
4182 fptoui,
4183 fptrunc,
4184 frem,
4185 @"frem fast",
4186 fsub,
4187 @"fsub fast",
4188 getelementptr,
4189 @"getelementptr inbounds",
4190 @"icmp eq",
4191 @"icmp ne",
4192 @"icmp sge",
4193 @"icmp sgt",
4194 @"icmp sle",
4195 @"icmp slt",
4196 @"icmp uge",
4197 @"icmp ugt",
4198 @"icmp ule",
4199 @"icmp ult",
4200 indirectbr,
4201 insertelement,
4202 insertvalue,
4203 inttoptr,
4204 load,
4205 @"load atomic",
4206 lshr,
4207 @"lshr exact",
4208 mul,
4209 @"mul nsw",
4210 @"mul nuw",
4211 @"mul nuw nsw",
4212 @"musttail call",
4213 @"musttail call fast",
4214 @"notail call",
4215 @"notail call fast",
4216 @"or",
4217 phi,
4218 @"phi fast",
4219 ptrtoint,
4220 ret,
4221 @"ret void",
4222 sdiv,
4223 @"sdiv exact",
4224 select,
4225 @"select fast",
4226 sext,
4227 shl,
4228 @"shl nsw",
4229 @"shl nuw",
4230 @"shl nuw nsw",
4231 shufflevector,
4232 sitofp,
4233 srem,
4234 store,
4235 @"store atomic",
4236 sub,
4237 @"sub nsw",
4238 @"sub nuw",
4239 @"sub nuw nsw",
4240 @"switch",
4241 @"tail call",
4242 @"tail call fast",
4243 trunc,
4244 udiv,
4245 @"udiv exact",
4246 urem,
4247 uitofp,
4248 @"unreachable",
4249 va_arg,
4250 xor,
4251 zext,
4252
4253 pub fn toBinaryOpcode(self: Tag) BinaryOpcode {
4254 return switch (self) {
4255 .add,
4256 .@"add nsw",
4257 .@"add nuw",
4258 .@"add nuw nsw",
4259 .fadd,
4260 .@"fadd fast",
4261 => .add,
4262 .sub,
4263 .@"sub nsw",
4264 .@"sub nuw",
4265 .@"sub nuw nsw",
4266 .fsub,
4267 .@"fsub fast",
4268 => .sub,
4269 .sdiv,
4270 .@"sdiv exact",
4271 .fdiv,
4272 .@"fdiv fast",
4273 => .sdiv,
4274 .fmul,
4275 .@"fmul fast",
4276 .mul,
4277 .@"mul nsw",
4278 .@"mul nuw",
4279 .@"mul nuw nsw",
4280 => .mul,
4281 .srem,
4282 .frem,
4283 .@"frem fast",
4284 => .srem,
4285 .udiv,
4286 .@"udiv exact",
4287 => .udiv,
4288 .shl,
4289 .@"shl nsw",
4290 .@"shl nuw",
4291 .@"shl nuw nsw",
4292 => .shl,
4293 .lshr,
4294 .@"lshr exact",
4295 => .lshr,
4296 .ashr,
4297 .@"ashr exact",
4298 => .ashr,
4299 .@"and" => .@"and",
4300 .@"or" => .@"or",
4301 .xor => .xor,
4302 .urem => .urem,
4303 else => unreachable,
4304 };
4305 }
4306
4307 pub fn toCastOpcode(self: Tag) CastOpcode {
4308 return switch (self) {
4309 .trunc => .trunc,
4310 .zext => .zext,
4311 .sext => .sext,
4312 .fptoui => .fptoui,
4313 .fptosi => .fptosi,
4314 .uitofp => .uitofp,
4315 .sitofp => .sitofp,
4316 .fptrunc => .fptrunc,
4317 .fpext => .fpext,
4318 .ptrtoint => .ptrtoint,
4319 .inttoptr => .inttoptr,
4320 .bitcast => .bitcast,
4321 .addrspacecast => .addrspacecast,
4322 else => unreachable,
4323 };
4324 }
4325
4326 pub fn toCmpPredicate(self: Tag) CmpPredicate {
4327 return switch (self) {
4328 .@"fcmp false",
4329 .@"fcmp fast false",
4330 => .fcmp_false,
4331 .@"fcmp oeq",
4332 .@"fcmp fast oeq",
4333 => .fcmp_oeq,
4334 .@"fcmp oge",
4335 .@"fcmp fast oge",
4336 => .fcmp_oge,
4337 .@"fcmp ogt",
4338 .@"fcmp fast ogt",
4339 => .fcmp_ogt,
4340 .@"fcmp ole",
4341 .@"fcmp fast ole",
4342 => .fcmp_ole,
4343 .@"fcmp olt",
4344 .@"fcmp fast olt",
4345 => .fcmp_olt,
4346 .@"fcmp one",
4347 .@"fcmp fast one",
4348 => .fcmp_one,
4349 .@"fcmp ord",
4350 .@"fcmp fast ord",
4351 => .fcmp_ord,
4352 .@"fcmp true",
4353 .@"fcmp fast true",
4354 => .fcmp_true,
4355 .@"fcmp ueq",
4356 .@"fcmp fast ueq",
4357 => .fcmp_ueq,
4358 .@"fcmp uge",
4359 .@"fcmp fast uge",
4360 => .fcmp_uge,
4361 .@"fcmp ugt",
4362 .@"fcmp fast ugt",
4363 => .fcmp_ugt,
4364 .@"fcmp ule",
4365 .@"fcmp fast ule",
4366 => .fcmp_ule,
4367 .@"fcmp ult",
4368 .@"fcmp fast ult",
4369 => .fcmp_ult,
4370 .@"fcmp une",
4371 .@"fcmp fast une",
4372 => .fcmp_une,
4373 .@"fcmp uno",
4374 .@"fcmp fast uno",
4375 => .fcmp_uno,
4376 .@"icmp eq" => .icmp_eq,
4377 .@"icmp ne" => .icmp_ne,
4378 .@"icmp sge" => .icmp_sge,
4379 .@"icmp sgt" => .icmp_sgt,
4380 .@"icmp sle" => .icmp_sle,
4381 .@"icmp slt" => .icmp_slt,
4382 .@"icmp uge" => .icmp_uge,
4383 .@"icmp ugt" => .icmp_ugt,
4384 .@"icmp ule" => .icmp_ule,
4385 .@"icmp ult" => .icmp_ult,
4386 else => unreachable,
4387 };
4388 }
4389 };
4390
4391 pub const Index = enum(u32) {
4392 none = std.math.maxInt(u31),
4393 _,
4394
4395 pub fn name(self: Instruction.Index, function: *const Function) String {
4396 return function.names[@intFromEnum(self)];
4397 }
4398
4399 pub fn valueIndex(self: Instruction.Index, function: *const Function) u32 {
4400 return function.value_indices[@intFromEnum(self)];
4401 }
4402
4403 pub fn toValue(self: Instruction.Index) Value {
4404 return @enumFromInt(@intFromEnum(self));
4405 }
4406
4407 pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool {
4408 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
4409 .br,
4410 .br_cond,
4411 .indirectbr,
4412 .ret,
4413 .@"ret void",
4414 .@"switch",
4415 .@"unreachable",
4416 => true,
4417 else => false,
4418 };
4419 }
4420
4421 pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool {
4422 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
4423 .br,
4424 .br_cond,
4425 .fence,
4426 .indirectbr,
4427 .ret,
4428 .@"ret void",
4429 .store,
4430 .@"store atomic",
4431 .@"switch",
4432 .@"unreachable",
4433 .block,
4434 => false,
4435 .call,
4436 .@"call fast",
4437 .@"musttail call",
4438 .@"musttail call fast",
4439 .@"notail call",
4440 .@"notail call fast",
4441 .@"tail call",
4442 .@"tail call fast",
4443 => self.typeOfWip(wip) != .void,
4444 else => true,
4445 };
4446 }
4447
4448 pub fn typeOfWip(self: Instruction.Index, wip: *const WipFunction) Type {
4449 const instruction = wip.instructions.get(@intFromEnum(self));
4450 return switch (instruction.tag) {
4451 .add,
4452 .@"add nsw",
4453 .@"add nuw",
4454 .@"add nuw nsw",
4455 .@"and",
4456 .ashr,
4457 .@"ashr exact",
4458 .fadd,
4459 .@"fadd fast",
4460 .fdiv,
4461 .@"fdiv fast",
4462 .fmul,
4463 .@"fmul fast",
4464 .frem,
4465 .@"frem fast",
4466 .fsub,
4467 .@"fsub fast",
4468 .lshr,
4469 .@"lshr exact",
4470 .mul,
4471 .@"mul nsw",
4472 .@"mul nuw",
4473 .@"mul nuw nsw",
4474 .@"or",
4475 .sdiv,
4476 .@"sdiv exact",
4477 .shl,
4478 .@"shl nsw",
4479 .@"shl nuw",
4480 .@"shl nuw nsw",
4481 .srem,
4482 .sub,
4483 .@"sub nsw",
4484 .@"sub nuw",
4485 .@"sub nuw nsw",
4486 .udiv,
4487 .@"udiv exact",
4488 .urem,
4489 .xor,
4490 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip),
4491 .addrspacecast,
4492 .bitcast,
4493 .fpext,
4494 .fptosi,
4495 .fptoui,
4496 .fptrunc,
4497 .inttoptr,
4498 .ptrtoint,
4499 .sext,
4500 .sitofp,
4501 .trunc,
4502 .uitofp,
4503 .zext,
4504 => wip.extraData(Cast, instruction.data).type,
4505 .alloca,
4506 .@"alloca inalloca",
4507 => wip.builder.ptrTypeAssumeCapacity(
4508 wip.extraData(Alloca, instruction.data).info.addr_space,
4509 ),
4510 .arg => wip.function.typeOf(wip.builder)
4511 .functionParameters(wip.builder)[instruction.data],
4512 .atomicrmw => wip.extraData(AtomicRmw, instruction.data).val.typeOfWip(wip),
4513 .block => .label,
4514 .br,
4515 .br_cond,
4516 .fence,
4517 .indirectbr,
4518 .ret,
4519 .@"ret void",
4520 .store,
4521 .@"store atomic",
4522 .@"switch",
4523 .@"unreachable",
4524 => .none,
4525 .call,
4526 .@"call fast",
4527 .@"musttail call",
4528 .@"musttail call fast",
4529 .@"notail call",
4530 .@"notail call fast",
4531 .@"tail call",
4532 .@"tail call fast",
4533 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
4534 .cmpxchg,
4535 .@"cmpxchg weak",
4536 => wip.builder.structTypeAssumeCapacity(.normal, &.{
4537 wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
4538 .i1,
4539 }),
4540 .extractelement => wip.extraData(ExtractElement, instruction.data)
4541 .val.typeOfWip(wip).childType(wip.builder),
4542 .extractvalue => {
4543 var extra = wip.extraDataTrail(ExtractValue, instruction.data);
4544 const indices = extra.trail.next(extra.data.indices_len, u32, wip);
4545 return extra.data.val.typeOfWip(wip).childTypeAt(indices, wip.builder);
4546 },
4547 .@"fcmp false",
4548 .@"fcmp fast false",
4549 .@"fcmp fast oeq",
4550 .@"fcmp fast oge",
4551 .@"fcmp fast ogt",
4552 .@"fcmp fast ole",
4553 .@"fcmp fast olt",
4554 .@"fcmp fast one",
4555 .@"fcmp fast ord",
4556 .@"fcmp fast true",
4557 .@"fcmp fast ueq",
4558 .@"fcmp fast uge",
4559 .@"fcmp fast ugt",
4560 .@"fcmp fast ule",
4561 .@"fcmp fast ult",
4562 .@"fcmp fast une",
4563 .@"fcmp fast uno",
4564 .@"fcmp oeq",
4565 .@"fcmp oge",
4566 .@"fcmp ogt",
4567 .@"fcmp ole",
4568 .@"fcmp olt",
4569 .@"fcmp one",
4570 .@"fcmp ord",
4571 .@"fcmp true",
4572 .@"fcmp ueq",
4573 .@"fcmp uge",
4574 .@"fcmp ugt",
4575 .@"fcmp ule",
4576 .@"fcmp ult",
4577 .@"fcmp une",
4578 .@"fcmp uno",
4579 .@"icmp eq",
4580 .@"icmp ne",
4581 .@"icmp sge",
4582 .@"icmp sgt",
4583 .@"icmp sle",
4584 .@"icmp slt",
4585 .@"icmp uge",
4586 .@"icmp ugt",
4587 .@"icmp ule",
4588 .@"icmp ult",
4589 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip)
4590 .changeScalarAssumeCapacity(.i1, wip.builder),
4591 .fneg,
4592 .@"fneg fast",
4593 => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
4594 .getelementptr,
4595 .@"getelementptr inbounds",
4596 => {
4597 var extra = wip.extraDataTrail(GetElementPtr, instruction.data);
4598 const indices = extra.trail.next(extra.data.indices_len, Value, wip);
4599 const base_ty = extra.data.base.typeOfWip(wip);
4600 if (!base_ty.isVector(wip.builder)) for (indices) |index| {
4601 const index_ty = index.typeOfWip(wip);
4602 if (!index_ty.isVector(wip.builder)) continue;
4603 return index_ty.changeScalarAssumeCapacity(base_ty, wip.builder);
4604 };
4605 return base_ty;
4606 },
4607 .insertelement => wip.extraData(InsertElement, instruction.data).val.typeOfWip(wip),
4608 .insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
4609 .load,
4610 .@"load atomic",
4611 => wip.extraData(Load, instruction.data).type,
4612 .phi,
4613 .@"phi fast",
4614 => wip.extraData(Phi, instruction.data).type,
4615 .select,
4616 .@"select fast",
4617 => wip.extraData(Select, instruction.data).lhs.typeOfWip(wip),
4618 .shufflevector => {
4619 const extra = wip.extraData(ShuffleVector, instruction.data);
4620 return extra.lhs.typeOfWip(wip).changeLengthAssumeCapacity(
4621 extra.mask.typeOfWip(wip).vectorLen(wip.builder),
4622 wip.builder,
4623 );
4624 },
4625 .va_arg => wip.extraData(VaArg, instruction.data).type,
4626 };
4627 }
4628
4629 pub fn typeOf(
4630 self: Instruction.Index,
4631 function_index: Function.Index,
4632 builder: *Builder,
4633 ) Type {
4634 const function = function_index.ptrConst(builder);
4635 const instruction = function.instructions.get(@intFromEnum(self));
4636 return switch (instruction.tag) {
4637 .add,
4638 .@"add nsw",
4639 .@"add nuw",
4640 .@"add nuw nsw",
4641 .@"and",
4642 .ashr,
4643 .@"ashr exact",
4644 .fadd,
4645 .@"fadd fast",
4646 .fdiv,
4647 .@"fdiv fast",
4648 .fmul,
4649 .@"fmul fast",
4650 .frem,
4651 .@"frem fast",
4652 .fsub,
4653 .@"fsub fast",
4654 .lshr,
4655 .@"lshr exact",
4656 .mul,
4657 .@"mul nsw",
4658 .@"mul nuw",
4659 .@"mul nuw nsw",
4660 .@"or",
4661 .sdiv,
4662 .@"sdiv exact",
4663 .shl,
4664 .@"shl nsw",
4665 .@"shl nuw",
4666 .@"shl nuw nsw",
4667 .srem,
4668 .sub,
4669 .@"sub nsw",
4670 .@"sub nuw",
4671 .@"sub nuw nsw",
4672 .udiv,
4673 .@"udiv exact",
4674 .urem,
4675 .xor,
4676 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder),
4677 .addrspacecast,
4678 .bitcast,
4679 .fpext,
4680 .fptosi,
4681 .fptoui,
4682 .fptrunc,
4683 .inttoptr,
4684 .ptrtoint,
4685 .sext,
4686 .sitofp,
4687 .trunc,
4688 .uitofp,
4689 .zext,
4690 => function.extraData(Cast, instruction.data).type,
4691 .alloca,
4692 .@"alloca inalloca",
4693 => builder.ptrTypeAssumeCapacity(
4694 function.extraData(Alloca, instruction.data).info.addr_space,
4695 ),
4696 .arg => function.global.typeOf(builder)
4697 .functionParameters(builder)[instruction.data],
4698 .atomicrmw => function.extraData(AtomicRmw, instruction.data)
4699 .val.typeOf(function_index, builder),
4700 .block => .label,
4701 .br,
4702 .br_cond,
4703 .fence,
4704 .indirectbr,
4705 .ret,
4706 .@"ret void",
4707 .store,
4708 .@"store atomic",
4709 .@"switch",
4710 .@"unreachable",
4711 => .none,
4712 .call,
4713 .@"call fast",
4714 .@"musttail call",
4715 .@"musttail call fast",
4716 .@"notail call",
4717 .@"notail call fast",
4718 .@"tail call",
4719 .@"tail call fast",
4720 => function.extraData(Call, instruction.data).ty.functionReturn(builder),
4721 .cmpxchg,
4722 .@"cmpxchg weak",
4723 => builder.structTypeAssumeCapacity(.normal, &.{
4724 function.extraData(CmpXchg, instruction.data)
4725 .cmp.typeOf(function_index, builder),
4726 .i1,
4727 }),
4728 .extractelement => function.extraData(ExtractElement, instruction.data)
4729 .val.typeOf(function_index, builder).childType(builder),
4730 .extractvalue => {
4731 var extra = function.extraDataTrail(ExtractValue, instruction.data);
4732 const indices = extra.trail.next(extra.data.indices_len, u32, function);
4733 return extra.data.val.typeOf(function_index, builder)
4734 .childTypeAt(indices, builder);
4735 },
4736 .@"fcmp false",
4737 .@"fcmp fast false",
4738 .@"fcmp fast oeq",
4739 .@"fcmp fast oge",
4740 .@"fcmp fast ogt",
4741 .@"fcmp fast ole",
4742 .@"fcmp fast olt",
4743 .@"fcmp fast one",
4744 .@"fcmp fast ord",
4745 .@"fcmp fast true",
4746 .@"fcmp fast ueq",
4747 .@"fcmp fast uge",
4748 .@"fcmp fast ugt",
4749 .@"fcmp fast ule",
4750 .@"fcmp fast ult",
4751 .@"fcmp fast une",
4752 .@"fcmp fast uno",
4753 .@"fcmp oeq",
4754 .@"fcmp oge",
4755 .@"fcmp ogt",
4756 .@"fcmp ole",
4757 .@"fcmp olt",
4758 .@"fcmp one",
4759 .@"fcmp ord",
4760 .@"fcmp true",
4761 .@"fcmp ueq",
4762 .@"fcmp uge",
4763 .@"fcmp ugt",
4764 .@"fcmp ule",
4765 .@"fcmp ult",
4766 .@"fcmp une",
4767 .@"fcmp uno",
4768 .@"icmp eq",
4769 .@"icmp ne",
4770 .@"icmp sge",
4771 .@"icmp sgt",
4772 .@"icmp sle",
4773 .@"icmp slt",
4774 .@"icmp uge",
4775 .@"icmp ugt",
4776 .@"icmp ule",
4777 .@"icmp ult",
4778 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder)
4779 .changeScalarAssumeCapacity(.i1, builder),
4780 .fneg,
4781 .@"fneg fast",
4782 => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
4783 .getelementptr,
4784 .@"getelementptr inbounds",
4785 => {
4786 var extra = function.extraDataTrail(GetElementPtr, instruction.data);
4787 const indices = extra.trail.next(extra.data.indices_len, Value, function);
4788 const base_ty = extra.data.base.typeOf(function_index, builder);
4789 if (!base_ty.isVector(builder)) for (indices) |index| {
4790 const index_ty = index.typeOf(function_index, builder);
4791 if (!index_ty.isVector(builder)) continue;
4792 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
4793 };
4794 return base_ty;
4795 },
4796 .insertelement => function.extraData(InsertElement, instruction.data)
4797 .val.typeOf(function_index, builder),
4798 .insertvalue => function.extraData(InsertValue, instruction.data)
4799 .val.typeOf(function_index, builder),
4800 .load,
4801 .@"load atomic",
4802 => function.extraData(Load, instruction.data).type,
4803 .phi,
4804 .@"phi fast",
4805 => function.extraData(Phi, instruction.data).type,
4806 .select,
4807 .@"select fast",
4808 => function.extraData(Select, instruction.data).lhs.typeOf(function_index, builder),
4809 .shufflevector => {
4810 const extra = function.extraData(ShuffleVector, instruction.data);
4811 return extra.lhs.typeOf(function_index, builder).changeLengthAssumeCapacity(
4812 extra.mask.typeOf(function_index, builder).vectorLen(builder),
4813 builder,
4814 );
4815 },
4816 .va_arg => function.extraData(VaArg, instruction.data).type,
4817 };
4818 }
4819
4820 const FormatData = struct {
4821 instruction: Instruction.Index,
4822 function: Function.Index,
4823 builder: *Builder,
4824 };
4825 fn format(
4826 data: FormatData,
4827 comptime fmt_str: []const u8,
4828 _: std.fmt.FormatOptions,
4829 writer: anytype,
4830 ) @TypeOf(writer).Error!void {
4831 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
4832 @compileError("invalid format string: '" ++ fmt_str ++ "'");
4833 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
4834 if (data.instruction == .none) return;
4835 try writer.writeByte(',');
4836 }
4837 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
4838 if (data.instruction == .none) return;
4839 try writer.writeByte(' ');
4840 }
4841 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print(
4842 "{%} ",
4843 .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)},
4844 );
4845 assert(data.instruction != .none);
4846 try writer.print("%{}", .{
4847 data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder),
4848 });
4849 }
4850 pub fn fmt(
4851 self: Instruction.Index,
4852 function: Function.Index,
4853 builder: *Builder,
4854 ) std.fmt.Formatter(format) {
4855 return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
4856 }
4857 };
4858
4859 pub const ExtraIndex = u32;
4860
4861 pub const BrCond = struct {
4862 cond: Value,
4863 then: Block.Index,
4864 @"else": Block.Index,
4865 weights: Weights,
4866 pub const Weights = enum(u32) {
4867 // We can do this as metadata indices 0 and 1 are reserved.
4868 none = 0,
4869 unpredictable = 1,
4870 /// These values should be converted to `Metadata` to be used
4871 /// in a `prof` annotation providing branch weights.
4872 _,
4873 };
4874 };
4875
4876 pub const Switch = struct {
4877 val: Value,
4878 default: Block.Index,
4879 cases_len: u32,
4880 weights: BrCond.Weights,
4881 //case_vals: [cases_len]Constant,
4882 //case_blocks: [cases_len]Block.Index,
4883 };
4884
4885 pub const IndirectBr = struct {
4886 addr: Value,
4887 targets_len: u32,
4888 //targets: [targets_len]Block.Index,
4889 };
4890
4891 pub const Binary = struct {
4892 lhs: Value,
4893 rhs: Value,
4894 };
4895
4896 pub const ExtractElement = struct {
4897 val: Value,
4898 index: Value,
4899 };
4900
4901 pub const InsertElement = struct {
4902 val: Value,
4903 elem: Value,
4904 index: Value,
4905 };
4906
4907 pub const ShuffleVector = struct {
4908 lhs: Value,
4909 rhs: Value,
4910 mask: Value,
4911 };
4912
4913 pub const ExtractValue = struct {
4914 val: Value,
4915 indices_len: u32,
4916 //indices: [indices_len]u32,
4917 };
4918
4919 pub const InsertValue = struct {
4920 val: Value,
4921 elem: Value,
4922 indices_len: u32,
4923 //indices: [indices_len]u32,
4924 };
4925
4926 pub const Alloca = struct {
4927 type: Type,
4928 len: Value,
4929 info: Info,
4930
4931 pub const Kind = enum { normal, inalloca };
4932 pub const Info = packed struct(u32) {
4933 alignment: Alignment,
4934 addr_space: AddrSpace,
4935 _: u2 = undefined,
4936 };
4937 };
4938
4939 pub const Load = struct {
4940 info: MemoryAccessInfo,
4941 type: Type,
4942 ptr: Value,
4943 };
4944
4945 pub const Store = struct {
4946 info: MemoryAccessInfo,
4947 val: Value,
4948 ptr: Value,
4949 };
4950
4951 pub const CmpXchg = struct {
4952 info: MemoryAccessInfo,
4953 ptr: Value,
4954 cmp: Value,
4955 new: Value,
4956
4957 pub const Kind = enum { strong, weak };
4958 };
4959
4960 pub const AtomicRmw = struct {
4961 info: MemoryAccessInfo,
4962 ptr: Value,
4963 val: Value,
4964
4965 pub const Operation = enum(u5) {
4966 xchg = 0,
4967 add = 1,
4968 sub = 2,
4969 @"and" = 3,
4970 nand = 4,
4971 @"or" = 5,
4972 xor = 6,
4973 max = 7,
4974 min = 8,
4975 umax = 9,
4976 umin = 10,
4977 fadd = 11,
4978 fsub = 12,
4979 fmax = 13,
4980 fmin = 14,
4981 none = std.math.maxInt(u5),
4982 };
4983 };
4984
4985 pub const GetElementPtr = struct {
4986 type: Type,
4987 base: Value,
4988 indices_len: u32,
4989 //indices: [indices_len]Value,
4990
4991 pub const Kind = Constant.GetElementPtr.Kind;
4992 };
4993
4994 pub const Cast = struct {
4995 val: Value,
4996 type: Type,
4997
4998 pub const Signedness = Constant.Cast.Signedness;
4999 };
5000
5001 pub const Phi = struct {
5002 type: Type,
5003 //incoming_vals: [block.incoming]Value,
5004 //incoming_blocks: [block.incoming]Block.Index,
5005 };
5006
5007 pub const Select = struct {
5008 cond: Value,
5009 lhs: Value,
5010 rhs: Value,
5011 };
5012
5013 pub const Call = struct {
5014 info: Info,
5015 attributes: FunctionAttributes,
5016 ty: Type,
5017 callee: Value,
5018 args_len: u32,
5019 //args: [args_len]Value,
5020
5021 pub const Kind = enum {
5022 normal,
5023 fast,
5024 musttail,
5025 musttail_fast,
5026 notail,
5027 notail_fast,
5028 tail,
5029 tail_fast,
5030 };
5031 pub const Info = packed struct(u32) {
5032 call_conv: CallConv,
5033 has_op_bundle_cold: bool,
5034 _: u21 = undefined,
5035 };
5036 };
5037
5038 pub const VaArg = struct {
5039 list: Value,
5040 type: Type,
5041 };
5042 };
5043
5044 pub fn deinit(self: *Function, gpa: Allocator) void {
5045 gpa.free(self.extra);
5046 gpa.free(self.debug_values);
5047 self.debug_locations.deinit(gpa);
5048 gpa.free(self.value_indices[0..self.instructions.len]);
5049 gpa.free(self.names[0..self.instructions.len]);
5050 self.instructions.deinit(gpa);
5051 gpa.free(self.blocks);
5052 self.* = undefined;
5053 }
5054
5055 pub fn arg(self: *const Function, index: u32) Value {
5056 const argument = self.instructions.get(index);
5057 assert(argument.tag == .arg);
5058 assert(argument.data == index);
5059
5060 const argument_index: Instruction.Index = @enumFromInt(index);
5061 return argument_index.toValue();
5062 }
5063
5064 const ExtraDataTrail = struct {
5065 index: Instruction.ExtraIndex,
5066
5067 fn nextMut(self: *ExtraDataTrail, len: u32, comptime Item: type, function: *Function) []Item {
5068 const items: []Item = @ptrCast(function.extra[self.index..][0..len]);
5069 self.index += @intCast(len);
5070 return items;
5071 }
5072
5073 fn next(
5074 self: *ExtraDataTrail,
5075 len: u32,
5076 comptime Item: type,
5077 function: *const Function,
5078 ) []const Item {
5079 const items: []const Item = @ptrCast(function.extra[self.index..][0..len]);
5080 self.index += @intCast(len);
5081 return items;
5082 }
5083 };
5084
5085 fn extraDataTrail(
5086 self: *const Function,
5087 comptime T: type,
5088 index: Instruction.ExtraIndex,
5089 ) struct { data: T, trail: ExtraDataTrail } {
5090 var result: T = undefined;
5091 const fields = @typeInfo(T).@"struct".fields;
5092 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
5093 @field(result, field.name) = switch (field.type) {
5094 u32 => value,
5095 Alignment,
5096 AtomicOrdering,
5097 Block.Index,
5098 FunctionAttributes,
5099 Type,
5100 Value,
5101 Instruction.BrCond.Weights,
5102 => @enumFromInt(value),
5103 MemoryAccessInfo,
5104 Instruction.Alloca.Info,
5105 Instruction.Call.Info,
5106 => @bitCast(value),
5107 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
5108 };
5109 return .{
5110 .data = result,
5111 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
5112 };
5113 }
5114
5115 fn extraData(self: *const Function, comptime T: type, index: Instruction.ExtraIndex) T {
5116 return self.extraDataTrail(T, index).data;
5117 }
5118};
5119
5120pub const DebugLocation = union(enum) {
5121 no_location: void,
5122 location: Location,
5123
5124 pub const Location = struct {
5125 line: u32,
5126 column: u32,
5127 scope: Builder.Metadata,
5128 inlined_at: Builder.Metadata,
5129 };
5130
5131 pub fn toMetadata(self: DebugLocation, builder: *Builder) Allocator.Error!Metadata {
5132 return switch (self) {
5133 .no_location => .none,
5134 .location => |location| try builder.debugLocation(
5135 location.line,
5136 location.column,
5137 location.scope,
5138 location.inlined_at,
5139 ),
5140 };
5141 }
5142};
5143
5144pub const WipFunction = struct {
5145 builder: *Builder,
5146 function: Function.Index,
5147 prev_debug_location: DebugLocation,
5148 debug_location: DebugLocation,
5149 cursor: Cursor,
5150 blocks: std.ArrayListUnmanaged(Block),
5151 instructions: std.MultiArrayList(Instruction),
5152 names: std.ArrayListUnmanaged(String),
5153 strip: bool,
5154 debug_locations: std.AutoArrayHashMapUnmanaged(Instruction.Index, DebugLocation),
5155 debug_values: std.AutoArrayHashMapUnmanaged(Instruction.Index, void),
5156 extra: std.ArrayListUnmanaged(u32),
5157
5158 pub const Cursor = struct { block: Block.Index, instruction: u32 = 0 };
5159
5160 pub const Block = struct {
5161 name: String,
5162 incoming: u32,
5163 branches: u32 = 0,
5164 instructions: std.ArrayListUnmanaged(Instruction.Index),
5165
5166 const Index = enum(u32) {
5167 entry,
5168 _,
5169
5170 pub fn ptr(self: Index, wip: *WipFunction) *Block {
5171 return &wip.blocks.items[@intFromEnum(self)];
5172 }
5173
5174 pub fn ptrConst(self: Index, wip: *const WipFunction) *const Block {
5175 return &wip.blocks.items[@intFromEnum(self)];
5176 }
5177
5178 pub fn toInst(self: Index, function: *const Function) Instruction.Index {
5179 return function.blocks[@intFromEnum(self)].instruction;
5180 }
5181 };
5182 };
5183
5184 pub const Instruction = Function.Instruction;
5185
5186 pub fn init(builder: *Builder, options: struct {
5187 function: Function.Index,
5188 strip: bool,
5189 }) Allocator.Error!WipFunction {
5190 var self: WipFunction = .{
5191 .builder = builder,
5192 .function = options.function,
5193 .prev_debug_location = .no_location,
5194 .debug_location = .no_location,
5195 .cursor = undefined,
5196 .blocks = .{},
5197 .instructions = .{},
5198 .names = .{},
5199 .strip = options.strip,
5200 .debug_locations = .{},
5201 .debug_values = .{},
5202 .extra = .{},
5203 };
5204 errdefer self.deinit();
5205
5206 const params_len = options.function.typeOf(self.builder).functionParameters(self.builder).len;
5207 try self.ensureUnusedExtraCapacity(params_len, NoExtra, 0);
5208 try self.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
5209 if (!self.strip) {
5210 try self.names.ensureUnusedCapacity(self.builder.gpa, params_len);
5211 }
5212 for (0..params_len) |param_index| {
5213 self.instructions.appendAssumeCapacity(.{ .tag = .arg, .data = @intCast(param_index) });
5214 if (!self.strip) {
5215 self.names.appendAssumeCapacity(.empty); // TODO: param names
5216 }
5217 }
5218
5219 return self;
5220 }
5221
5222 pub fn arg(self: *const WipFunction, index: u32) Value {
5223 const argument = self.instructions.get(index);
5224 assert(argument.tag == .arg);
5225 assert(argument.data == index);
5226
5227 const argument_index: Instruction.Index = @enumFromInt(index);
5228 return argument_index.toValue();
5229 }
5230
5231 pub fn block(self: *WipFunction, incoming: u32, name: []const u8) Allocator.Error!Block.Index {
5232 try self.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
5233
5234 const index: Block.Index = @enumFromInt(self.blocks.items.len);
5235 const final_name = if (self.strip) .empty else try self.builder.string(name);
5236 self.blocks.appendAssumeCapacity(.{
5237 .name = final_name,
5238 .incoming = incoming,
5239 .instructions = .{},
5240 });
5241 return index;
5242 }
5243
5244 pub fn ret(self: *WipFunction, val: Value) Allocator.Error!Instruction.Index {
5245 assert(val.typeOfWip(self) == self.function.typeOf(self.builder).functionReturn(self.builder));
5246 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5247 return try self.addInst(null, .{ .tag = .ret, .data = @intFromEnum(val) });
5248 }
5249
5250 pub fn retVoid(self: *WipFunction) Allocator.Error!Instruction.Index {
5251 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5252 return try self.addInst(null, .{ .tag = .@"ret void", .data = undefined });
5253 }
5254
5255 pub fn br(self: *WipFunction, dest: Block.Index) Allocator.Error!Instruction.Index {
5256 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5257 const instruction = try self.addInst(null, .{ .tag = .br, .data = @intFromEnum(dest) });
5258 dest.ptr(self).branches += 1;
5259 return instruction;
5260 }
5261
5262 pub fn brCond(
5263 self: *WipFunction,
5264 cond: Value,
5265 then: Block.Index,
5266 @"else": Block.Index,
5267 weights: enum { none, unpredictable, then_likely, else_likely },
5268 ) Allocator.Error!Instruction.Index {
5269 assert(cond.typeOfWip(self) == .i1);
5270 try self.ensureUnusedExtraCapacity(1, Instruction.BrCond, 0);
5271 const instruction = try self.addInst(null, .{
5272 .tag = .br_cond,
5273 .data = self.addExtraAssumeCapacity(Instruction.BrCond{
5274 .cond = cond,
5275 .then = then,
5276 .@"else" = @"else",
5277 .weights = switch (weights) {
5278 .none => .none,
5279 .unpredictable => .unpredictable,
5280 .then_likely, .else_likely => w: {
5281 const branch_weights_str = try self.builder.metadataString("branch_weights");
5282 const unlikely_const = try self.builder.metadataConstant(try self.builder.intConst(.i32, 1));
5283 const likely_const = try self.builder.metadataConstant(try self.builder.intConst(.i32, 2000));
5284 const weight_vals: [2]Metadata = switch (weights) {
5285 .none, .unpredictable => unreachable,
5286 .then_likely => .{ likely_const, unlikely_const },
5287 .else_likely => .{ unlikely_const, likely_const },
5288 };
5289 const tuple = try self.builder.strTuple(branch_weights_str, &weight_vals);
5290 break :w @enumFromInt(@intFromEnum(tuple));
5291 },
5292 },
5293 }),
5294 });
5295 then.ptr(self).branches += 1;
5296 @"else".ptr(self).branches += 1;
5297 return instruction;
5298 }
5299
5300 pub const WipSwitch = struct {
5301 index: u32,
5302 instruction: Instruction.Index,
5303
5304 pub fn addCase(
5305 self: *WipSwitch,
5306 val: Constant,
5307 dest: Block.Index,
5308 wip: *WipFunction,
5309 ) Allocator.Error!void {
5310 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
5311 var extra = wip.extraDataTrail(Instruction.Switch, instruction.data);
5312 assert(val.typeOf(wip.builder) == extra.data.val.typeOfWip(wip));
5313 extra.trail.nextMut(extra.data.cases_len, Constant, wip)[self.index] = val;
5314 extra.trail.nextMut(extra.data.cases_len, Block.Index, wip)[self.index] = dest;
5315 self.index += 1;
5316 dest.ptr(wip).branches += 1;
5317 }
5318
5319 pub fn finish(self: WipSwitch, wip: *WipFunction) void {
5320 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
5321 const extra = wip.extraData(Instruction.Switch, instruction.data);
5322 assert(self.index == extra.cases_len);
5323 }
5324 };
5325
5326 pub fn @"switch"(
5327 self: *WipFunction,
5328 val: Value,
5329 default: Block.Index,
5330 cases_len: u32,
5331 weights: Instruction.BrCond.Weights,
5332 ) Allocator.Error!WipSwitch {
5333 try self.ensureUnusedExtraCapacity(1, Instruction.Switch, cases_len * 2);
5334 const instruction = try self.addInst(null, .{
5335 .tag = .@"switch",
5336 .data = self.addExtraAssumeCapacity(Instruction.Switch{
5337 .val = val,
5338 .default = default,
5339 .cases_len = cases_len,
5340 .weights = weights,
5341 }),
5342 });
5343 _ = self.extra.addManyAsSliceAssumeCapacity(cases_len * 2);
5344 default.ptr(self).branches += 1;
5345 return .{ .index = 0, .instruction = instruction };
5346 }
5347
5348 pub fn indirectbr(
5349 self: *WipFunction,
5350 addr: Value,
5351 targets: []const Block.Index,
5352 ) Allocator.Error!Instruction.Index {
5353 try self.ensureUnusedExtraCapacity(1, Instruction.IndirectBr, targets.len);
5354 const instruction = try self.addInst(null, .{
5355 .tag = .indirectbr,
5356 .data = self.addExtraAssumeCapacity(Instruction.IndirectBr{
5357 .addr = addr,
5358 .targets_len = @intCast(targets.len),
5359 }),
5360 });
5361 _ = self.extra.appendSliceAssumeCapacity(@ptrCast(targets));
5362 for (targets) |target| target.ptr(self).branches += 1;
5363 return instruction;
5364 }
5365
5366 pub fn @"unreachable"(self: *WipFunction) Allocator.Error!Instruction.Index {
5367 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5368 return try self.addInst(null, .{ .tag = .@"unreachable", .data = undefined });
5369 }
5370
5371 pub fn un(
5372 self: *WipFunction,
5373 tag: Instruction.Tag,
5374 val: Value,
5375 name: []const u8,
5376 ) Allocator.Error!Value {
5377 switch (tag) {
5378 .fneg,
5379 .@"fneg fast",
5380 => assert(val.typeOfWip(self).scalarType(self.builder).isFloatingPoint()),
5381 else => unreachable,
5382 }
5383 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5384 const instruction = try self.addInst(name, .{ .tag = tag, .data = @intFromEnum(val) });
5385 return instruction.toValue();
5386 }
5387
5388 pub fn not(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
5389 const ty = val.typeOfWip(self);
5390 const all_ones = try self.builder.splatValue(
5391 ty,
5392 try self.builder.intConst(ty.scalarType(self.builder), -1),
5393 );
5394 return self.bin(.xor, val, all_ones, name);
5395 }
5396
5397 pub fn neg(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
5398 return self.bin(.sub, try self.builder.zeroInitValue(val.typeOfWip(self)), val, name);
5399 }
5400
5401 pub fn bin(
5402 self: *WipFunction,
5403 tag: Instruction.Tag,
5404 lhs: Value,
5405 rhs: Value,
5406 name: []const u8,
5407 ) Allocator.Error!Value {
5408 switch (tag) {
5409 .add,
5410 .@"add nsw",
5411 .@"add nuw",
5412 .@"and",
5413 .ashr,
5414 .@"ashr exact",
5415 .fadd,
5416 .@"fadd fast",
5417 .fdiv,
5418 .@"fdiv fast",
5419 .fmul,
5420 .@"fmul fast",
5421 .frem,
5422 .@"frem fast",
5423 .fsub,
5424 .@"fsub fast",
5425 .lshr,
5426 .@"lshr exact",
5427 .mul,
5428 .@"mul nsw",
5429 .@"mul nuw",
5430 .@"or",
5431 .sdiv,
5432 .@"sdiv exact",
5433 .shl,
5434 .@"shl nsw",
5435 .@"shl nuw",
5436 .srem,
5437 .sub,
5438 .@"sub nsw",
5439 .@"sub nuw",
5440 .udiv,
5441 .@"udiv exact",
5442 .urem,
5443 .xor,
5444 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
5445 else => unreachable,
5446 }
5447 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
5448 const instruction = try self.addInst(name, .{
5449 .tag = tag,
5450 .data = self.addExtraAssumeCapacity(Instruction.Binary{ .lhs = lhs, .rhs = rhs }),
5451 });
5452 return instruction.toValue();
5453 }
5454
5455 pub fn extractElement(
5456 self: *WipFunction,
5457 val: Value,
5458 index: Value,
5459 name: []const u8,
5460 ) Allocator.Error!Value {
5461 assert(val.typeOfWip(self).isVector(self.builder));
5462 assert(index.typeOfWip(self).isInteger(self.builder));
5463 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractElement, 0);
5464 const instruction = try self.addInst(name, .{
5465 .tag = .extractelement,
5466 .data = self.addExtraAssumeCapacity(Instruction.ExtractElement{
5467 .val = val,
5468 .index = index,
5469 }),
5470 });
5471 return instruction.toValue();
5472 }
5473
5474 pub fn insertElement(
5475 self: *WipFunction,
5476 val: Value,
5477 elem: Value,
5478 index: Value,
5479 name: []const u8,
5480 ) Allocator.Error!Value {
5481 assert(val.typeOfWip(self).scalarType(self.builder) == elem.typeOfWip(self));
5482 assert(index.typeOfWip(self).isInteger(self.builder));
5483 try self.ensureUnusedExtraCapacity(1, Instruction.InsertElement, 0);
5484 const instruction = try self.addInst(name, .{
5485 .tag = .insertelement,
5486 .data = self.addExtraAssumeCapacity(Instruction.InsertElement{
5487 .val = val,
5488 .elem = elem,
5489 .index = index,
5490 }),
5491 });
5492 return instruction.toValue();
5493 }
5494
5495 pub fn shuffleVector(
5496 self: *WipFunction,
5497 lhs: Value,
5498 rhs: Value,
5499 mask: Value,
5500 name: []const u8,
5501 ) Allocator.Error!Value {
5502 assert(lhs.typeOfWip(self).isVector(self.builder));
5503 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
5504 assert(mask.typeOfWip(self).scalarType(self.builder).isInteger(self.builder));
5505 _ = try self.ensureUnusedExtraCapacity(1, Instruction.ShuffleVector, 0);
5506 const instruction = try self.addInst(name, .{
5507 .tag = .shufflevector,
5508 .data = self.addExtraAssumeCapacity(Instruction.ShuffleVector{
5509 .lhs = lhs,
5510 .rhs = rhs,
5511 .mask = mask,
5512 }),
5513 });
5514 return instruction.toValue();
5515 }
5516
5517 pub fn splatVector(
5518 self: *WipFunction,
5519 ty: Type,
5520 elem: Value,
5521 name: []const u8,
5522 ) Allocator.Error!Value {
5523 const scalar_ty = try ty.changeLength(1, self.builder);
5524 const mask_ty = try ty.changeScalar(.i32, self.builder);
5525 const poison = try self.builder.poisonValue(scalar_ty);
5526 const mask = try self.builder.splatValue(mask_ty, .@"0");
5527 const scalar = try self.insertElement(poison, elem, .@"0", name);
5528 return self.shuffleVector(scalar, poison, mask, name);
5529 }
5530
5531 pub fn extractValue(
5532 self: *WipFunction,
5533 val: Value,
5534 indices: []const u32,
5535 name: []const u8,
5536 ) Allocator.Error!Value {
5537 assert(indices.len > 0);
5538 _ = val.typeOfWip(self).childTypeAt(indices, self.builder);
5539 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractValue, indices.len);
5540 const instruction = try self.addInst(name, .{
5541 .tag = .extractvalue,
5542 .data = self.addExtraAssumeCapacity(Instruction.ExtractValue{
5543 .val = val,
5544 .indices_len = @intCast(indices.len),
5545 }),
5546 });
5547 self.extra.appendSliceAssumeCapacity(indices);
5548 return instruction.toValue();
5549 }
5550
5551 pub fn insertValue(
5552 self: *WipFunction,
5553 val: Value,
5554 elem: Value,
5555 indices: []const u32,
5556 name: []const u8,
5557 ) Allocator.Error!Value {
5558 assert(indices.len > 0);
5559 assert(val.typeOfWip(self).childTypeAt(indices, self.builder) == elem.typeOfWip(self));
5560 try self.ensureUnusedExtraCapacity(1, Instruction.InsertValue, indices.len);
5561 const instruction = try self.addInst(name, .{
5562 .tag = .insertvalue,
5563 .data = self.addExtraAssumeCapacity(Instruction.InsertValue{
5564 .val = val,
5565 .elem = elem,
5566 .indices_len = @intCast(indices.len),
5567 }),
5568 });
5569 self.extra.appendSliceAssumeCapacity(indices);
5570 return instruction.toValue();
5571 }
5572
5573 pub fn buildAggregate(
5574 self: *WipFunction,
5575 ty: Type,
5576 elems: []const Value,
5577 name: []const u8,
5578 ) Allocator.Error!Value {
5579 assert(ty.aggregateLen(self.builder) == elems.len);
5580 var cur = try self.builder.poisonValue(ty);
5581 for (elems, 0..) |elem, index|
5582 cur = try self.insertValue(cur, elem, &[_]u32{@intCast(index)}, name);
5583 return cur;
5584 }
5585
5586 pub fn alloca(
5587 self: *WipFunction,
5588 kind: Instruction.Alloca.Kind,
5589 ty: Type,
5590 len: Value,
5591 alignment: Alignment,
5592 addr_space: AddrSpace,
5593 name: []const u8,
5594 ) Allocator.Error!Value {
5595 assert(len == .none or len.typeOfWip(self).isInteger(self.builder));
5596 _ = try self.builder.ptrType(addr_space);
5597 try self.ensureUnusedExtraCapacity(1, Instruction.Alloca, 0);
5598 const instruction = try self.addInst(name, .{
5599 .tag = switch (kind) {
5600 .normal => .alloca,
5601 .inalloca => .@"alloca inalloca",
5602 },
5603 .data = self.addExtraAssumeCapacity(Instruction.Alloca{
5604 .type = ty,
5605 .len = switch (len) {
5606 .none => .@"1",
5607 else => len,
5608 },
5609 .info = .{ .alignment = alignment, .addr_space = addr_space },
5610 }),
5611 });
5612 return instruction.toValue();
5613 }
5614
5615 pub fn load(
5616 self: *WipFunction,
5617 access_kind: MemoryAccessKind,
5618 ty: Type,
5619 ptr: Value,
5620 alignment: Alignment,
5621 name: []const u8,
5622 ) Allocator.Error!Value {
5623 return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name);
5624 }
5625
5626 pub fn loadAtomic(
5627 self: *WipFunction,
5628 access_kind: MemoryAccessKind,
5629 ty: Type,
5630 ptr: Value,
5631 sync_scope: SyncScope,
5632 ordering: AtomicOrdering,
5633 alignment: Alignment,
5634 name: []const u8,
5635 ) Allocator.Error!Value {
5636 assert(ptr.typeOfWip(self).isPointer(self.builder));
5637 try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
5638 const instruction = try self.addInst(name, .{
5639 .tag = switch (ordering) {
5640 .none => .load,
5641 else => .@"load atomic",
5642 },
5643 .data = self.addExtraAssumeCapacity(Instruction.Load{
5644 .info = .{
5645 .access_kind = access_kind,
5646 .sync_scope = switch (ordering) {
5647 .none => .system,
5648 else => sync_scope,
5649 },
5650 .success_ordering = ordering,
5651 .alignment = alignment,
5652 },
5653 .type = ty,
5654 .ptr = ptr,
5655 }),
5656 });
5657 return instruction.toValue();
5658 }
5659
5660 pub fn store(
5661 self: *WipFunction,
5662 kind: MemoryAccessKind,
5663 val: Value,
5664 ptr: Value,
5665 alignment: Alignment,
5666 ) Allocator.Error!Instruction.Index {
5667 return self.storeAtomic(kind, val, ptr, .system, .none, alignment);
5668 }
5669
5670 pub fn storeAtomic(
5671 self: *WipFunction,
5672 access_kind: MemoryAccessKind,
5673 val: Value,
5674 ptr: Value,
5675 sync_scope: SyncScope,
5676 ordering: AtomicOrdering,
5677 alignment: Alignment,
5678 ) Allocator.Error!Instruction.Index {
5679 assert(ptr.typeOfWip(self).isPointer(self.builder));
5680 try self.ensureUnusedExtraCapacity(1, Instruction.Store, 0);
5681 const instruction = try self.addInst(null, .{
5682 .tag = switch (ordering) {
5683 .none => .store,
5684 else => .@"store atomic",
5685 },
5686 .data = self.addExtraAssumeCapacity(Instruction.Store{
5687 .info = .{
5688 .access_kind = access_kind,
5689 .sync_scope = switch (ordering) {
5690 .none => .system,
5691 else => sync_scope,
5692 },
5693 .success_ordering = ordering,
5694 .alignment = alignment,
5695 },
5696 .val = val,
5697 .ptr = ptr,
5698 }),
5699 });
5700 return instruction;
5701 }
5702
5703 pub fn fence(
5704 self: *WipFunction,
5705 sync_scope: SyncScope,
5706 ordering: AtomicOrdering,
5707 ) Allocator.Error!Instruction.Index {
5708 assert(ordering != .none);
5709 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5710 const instruction = try self.addInst(null, .{
5711 .tag = .fence,
5712 .data = @bitCast(MemoryAccessInfo{
5713 .sync_scope = sync_scope,
5714 .success_ordering = ordering,
5715 }),
5716 });
5717 return instruction;
5718 }
5719
5720 pub fn cmpxchg(
5721 self: *WipFunction,
5722 kind: Instruction.CmpXchg.Kind,
5723 access_kind: MemoryAccessKind,
5724 ptr: Value,
5725 cmp: Value,
5726 new: Value,
5727 sync_scope: SyncScope,
5728 success_ordering: AtomicOrdering,
5729 failure_ordering: AtomicOrdering,
5730 alignment: Alignment,
5731 name: []const u8,
5732 ) Allocator.Error!Value {
5733 assert(ptr.typeOfWip(self).isPointer(self.builder));
5734 const ty = cmp.typeOfWip(self);
5735 assert(ty == new.typeOfWip(self));
5736 assert(success_ordering != .none);
5737 assert(failure_ordering != .none);
5738
5739 _ = try self.builder.structType(.normal, &.{ ty, .i1 });
5740 try self.ensureUnusedExtraCapacity(1, Instruction.CmpXchg, 0);
5741 const instruction = try self.addInst(name, .{
5742 .tag = switch (kind) {
5743 .strong => .cmpxchg,
5744 .weak => .@"cmpxchg weak",
5745 },
5746 .data = self.addExtraAssumeCapacity(Instruction.CmpXchg{
5747 .info = .{
5748 .access_kind = access_kind,
5749 .sync_scope = sync_scope,
5750 .success_ordering = success_ordering,
5751 .failure_ordering = failure_ordering,
5752 .alignment = alignment,
5753 },
5754 .ptr = ptr,
5755 .cmp = cmp,
5756 .new = new,
5757 }),
5758 });
5759 return instruction.toValue();
5760 }
5761
5762 pub fn atomicrmw(
5763 self: *WipFunction,
5764 access_kind: MemoryAccessKind,
5765 operation: Instruction.AtomicRmw.Operation,
5766 ptr: Value,
5767 val: Value,
5768 sync_scope: SyncScope,
5769 ordering: AtomicOrdering,
5770 alignment: Alignment,
5771 name: []const u8,
5772 ) Allocator.Error!Value {
5773 assert(ptr.typeOfWip(self).isPointer(self.builder));
5774 assert(ordering != .none);
5775
5776 try self.ensureUnusedExtraCapacity(1, Instruction.AtomicRmw, 0);
5777 const instruction = try self.addInst(name, .{
5778 .tag = .atomicrmw,
5779 .data = self.addExtraAssumeCapacity(Instruction.AtomicRmw{
5780 .info = .{
5781 .access_kind = access_kind,
5782 .atomic_rmw_operation = operation,
5783 .sync_scope = sync_scope,
5784 .success_ordering = ordering,
5785 .alignment = alignment,
5786 },
5787 .ptr = ptr,
5788 .val = val,
5789 }),
5790 });
5791 return instruction.toValue();
5792 }
5793
5794 pub fn gep(
5795 self: *WipFunction,
5796 kind: Instruction.GetElementPtr.Kind,
5797 ty: Type,
5798 base: Value,
5799 indices: []const Value,
5800 name: []const u8,
5801 ) Allocator.Error!Value {
5802 const base_ty = base.typeOfWip(self);
5803 const base_is_vector = base_ty.isVector(self.builder);
5804
5805 const VectorInfo = struct {
5806 kind: Type.Vector.Kind,
5807 len: u32,
5808
5809 fn init(vector_ty: Type, builder: *const Builder) @This() {
5810 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
5811 }
5812 };
5813 var vector_info: ?VectorInfo =
5814 if (base_is_vector) VectorInfo.init(base_ty, self.builder) else null;
5815 for (indices) |index| {
5816 const index_ty = index.typeOfWip(self);
5817 switch (index_ty.tag(self.builder)) {
5818 .integer => {},
5819 .vector, .scalable_vector => {
5820 const index_info = VectorInfo.init(index_ty, self.builder);
5821 if (vector_info) |info|
5822 assert(std.meta.eql(info, index_info))
5823 else
5824 vector_info = index_info;
5825 },
5826 else => unreachable,
5827 }
5828 }
5829 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
5830 inline else => |vector_kind| _ = try self.builder.vectorType(
5831 vector_kind,
5832 info.len,
5833 base_ty,
5834 ),
5835 };
5836
5837 try self.ensureUnusedExtraCapacity(1, Instruction.GetElementPtr, indices.len);
5838 const instruction = try self.addInst(name, .{
5839 .tag = switch (kind) {
5840 .normal => .getelementptr,
5841 .inbounds => .@"getelementptr inbounds",
5842 },
5843 .data = self.addExtraAssumeCapacity(Instruction.GetElementPtr{
5844 .type = ty,
5845 .base = base,
5846 .indices_len = @intCast(indices.len),
5847 }),
5848 });
5849 self.extra.appendSliceAssumeCapacity(@ptrCast(indices));
5850 return instruction.toValue();
5851 }
5852
5853 pub fn gepStruct(
5854 self: *WipFunction,
5855 ty: Type,
5856 base: Value,
5857 index: usize,
5858 name: []const u8,
5859 ) Allocator.Error!Value {
5860 assert(ty.isStruct(self.builder));
5861 return self.gep(.inbounds, ty, base, &.{ .@"0", try self.builder.intValue(.i32, index) }, name);
5862 }
5863
5864 pub fn conv(
5865 self: *WipFunction,
5866 signedness: Instruction.Cast.Signedness,
5867 val: Value,
5868 ty: Type,
5869 name: []const u8,
5870 ) Allocator.Error!Value {
5871 const val_ty = val.typeOfWip(self);
5872 if (val_ty == ty) return val;
5873 return self.cast(self.builder.convTag(signedness, val_ty, ty), val, ty, name);
5874 }
5875
5876 pub fn cast(
5877 self: *WipFunction,
5878 tag: Instruction.Tag,
5879 val: Value,
5880 ty: Type,
5881 name: []const u8,
5882 ) Allocator.Error!Value {
5883 switch (tag) {
5884 .addrspacecast,
5885 .bitcast,
5886 .fpext,
5887 .fptosi,
5888 .fptoui,
5889 .fptrunc,
5890 .inttoptr,
5891 .ptrtoint,
5892 .sext,
5893 .sitofp,
5894 .trunc,
5895 .uitofp,
5896 .zext,
5897 => {},
5898 else => unreachable,
5899 }
5900 if (val.typeOfWip(self) == ty) return val;
5901 try self.ensureUnusedExtraCapacity(1, Instruction.Cast, 0);
5902 const instruction = try self.addInst(name, .{
5903 .tag = tag,
5904 .data = self.addExtraAssumeCapacity(Instruction.Cast{
5905 .val = val,
5906 .type = ty,
5907 }),
5908 });
5909 return instruction.toValue();
5910 }
5911
5912 pub fn icmp(
5913 self: *WipFunction,
5914 cond: IntegerCondition,
5915 lhs: Value,
5916 rhs: Value,
5917 name: []const u8,
5918 ) Allocator.Error!Value {
5919 return self.cmpTag(switch (cond) {
5920 inline else => |tag| @field(Instruction.Tag, "icmp " ++ @tagName(tag)),
5921 }, lhs, rhs, name);
5922 }
5923
5924 pub fn fcmp(
5925 self: *WipFunction,
5926 fast: FastMathKind,
5927 cond: FloatCondition,
5928 lhs: Value,
5929 rhs: Value,
5930 name: []const u8,
5931 ) Allocator.Error!Value {
5932 return self.cmpTag(switch (fast) {
5933 inline else => |fast_tag| switch (cond) {
5934 inline else => |cond_tag| @field(Instruction.Tag, "fcmp " ++ switch (fast_tag) {
5935 .normal => "",
5936 .fast => "fast ",
5937 } ++ @tagName(cond_tag)),
5938 },
5939 }, lhs, rhs, name);
5940 }
5941
5942 pub const WipPhi = struct {
5943 block: Block.Index,
5944 instruction: Instruction.Index,
5945
5946 pub fn toValue(self: WipPhi) Value {
5947 return self.instruction.toValue();
5948 }
5949
5950 pub fn finish(
5951 self: WipPhi,
5952 vals: []const Value,
5953 blocks: []const Block.Index,
5954 wip: *WipFunction,
5955 ) void {
5956 const incoming_len = self.block.ptrConst(wip).incoming;
5957 assert(vals.len == incoming_len and blocks.len == incoming_len);
5958 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
5959 var extra = wip.extraDataTrail(Instruction.Phi, instruction.data);
5960 for (vals) |val| assert(val.typeOfWip(wip) == extra.data.type);
5961 @memcpy(extra.trail.nextMut(incoming_len, Value, wip), vals);
5962 @memcpy(extra.trail.nextMut(incoming_len, Block.Index, wip), blocks);
5963 }
5964 };
5965
5966 pub fn phi(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
5967 return self.phiTag(.phi, ty, name);
5968 }
5969
5970 pub fn phiFast(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
5971 return self.phiTag(.@"phi fast", ty, name);
5972 }
5973
5974 pub fn select(
5975 self: *WipFunction,
5976 fast: FastMathKind,
5977 cond: Value,
5978 lhs: Value,
5979 rhs: Value,
5980 name: []const u8,
5981 ) Allocator.Error!Value {
5982 return self.selectTag(switch (fast) {
5983 .normal => .select,
5984 .fast => .@"select fast",
5985 }, cond, lhs, rhs, name);
5986 }
5987
5988 pub fn call(
5989 self: *WipFunction,
5990 kind: Instruction.Call.Kind,
5991 call_conv: CallConv,
5992 function_attributes: FunctionAttributes,
5993 ty: Type,
5994 callee: Value,
5995 args: []const Value,
5996 name: []const u8,
5997 ) Allocator.Error!Value {
5998 return self.callInner(kind, call_conv, function_attributes, ty, callee, args, name, false);
5999 }
6000
6001 fn callInner(
6002 self: *WipFunction,
6003 kind: Instruction.Call.Kind,
6004 call_conv: CallConv,
6005 function_attributes: FunctionAttributes,
6006 ty: Type,
6007 callee: Value,
6008 args: []const Value,
6009 name: []const u8,
6010 has_op_bundle_cold: bool,
6011 ) Allocator.Error!Value {
6012 const ret_ty = ty.functionReturn(self.builder);
6013 assert(ty.isFunction(self.builder));
6014 assert(callee.typeOfWip(self).isPointer(self.builder));
6015 const params = ty.functionParameters(self.builder);
6016 for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self));
6017
6018 try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len);
6019 const instruction = try self.addInst(switch (ret_ty) {
6020 .void => null,
6021 else => name,
6022 }, .{
6023 .tag = switch (kind) {
6024 .normal => .call,
6025 .fast => .@"call fast",
6026 .musttail => .@"musttail call",
6027 .musttail_fast => .@"musttail call fast",
6028 .notail => .@"notail call",
6029 .notail_fast => .@"notail call fast",
6030 .tail => .@"tail call",
6031 .tail_fast => .@"tail call fast",
6032 },
6033 .data = self.addExtraAssumeCapacity(Instruction.Call{
6034 .info = .{
6035 .call_conv = call_conv,
6036 .has_op_bundle_cold = has_op_bundle_cold,
6037 },
6038 .attributes = function_attributes,
6039 .ty = ty,
6040 .callee = callee,
6041 .args_len = @intCast(args.len),
6042 }),
6043 });
6044 self.extra.appendSliceAssumeCapacity(@ptrCast(args));
6045 return instruction.toValue();
6046 }
6047
6048 pub fn callAsm(
6049 self: *WipFunction,
6050 function_attributes: FunctionAttributes,
6051 ty: Type,
6052 kind: Constant.Assembly.Info,
6053 assembly: String,
6054 constraints: String,
6055 args: []const Value,
6056 name: []const u8,
6057 ) Allocator.Error!Value {
6058 const callee = try self.builder.asmValue(ty, kind, assembly, constraints);
6059 return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name);
6060 }
6061
6062 pub fn callIntrinsic(
6063 self: *WipFunction,
6064 fast: FastMathKind,
6065 function_attributes: FunctionAttributes,
6066 id: Intrinsic,
6067 overload: []const Type,
6068 args: []const Value,
6069 name: []const u8,
6070 ) Allocator.Error!Value {
6071 const intrinsic = try self.builder.getIntrinsic(id, overload);
6072 return self.call(
6073 fast.toCallKind(),
6074 CallConv.default,
6075 function_attributes,
6076 intrinsic.typeOf(self.builder),
6077 intrinsic.toValue(self.builder),
6078 args,
6079 name,
6080 );
6081 }
6082
6083 pub fn callIntrinsicAssumeCold(self: *WipFunction) Allocator.Error!Value {
6084 const intrinsic = try self.builder.getIntrinsic(.assume, &.{});
6085 return self.callInner(
6086 .normal,
6087 CallConv.default,
6088 .none,
6089 intrinsic.typeOf(self.builder),
6090 intrinsic.toValue(self.builder),
6091 &.{try self.builder.intValue(.i1, 1)},
6092 "",
6093 true,
6094 );
6095 }
6096
6097 pub fn callMemCpy(
6098 self: *WipFunction,
6099 dst: Value,
6100 dst_align: Alignment,
6101 src: Value,
6102 src_align: Alignment,
6103 len: Value,
6104 kind: MemoryAccessKind,
6105 @"inline": bool,
6106 ) Allocator.Error!Instruction.Index {
6107 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6108 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
6109 const value = try self.callIntrinsic(
6110 .normal,
6111 try self.builder.fnAttrs(&.{
6112 .none,
6113 .none,
6114 try self.builder.attrs(&dst_attrs),
6115 try self.builder.attrs(&src_attrs),
6116 }),
6117 if (@"inline") .@"memcpy.inline" else .memcpy,
6118 &.{ dst.typeOfWip(self), src.typeOfWip(self), len.typeOfWip(self) },
6119 &.{ dst, src, len, switch (kind) {
6120 .normal => Value.false,
6121 .@"volatile" => Value.true,
6122 } },
6123 undefined,
6124 );
6125 return value.unwrap().instruction;
6126 }
6127
6128 pub fn callMemSet(
6129 self: *WipFunction,
6130 dst: Value,
6131 dst_align: Alignment,
6132 val: Value,
6133 len: Value,
6134 kind: MemoryAccessKind,
6135 @"inline": bool,
6136 ) Allocator.Error!Instruction.Index {
6137 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6138 const value = try self.callIntrinsic(
6139 .normal,
6140 try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
6141 if (@"inline") .@"memset.inline" else .memset,
6142 &.{ dst.typeOfWip(self), len.typeOfWip(self) },
6143 &.{ dst, val, len, switch (kind) {
6144 .normal => Value.false,
6145 .@"volatile" => Value.true,
6146 } },
6147 undefined,
6148 );
6149 return value.unwrap().instruction;
6150 }
6151
6152 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
6153 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
6154 const instruction = try self.addInst(name, .{
6155 .tag = .va_arg,
6156 .data = self.addExtraAssumeCapacity(Instruction.VaArg{
6157 .list = list,
6158 .type = ty,
6159 }),
6160 });
6161 return instruction.toValue();
6162 }
6163
6164 pub fn debugValue(self: *WipFunction, value: Value) Allocator.Error!Metadata {
6165 if (self.strip) return .none;
6166 return switch (value.unwrap()) {
6167 .instruction => |instr_index| blk: {
6168 const gop = try self.debug_values.getOrPut(self.builder.gpa, instr_index);
6169
6170 const metadata: Metadata = @enumFromInt(Metadata.first_local_metadata + gop.index);
6171 if (!gop.found_existing) gop.key_ptr.* = instr_index;
6172
6173 break :blk metadata;
6174 },
6175 .constant => |constant| try self.builder.metadataConstant(constant),
6176 .metadata => |metadata| metadata,
6177 };
6178 }
6179
6180 pub fn finish(self: *WipFunction) Allocator.Error!void {
6181 const gpa = self.builder.gpa;
6182 const function = self.function.ptr(self.builder);
6183 const params_len = self.function.typeOf(self.builder).functionParameters(self.builder).len;
6184 const final_instructions_len = self.blocks.items.len + self.instructions.len;
6185
6186 const blocks = try gpa.alloc(Function.Block, self.blocks.items.len);
6187 errdefer gpa.free(blocks);
6188
6189 const instructions: struct {
6190 items: []Instruction.Index,
6191
6192 fn map(instructions: @This(), val: Value) Value {
6193 if (val == .none) return .none;
6194 return switch (val.unwrap()) {
6195 .instruction => |instruction| instructions.items[
6196 @intFromEnum(instruction)
6197 ].toValue(),
6198 .constant => |constant| constant.toValue(),
6199 .metadata => |metadata| metadata.toValue(),
6200 };
6201 }
6202 } = .{ .items = try gpa.alloc(Instruction.Index, self.instructions.len) };
6203 defer gpa.free(instructions.items);
6204
6205 const names = try gpa.alloc(String, final_instructions_len);
6206 errdefer gpa.free(names);
6207
6208 const value_indices = try gpa.alloc(u32, final_instructions_len);
6209 errdefer gpa.free(value_indices);
6210
6211 var debug_locations: std.AutoHashMapUnmanaged(Instruction.Index, DebugLocation) = .empty;
6212 errdefer debug_locations.deinit(gpa);
6213 try debug_locations.ensureUnusedCapacity(gpa, @intCast(self.debug_locations.count()));
6214
6215 const debug_values = try gpa.alloc(Instruction.Index, self.debug_values.count());
6216 errdefer gpa.free(debug_values);
6217
6218 var wip_extra: struct {
6219 index: Instruction.ExtraIndex = 0,
6220 items: []u32,
6221
6222 fn addExtra(wip_extra: *@This(), extra: anytype) Instruction.ExtraIndex {
6223 const result = wip_extra.index;
6224 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
6225 const value = @field(extra, field.name);
6226 wip_extra.items[wip_extra.index] = switch (field.type) {
6227 u32 => value,
6228 Alignment,
6229 AtomicOrdering,
6230 Block.Index,
6231 FunctionAttributes,
6232 Type,
6233 Value,
6234 Instruction.BrCond.Weights,
6235 => @intFromEnum(value),
6236 MemoryAccessInfo,
6237 Instruction.Alloca.Info,
6238 Instruction.Call.Info,
6239 => @bitCast(value),
6240 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
6241 };
6242 wip_extra.index += 1;
6243 }
6244 return result;
6245 }
6246
6247 fn appendSlice(wip_extra: *@This(), slice: anytype) void {
6248 if (@typeInfo(@TypeOf(slice)).pointer.child == Value)
6249 @compileError("use appendMappedValues");
6250 const data: []const u32 = @ptrCast(slice);
6251 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
6252 wip_extra.index += @intCast(data.len);
6253 }
6254
6255 fn appendMappedValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
6256 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
6257 extra.* = @intFromEnum(ctx.map(val));
6258 wip_extra.index += @intCast(vals.len);
6259 }
6260
6261 fn finish(wip_extra: *const @This()) []const u32 {
6262 assert(wip_extra.index == wip_extra.items.len);
6263 return wip_extra.items;
6264 }
6265 } = .{ .items = try gpa.alloc(u32, self.extra.items.len) };
6266 errdefer gpa.free(wip_extra.items);
6267
6268 gpa.free(function.blocks);
6269 function.blocks = &.{};
6270 gpa.free(function.names[0..function.instructions.len]);
6271 function.debug_locations.deinit(gpa);
6272 function.debug_locations = .{};
6273 gpa.free(function.debug_values);
6274 function.debug_values = &.{};
6275 gpa.free(function.extra);
6276 function.extra = &.{};
6277
6278 function.instructions.shrinkRetainingCapacity(0);
6279 try function.instructions.setCapacity(gpa, final_instructions_len);
6280 errdefer function.instructions.shrinkRetainingCapacity(0);
6281
6282 {
6283 var final_instruction_index: Instruction.Index = @enumFromInt(0);
6284 for (0..params_len) |param_index| {
6285 instructions.items[param_index] = final_instruction_index;
6286 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
6287 }
6288 for (blocks, self.blocks.items) |*final_block, current_block| {
6289 assert(current_block.incoming == current_block.branches);
6290 final_block.instruction = final_instruction_index;
6291 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
6292 for (current_block.instructions.items) |instruction| {
6293 instructions.items[@intFromEnum(instruction)] = final_instruction_index;
6294 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
6295 }
6296 }
6297 }
6298
6299 var wip_name: struct {
6300 next_name: String = @enumFromInt(0),
6301 next_unique_name: std.AutoHashMap(String, String),
6302 builder: *Builder,
6303
6304 fn map(wip_name: *@This(), name: String, sep: []const u8) Allocator.Error!String {
6305 switch (name) {
6306 .none => return .none,
6307 .empty => {
6308 assert(wip_name.next_name != .none);
6309 defer wip_name.next_name = @enumFromInt(@intFromEnum(wip_name.next_name) + 1);
6310 return wip_name.next_name;
6311 },
6312 _ => {
6313 assert(!name.isAnon());
6314 const gop = try wip_name.next_unique_name.getOrPut(name);
6315 if (!gop.found_existing) {
6316 gop.value_ptr.* = @enumFromInt(0);
6317 return name;
6318 }
6319
6320 while (true) {
6321 gop.value_ptr.* = @enumFromInt(@intFromEnum(gop.value_ptr.*) + 1);
6322 const unique_name = try wip_name.builder.fmt("{r}{s}{r}", .{
6323 name.fmt(wip_name.builder),
6324 sep,
6325 gop.value_ptr.fmt(wip_name.builder),
6326 });
6327 const unique_gop = try wip_name.next_unique_name.getOrPut(unique_name);
6328 if (!unique_gop.found_existing) {
6329 unique_gop.value_ptr.* = @enumFromInt(0);
6330 return unique_name;
6331 }
6332 }
6333 },
6334 }
6335 }
6336 } = .{
6337 .next_unique_name = std.AutoHashMap(String, String).init(gpa),
6338 .builder = self.builder,
6339 };
6340 defer wip_name.next_unique_name.deinit();
6341
6342 var value_index: u32 = 0;
6343 for (0..params_len) |param_index| {
6344 const old_argument_index: Instruction.Index = @enumFromInt(param_index);
6345 const new_argument_index: Instruction.Index = @enumFromInt(function.instructions.len);
6346 const argument = self.instructions.get(@intFromEnum(old_argument_index));
6347 assert(argument.tag == .arg);
6348 assert(argument.data == param_index);
6349 value_indices[function.instructions.len] = value_index;
6350 value_index += 1;
6351 function.instructions.appendAssumeCapacity(argument);
6352 names[@intFromEnum(new_argument_index)] = try wip_name.map(
6353 if (self.strip) .empty else self.names.items[@intFromEnum(old_argument_index)],
6354 ".",
6355 );
6356 if (self.debug_locations.get(old_argument_index)) |location| {
6357 debug_locations.putAssumeCapacity(new_argument_index, location);
6358 }
6359 if (self.debug_values.getIndex(old_argument_index)) |index| {
6360 debug_values[index] = new_argument_index;
6361 }
6362 }
6363 for (self.blocks.items) |current_block| {
6364 const new_block_index: Instruction.Index = @enumFromInt(function.instructions.len);
6365 value_indices[function.instructions.len] = value_index;
6366 function.instructions.appendAssumeCapacity(.{
6367 .tag = .block,
6368 .data = current_block.incoming,
6369 });
6370 names[@intFromEnum(new_block_index)] = try wip_name.map(current_block.name, "");
6371 for (current_block.instructions.items) |old_instruction_index| {
6372 const new_instruction_index: Instruction.Index = @enumFromInt(function.instructions.len);
6373 var instruction = self.instructions.get(@intFromEnum(old_instruction_index));
6374 switch (instruction.tag) {
6375 .add,
6376 .@"add nsw",
6377 .@"add nuw",
6378 .@"add nuw nsw",
6379 .@"and",
6380 .ashr,
6381 .@"ashr exact",
6382 .fadd,
6383 .@"fadd fast",
6384 .@"fcmp false",
6385 .@"fcmp fast false",
6386 .@"fcmp fast oeq",
6387 .@"fcmp fast oge",
6388 .@"fcmp fast ogt",
6389 .@"fcmp fast ole",
6390 .@"fcmp fast olt",
6391 .@"fcmp fast one",
6392 .@"fcmp fast ord",
6393 .@"fcmp fast true",
6394 .@"fcmp fast ueq",
6395 .@"fcmp fast uge",
6396 .@"fcmp fast ugt",
6397 .@"fcmp fast ule",
6398 .@"fcmp fast ult",
6399 .@"fcmp fast une",
6400 .@"fcmp fast uno",
6401 .@"fcmp oeq",
6402 .@"fcmp oge",
6403 .@"fcmp ogt",
6404 .@"fcmp ole",
6405 .@"fcmp olt",
6406 .@"fcmp one",
6407 .@"fcmp ord",
6408 .@"fcmp true",
6409 .@"fcmp ueq",
6410 .@"fcmp uge",
6411 .@"fcmp ugt",
6412 .@"fcmp ule",
6413 .@"fcmp ult",
6414 .@"fcmp une",
6415 .@"fcmp uno",
6416 .fdiv,
6417 .@"fdiv fast",
6418 .fmul,
6419 .@"fmul fast",
6420 .frem,
6421 .@"frem fast",
6422 .fsub,
6423 .@"fsub fast",
6424 .@"icmp eq",
6425 .@"icmp ne",
6426 .@"icmp sge",
6427 .@"icmp sgt",
6428 .@"icmp sle",
6429 .@"icmp slt",
6430 .@"icmp uge",
6431 .@"icmp ugt",
6432 .@"icmp ule",
6433 .@"icmp ult",
6434 .lshr,
6435 .@"lshr exact",
6436 .mul,
6437 .@"mul nsw",
6438 .@"mul nuw",
6439 .@"mul nuw nsw",
6440 .@"or",
6441 .sdiv,
6442 .@"sdiv exact",
6443 .shl,
6444 .@"shl nsw",
6445 .@"shl nuw",
6446 .@"shl nuw nsw",
6447 .srem,
6448 .sub,
6449 .@"sub nsw",
6450 .@"sub nuw",
6451 .@"sub nuw nsw",
6452 .udiv,
6453 .@"udiv exact",
6454 .urem,
6455 .xor,
6456 => {
6457 const extra = self.extraData(Instruction.Binary, instruction.data);
6458 instruction.data = wip_extra.addExtra(Instruction.Binary{
6459 .lhs = instructions.map(extra.lhs),
6460 .rhs = instructions.map(extra.rhs),
6461 });
6462 },
6463 .addrspacecast,
6464 .bitcast,
6465 .fpext,
6466 .fptosi,
6467 .fptoui,
6468 .fptrunc,
6469 .inttoptr,
6470 .ptrtoint,
6471 .sext,
6472 .sitofp,
6473 .trunc,
6474 .uitofp,
6475 .zext,
6476 => {
6477 const extra = self.extraData(Instruction.Cast, instruction.data);
6478 instruction.data = wip_extra.addExtra(Instruction.Cast{
6479 .val = instructions.map(extra.val),
6480 .type = extra.type,
6481 });
6482 },
6483 .alloca,
6484 .@"alloca inalloca",
6485 => {
6486 const extra = self.extraData(Instruction.Alloca, instruction.data);
6487 instruction.data = wip_extra.addExtra(Instruction.Alloca{
6488 .type = extra.type,
6489 .len = instructions.map(extra.len),
6490 .info = extra.info,
6491 });
6492 },
6493 .arg,
6494 .block,
6495 => unreachable,
6496 .atomicrmw => {
6497 const extra = self.extraData(Instruction.AtomicRmw, instruction.data);
6498 instruction.data = wip_extra.addExtra(Instruction.AtomicRmw{
6499 .info = extra.info,
6500 .ptr = instructions.map(extra.ptr),
6501 .val = instructions.map(extra.val),
6502 });
6503 },
6504 .br,
6505 .fence,
6506 .@"ret void",
6507 .@"unreachable",
6508 => {},
6509 .br_cond => {
6510 const extra = self.extraData(Instruction.BrCond, instruction.data);
6511 instruction.data = wip_extra.addExtra(Instruction.BrCond{
6512 .cond = instructions.map(extra.cond),
6513 .then = extra.then,
6514 .@"else" = extra.@"else",
6515 .weights = extra.weights,
6516 });
6517 },
6518 .call,
6519 .@"call fast",
6520 .@"musttail call",
6521 .@"musttail call fast",
6522 .@"notail call",
6523 .@"notail call fast",
6524 .@"tail call",
6525 .@"tail call fast",
6526 => {
6527 var extra = self.extraDataTrail(Instruction.Call, instruction.data);
6528 const args = extra.trail.next(extra.data.args_len, Value, self);
6529 instruction.data = wip_extra.addExtra(Instruction.Call{
6530 .info = extra.data.info,
6531 .attributes = extra.data.attributes,
6532 .ty = extra.data.ty,
6533 .callee = instructions.map(extra.data.callee),
6534 .args_len = extra.data.args_len,
6535 });
6536 wip_extra.appendMappedValues(args, instructions);
6537 },
6538 .cmpxchg,
6539 .@"cmpxchg weak",
6540 => {
6541 const extra = self.extraData(Instruction.CmpXchg, instruction.data);
6542 instruction.data = wip_extra.addExtra(Instruction.CmpXchg{
6543 .info = extra.info,
6544 .ptr = instructions.map(extra.ptr),
6545 .cmp = instructions.map(extra.cmp),
6546 .new = instructions.map(extra.new),
6547 });
6548 },
6549 .extractelement => {
6550 const extra = self.extraData(Instruction.ExtractElement, instruction.data);
6551 instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
6552 .val = instructions.map(extra.val),
6553 .index = instructions.map(extra.index),
6554 });
6555 },
6556 .extractvalue => {
6557 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
6558 const indices = extra.trail.next(extra.data.indices_len, u32, self);
6559 instruction.data = wip_extra.addExtra(Instruction.ExtractValue{
6560 .val = instructions.map(extra.data.val),
6561 .indices_len = extra.data.indices_len,
6562 });
6563 wip_extra.appendSlice(indices);
6564 },
6565 .fneg,
6566 .@"fneg fast",
6567 .ret,
6568 => instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))),
6569 .getelementptr,
6570 .@"getelementptr inbounds",
6571 => {
6572 var extra = self.extraDataTrail(Instruction.GetElementPtr, instruction.data);
6573 const indices = extra.trail.next(extra.data.indices_len, Value, self);
6574 instruction.data = wip_extra.addExtra(Instruction.GetElementPtr{
6575 .type = extra.data.type,
6576 .base = instructions.map(extra.data.base),
6577 .indices_len = extra.data.indices_len,
6578 });
6579 wip_extra.appendMappedValues(indices, instructions);
6580 },
6581 .indirectbr => {
6582 var extra = self.extraDataTrail(Instruction.IndirectBr, instruction.data);
6583 const targets = extra.trail.next(extra.data.targets_len, Block.Index, self);
6584 instruction.data = wip_extra.addExtra(Instruction.IndirectBr{
6585 .addr = instructions.map(extra.data.addr),
6586 .targets_len = extra.data.targets_len,
6587 });
6588 wip_extra.appendSlice(targets);
6589 },
6590 .insertelement => {
6591 const extra = self.extraData(Instruction.InsertElement, instruction.data);
6592 instruction.data = wip_extra.addExtra(Instruction.InsertElement{
6593 .val = instructions.map(extra.val),
6594 .elem = instructions.map(extra.elem),
6595 .index = instructions.map(extra.index),
6596 });
6597 },
6598 .insertvalue => {
6599 var extra = self.extraDataTrail(Instruction.InsertValue, instruction.data);
6600 const indices = extra.trail.next(extra.data.indices_len, u32, self);
6601 instruction.data = wip_extra.addExtra(Instruction.InsertValue{
6602 .val = instructions.map(extra.data.val),
6603 .elem = instructions.map(extra.data.elem),
6604 .indices_len = extra.data.indices_len,
6605 });
6606 wip_extra.appendSlice(indices);
6607 },
6608 .load,
6609 .@"load atomic",
6610 => {
6611 const extra = self.extraData(Instruction.Load, instruction.data);
6612 instruction.data = wip_extra.addExtra(Instruction.Load{
6613 .type = extra.type,
6614 .ptr = instructions.map(extra.ptr),
6615 .info = extra.info,
6616 });
6617 },
6618 .phi,
6619 .@"phi fast",
6620 => {
6621 const incoming_len = current_block.incoming;
6622 var extra = self.extraDataTrail(Instruction.Phi, instruction.data);
6623 const incoming_vals = extra.trail.next(incoming_len, Value, self);
6624 const incoming_blocks = extra.trail.next(incoming_len, Block.Index, self);
6625 instruction.data = wip_extra.addExtra(Instruction.Phi{
6626 .type = extra.data.type,
6627 });
6628 wip_extra.appendMappedValues(incoming_vals, instructions);
6629 wip_extra.appendSlice(incoming_blocks);
6630 },
6631 .select,
6632 .@"select fast",
6633 => {
6634 const extra = self.extraData(Instruction.Select, instruction.data);
6635 instruction.data = wip_extra.addExtra(Instruction.Select{
6636 .cond = instructions.map(extra.cond),
6637 .lhs = instructions.map(extra.lhs),
6638 .rhs = instructions.map(extra.rhs),
6639 });
6640 },
6641 .shufflevector => {
6642 const extra = self.extraData(Instruction.ShuffleVector, instruction.data);
6643 instruction.data = wip_extra.addExtra(Instruction.ShuffleVector{
6644 .lhs = instructions.map(extra.lhs),
6645 .rhs = instructions.map(extra.rhs),
6646 .mask = instructions.map(extra.mask),
6647 });
6648 },
6649 .store,
6650 .@"store atomic",
6651 => {
6652 const extra = self.extraData(Instruction.Store, instruction.data);
6653 instruction.data = wip_extra.addExtra(Instruction.Store{
6654 .val = instructions.map(extra.val),
6655 .ptr = instructions.map(extra.ptr),
6656 .info = extra.info,
6657 });
6658 },
6659 .@"switch" => {
6660 var extra = self.extraDataTrail(Instruction.Switch, instruction.data);
6661 const case_vals = extra.trail.next(extra.data.cases_len, Constant, self);
6662 const case_blocks = extra.trail.next(extra.data.cases_len, Block.Index, self);
6663 instruction.data = wip_extra.addExtra(Instruction.Switch{
6664 .val = instructions.map(extra.data.val),
6665 .default = extra.data.default,
6666 .cases_len = extra.data.cases_len,
6667 .weights = extra.data.weights,
6668 });
6669 wip_extra.appendSlice(case_vals);
6670 wip_extra.appendSlice(case_blocks);
6671 },
6672 .va_arg => {
6673 const extra = self.extraData(Instruction.VaArg, instruction.data);
6674 instruction.data = wip_extra.addExtra(Instruction.VaArg{
6675 .list = instructions.map(extra.list),
6676 .type = extra.type,
6677 });
6678 },
6679 }
6680 function.instructions.appendAssumeCapacity(instruction);
6681 names[@intFromEnum(new_instruction_index)] = try wip_name.map(if (self.strip)
6682 if (old_instruction_index.hasResultWip(self)) .empty else .none
6683 else
6684 self.names.items[@intFromEnum(old_instruction_index)], ".");
6685
6686 if (self.debug_locations.get(old_instruction_index)) |location| {
6687 debug_locations.putAssumeCapacity(new_instruction_index, location);
6688 }
6689
6690 if (self.debug_values.getIndex(old_instruction_index)) |index| {
6691 debug_values[index] = new_instruction_index;
6692 }
6693
6694 value_indices[@intFromEnum(new_instruction_index)] = value_index;
6695 if (old_instruction_index.hasResultWip(self)) value_index += 1;
6696 }
6697 }
6698
6699 assert(function.instructions.len == final_instructions_len);
6700 function.extra = wip_extra.finish();
6701 function.blocks = blocks;
6702 function.names = names.ptr;
6703 function.value_indices = value_indices.ptr;
6704 function.strip = self.strip;
6705 function.debug_locations = debug_locations;
6706 function.debug_values = debug_values;
6707 }
6708
6709 pub fn deinit(self: *WipFunction) void {
6710 self.extra.deinit(self.builder.gpa);
6711 self.debug_values.deinit(self.builder.gpa);
6712 self.debug_locations.deinit(self.builder.gpa);
6713 self.names.deinit(self.builder.gpa);
6714 self.instructions.deinit(self.builder.gpa);
6715 for (self.blocks.items) |*b| b.instructions.deinit(self.builder.gpa);
6716 self.blocks.deinit(self.builder.gpa);
6717 self.* = undefined;
6718 }
6719
6720 fn cmpTag(
6721 self: *WipFunction,
6722 tag: Instruction.Tag,
6723 lhs: Value,
6724 rhs: Value,
6725 name: []const u8,
6726 ) Allocator.Error!Value {
6727 switch (tag) {
6728 .@"fcmp false",
6729 .@"fcmp fast false",
6730 .@"fcmp fast oeq",
6731 .@"fcmp fast oge",
6732 .@"fcmp fast ogt",
6733 .@"fcmp fast ole",
6734 .@"fcmp fast olt",
6735 .@"fcmp fast one",
6736 .@"fcmp fast ord",
6737 .@"fcmp fast true",
6738 .@"fcmp fast ueq",
6739 .@"fcmp fast uge",
6740 .@"fcmp fast ugt",
6741 .@"fcmp fast ule",
6742 .@"fcmp fast ult",
6743 .@"fcmp fast une",
6744 .@"fcmp fast uno",
6745 .@"fcmp oeq",
6746 .@"fcmp oge",
6747 .@"fcmp ogt",
6748 .@"fcmp ole",
6749 .@"fcmp olt",
6750 .@"fcmp one",
6751 .@"fcmp ord",
6752 .@"fcmp true",
6753 .@"fcmp ueq",
6754 .@"fcmp uge",
6755 .@"fcmp ugt",
6756 .@"fcmp ule",
6757 .@"fcmp ult",
6758 .@"fcmp une",
6759 .@"fcmp uno",
6760 .@"icmp eq",
6761 .@"icmp ne",
6762 .@"icmp sge",
6763 .@"icmp sgt",
6764 .@"icmp sle",
6765 .@"icmp slt",
6766 .@"icmp uge",
6767 .@"icmp ugt",
6768 .@"icmp ule",
6769 .@"icmp ult",
6770 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
6771 else => unreachable,
6772 }
6773 _ = try lhs.typeOfWip(self).changeScalar(.i1, self.builder);
6774 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
6775 const instruction = try self.addInst(name, .{
6776 .tag = tag,
6777 .data = self.addExtraAssumeCapacity(Instruction.Binary{
6778 .lhs = lhs,
6779 .rhs = rhs,
6780 }),
6781 });
6782 return instruction.toValue();
6783 }
6784
6785 fn phiTag(
6786 self: *WipFunction,
6787 tag: Instruction.Tag,
6788 ty: Type,
6789 name: []const u8,
6790 ) Allocator.Error!WipPhi {
6791 switch (tag) {
6792 .phi, .@"phi fast" => assert(try ty.isSized(self.builder)),
6793 else => unreachable,
6794 }
6795 const incoming = self.cursor.block.ptrConst(self).incoming;
6796 assert(incoming > 0);
6797 try self.ensureUnusedExtraCapacity(1, Instruction.Phi, incoming * 2);
6798 const instruction = try self.addInst(name, .{
6799 .tag = tag,
6800 .data = self.addExtraAssumeCapacity(Instruction.Phi{ .type = ty }),
6801 });
6802 _ = self.extra.addManyAsSliceAssumeCapacity(incoming * 2);
6803 return .{ .block = self.cursor.block, .instruction = instruction };
6804 }
6805
6806 fn selectTag(
6807 self: *WipFunction,
6808 tag: Instruction.Tag,
6809 cond: Value,
6810 lhs: Value,
6811 rhs: Value,
6812 name: []const u8,
6813 ) Allocator.Error!Value {
6814 switch (tag) {
6815 .select, .@"select fast" => {
6816 assert(cond.typeOfWip(self).scalarType(self.builder) == .i1);
6817 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
6818 },
6819 else => unreachable,
6820 }
6821 try self.ensureUnusedExtraCapacity(1, Instruction.Select, 0);
6822 const instruction = try self.addInst(name, .{
6823 .tag = tag,
6824 .data = self.addExtraAssumeCapacity(Instruction.Select{
6825 .cond = cond,
6826 .lhs = lhs,
6827 .rhs = rhs,
6828 }),
6829 });
6830 return instruction.toValue();
6831 }
6832
6833 fn ensureUnusedExtraCapacity(
6834 self: *WipFunction,
6835 count: usize,
6836 comptime Extra: type,
6837 trail_len: usize,
6838 ) Allocator.Error!void {
6839 try self.extra.ensureUnusedCapacity(
6840 self.builder.gpa,
6841 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
6842 );
6843 }
6844
6845 fn addInst(
6846 self: *WipFunction,
6847 name: ?[]const u8,
6848 instruction: Instruction,
6849 ) Allocator.Error!Instruction.Index {
6850 const block_instructions = &self.cursor.block.ptr(self).instructions;
6851 try self.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
6852 if (!self.strip) {
6853 try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
6854 try self.debug_locations.ensureUnusedCapacity(self.builder.gpa, 1);
6855 }
6856 try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);
6857 const final_name = if (name) |n|
6858 if (self.strip) .empty else try self.builder.string(n)
6859 else
6860 .none;
6861
6862 const index: Instruction.Index = @enumFromInt(self.instructions.len);
6863 self.instructions.appendAssumeCapacity(instruction);
6864 if (!self.strip) {
6865 self.names.appendAssumeCapacity(final_name);
6866 if (block_instructions.items.len == 0 or
6867 !std.meta.eql(self.debug_location, self.prev_debug_location))
6868 {
6869 self.debug_locations.putAssumeCapacity(index, self.debug_location);
6870 self.prev_debug_location = self.debug_location;
6871 }
6872 }
6873 block_instructions.insertAssumeCapacity(self.cursor.instruction, index);
6874 self.cursor.instruction += 1;
6875 return index;
6876 }
6877
6878 fn addExtraAssumeCapacity(self: *WipFunction, extra: anytype) Instruction.ExtraIndex {
6879 const result: Instruction.ExtraIndex = @intCast(self.extra.items.len);
6880 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
6881 const value = @field(extra, field.name);
6882 self.extra.appendAssumeCapacity(switch (field.type) {
6883 u32 => value,
6884 Alignment,
6885 AtomicOrdering,
6886 Block.Index,
6887 FunctionAttributes,
6888 Type,
6889 Value,
6890 Instruction.BrCond.Weights,
6891 => @intFromEnum(value),
6892 MemoryAccessInfo,
6893 Instruction.Alloca.Info,
6894 Instruction.Call.Info,
6895 => @bitCast(value),
6896 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
6897 });
6898 }
6899 return result;
6900 }
6901
6902 const ExtraDataTrail = struct {
6903 index: Instruction.ExtraIndex,
6904
6905 fn nextMut(self: *ExtraDataTrail, len: u32, comptime Item: type, wip: *WipFunction) []Item {
6906 const items: []Item = @ptrCast(wip.extra.items[self.index..][0..len]);
6907 self.index += @intCast(len);
6908 return items;
6909 }
6910
6911 fn next(
6912 self: *ExtraDataTrail,
6913 len: u32,
6914 comptime Item: type,
6915 wip: *const WipFunction,
6916 ) []const Item {
6917 const items: []const Item = @ptrCast(wip.extra.items[self.index..][0..len]);
6918 self.index += @intCast(len);
6919 return items;
6920 }
6921 };
6922
6923 fn extraDataTrail(
6924 self: *const WipFunction,
6925 comptime T: type,
6926 index: Instruction.ExtraIndex,
6927 ) struct { data: T, trail: ExtraDataTrail } {
6928 var result: T = undefined;
6929 const fields = @typeInfo(T).@"struct".fields;
6930 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
6931 @field(result, field.name) = switch (field.type) {
6932 u32 => value,
6933 Alignment,
6934 AtomicOrdering,
6935 Block.Index,
6936 FunctionAttributes,
6937 Type,
6938 Value,
6939 Instruction.BrCond.Weights,
6940 => @enumFromInt(value),
6941 MemoryAccessInfo,
6942 Instruction.Alloca.Info,
6943 Instruction.Call.Info,
6944 => @bitCast(value),
6945 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
6946 };
6947 return .{
6948 .data = result,
6949 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
6950 };
6951 }
6952
6953 fn extraData(self: *const WipFunction, comptime T: type, index: Instruction.ExtraIndex) T {
6954 return self.extraDataTrail(T, index).data;
6955 }
6956};
6957
6958pub const FloatCondition = enum(u4) {
6959 oeq = 1,
6960 ogt = 2,
6961 oge = 3,
6962 olt = 4,
6963 ole = 5,
6964 one = 6,
6965 ord = 7,
6966 uno = 8,
6967 ueq = 9,
6968 ugt = 10,
6969 uge = 11,
6970 ult = 12,
6971 ule = 13,
6972 une = 14,
6973};
6974
6975pub const IntegerCondition = enum(u6) {
6976 eq = 32,
6977 ne = 33,
6978 ugt = 34,
6979 uge = 35,
6980 ult = 36,
6981 ule = 37,
6982 sgt = 38,
6983 sge = 39,
6984 slt = 40,
6985 sle = 41,
6986};
6987
6988pub const MemoryAccessKind = enum(u1) {
6989 normal,
6990 @"volatile",
6991
6992 pub fn format(
6993 self: MemoryAccessKind,
6994 comptime prefix: []const u8,
6995 _: std.fmt.FormatOptions,
6996 writer: anytype,
6997 ) @TypeOf(writer).Error!void {
6998 if (self != .normal) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
6999 }
7000};
7001
7002pub const SyncScope = enum(u1) {
7003 singlethread,
7004 system,
7005
7006 pub fn format(
7007 self: SyncScope,
7008 comptime prefix: []const u8,
7009 _: std.fmt.FormatOptions,
7010 writer: anytype,
7011 ) @TypeOf(writer).Error!void {
7012 if (self != .system) try writer.print(
7013 \\{s}syncscope("{s}")
7014 , .{ prefix, @tagName(self) });
7015 }
7016};
7017
7018pub const AtomicOrdering = enum(u3) {
7019 none = 0,
7020 unordered = 1,
7021 monotonic = 2,
7022 acquire = 3,
7023 release = 4,
7024 acq_rel = 5,
7025 seq_cst = 6,
7026
7027 pub fn format(
7028 self: AtomicOrdering,
7029 comptime prefix: []const u8,
7030 _: std.fmt.FormatOptions,
7031 writer: anytype,
7032 ) @TypeOf(writer).Error!void {
7033 if (self != .none) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
7034 }
7035};
7036
7037const MemoryAccessInfo = packed struct(u32) {
7038 access_kind: MemoryAccessKind = .normal,
7039 atomic_rmw_operation: Function.Instruction.AtomicRmw.Operation = .none,
7040 sync_scope: SyncScope,
7041 success_ordering: AtomicOrdering,
7042 failure_ordering: AtomicOrdering = .none,
7043 alignment: Alignment = .default,
7044 _: u13 = undefined,
7045};
7046
7047pub const FastMath = packed struct(u8) {
7048 unsafe_algebra: bool = false, // Legacy
7049 nnan: bool = false,
7050 ninf: bool = false,
7051 nsz: bool = false,
7052 arcp: bool = false,
7053 contract: bool = false,
7054 afn: bool = false,
7055 reassoc: bool = false,
7056
7057 pub const fast = FastMath{
7058 .nnan = true,
7059 .ninf = true,
7060 .nsz = true,
7061 .arcp = true,
7062 .contract = true,
7063 .afn = true,
7064 .reassoc = true,
7065 };
7066};
7067
7068pub const FastMathKind = enum {
7069 normal,
7070 fast,
7071
7072 pub fn toCallKind(self: FastMathKind) Function.Instruction.Call.Kind {
7073 return switch (self) {
7074 .normal => .normal,
7075 .fast => .fast,
7076 };
7077 }
7078};
7079
7080pub const Constant = enum(u32) {
7081 false,
7082 true,
7083 @"0",
7084 @"1",
7085 none,
7086 no_init = (1 << 30) - 1,
7087 _,
7088
7089 const first_global: Constant = @enumFromInt(1 << 29);
7090
7091 pub const Tag = enum(u7) {
7092 positive_integer,
7093 negative_integer,
7094 half,
7095 bfloat,
7096 float,
7097 double,
7098 fp128,
7099 x86_fp80,
7100 ppc_fp128,
7101 null,
7102 none,
7103 structure,
7104 packed_structure,
7105 array,
7106 string,
7107 vector,
7108 splat,
7109 zeroinitializer,
7110 undef,
7111 poison,
7112 blockaddress,
7113 dso_local_equivalent,
7114 no_cfi,
7115 trunc,
7116 ptrtoint,
7117 inttoptr,
7118 bitcast,
7119 addrspacecast,
7120 getelementptr,
7121 @"getelementptr inbounds",
7122 add,
7123 @"add nsw",
7124 @"add nuw",
7125 sub,
7126 @"sub nsw",
7127 @"sub nuw",
7128 shl,
7129 xor,
7130 @"asm",
7131 @"asm sideeffect",
7132 @"asm alignstack",
7133 @"asm sideeffect alignstack",
7134 @"asm inteldialect",
7135 @"asm sideeffect inteldialect",
7136 @"asm alignstack inteldialect",
7137 @"asm sideeffect alignstack inteldialect",
7138 @"asm unwind",
7139 @"asm sideeffect unwind",
7140 @"asm alignstack unwind",
7141 @"asm sideeffect alignstack unwind",
7142 @"asm inteldialect unwind",
7143 @"asm sideeffect inteldialect unwind",
7144 @"asm alignstack inteldialect unwind",
7145 @"asm sideeffect alignstack inteldialect unwind",
7146
7147 pub fn toBinaryOpcode(self: Tag) BinaryOpcode {
7148 return switch (self) {
7149 .add,
7150 .@"add nsw",
7151 .@"add nuw",
7152 => .add,
7153 .sub,
7154 .@"sub nsw",
7155 .@"sub nuw",
7156 => .sub,
7157 .shl => .shl,
7158 .xor => .xor,
7159 else => unreachable,
7160 };
7161 }
7162
7163 pub fn toCastOpcode(self: Tag) CastOpcode {
7164 return switch (self) {
7165 .trunc => .trunc,
7166 .ptrtoint => .ptrtoint,
7167 .inttoptr => .inttoptr,
7168 .bitcast => .bitcast,
7169 .addrspacecast => .addrspacecast,
7170 else => unreachable,
7171 };
7172 }
7173 };
7174
7175 pub const Item = struct {
7176 tag: Tag,
7177 data: ExtraIndex,
7178
7179 const ExtraIndex = u32;
7180 };
7181
7182 pub const Integer = packed struct(u64) {
7183 type: Type,
7184 limbs_len: u32,
7185
7186 pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
7187 };
7188
7189 pub const Double = struct {
7190 lo: u32,
7191 hi: u32,
7192 };
7193
7194 pub const Fp80 = struct {
7195 lo_lo: u32,
7196 lo_hi: u32,
7197 hi: u32,
7198 };
7199
7200 pub const Fp128 = struct {
7201 lo_lo: u32,
7202 lo_hi: u32,
7203 hi_lo: u32,
7204 hi_hi: u32,
7205 };
7206
7207 pub const Aggregate = struct {
7208 type: Type,
7209 //fields: [type.aggregateLen(builder)]Constant,
7210 };
7211
7212 pub const Splat = extern struct {
7213 type: Type,
7214 value: Constant,
7215 };
7216
7217 pub const BlockAddress = extern struct {
7218 function: Function.Index,
7219 block: Function.Block.Index,
7220 };
7221
7222 pub const Cast = extern struct {
7223 val: Constant,
7224 type: Type,
7225
7226 pub const Signedness = enum { unsigned, signed, unneeded };
7227 };
7228
7229 pub const GetElementPtr = struct {
7230 type: Type,
7231 base: Constant,
7232 info: Info,
7233 //indices: [info.indices_len]Constant,
7234
7235 pub const Kind = enum { normal, inbounds };
7236 pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };
7237 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
7238 };
7239
7240 pub const Binary = extern struct {
7241 lhs: Constant,
7242 rhs: Constant,
7243 };
7244
7245 pub const Assembly = extern struct {
7246 type: Type,
7247 assembly: String,
7248 constraints: String,
7249
7250 pub const Info = packed struct {
7251 sideeffect: bool = false,
7252 alignstack: bool = false,
7253 inteldialect: bool = false,
7254 unwind: bool = false,
7255 };
7256 };
7257
7258 pub fn unwrap(self: Constant) union(enum) {
7259 constant: u30,
7260 global: Global.Index,
7261 } {
7262 return if (@intFromEnum(self) < @intFromEnum(first_global))
7263 .{ .constant = @intCast(@intFromEnum(self)) }
7264 else
7265 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
7266 }
7267
7268 pub fn toValue(self: Constant) Value {
7269 return @enumFromInt(Value.first_constant + @intFromEnum(self));
7270 }
7271
7272 pub fn typeOf(self: Constant, builder: *Builder) Type {
7273 switch (self.unwrap()) {
7274 .constant => |constant| {
7275 const item = builder.constant_items.get(constant);
7276 return switch (item.tag) {
7277 .positive_integer,
7278 .negative_integer,
7279 => @as(
7280 *align(@alignOf(std.math.big.Limb)) Integer,
7281 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
7282 ).type,
7283 .half => .half,
7284 .bfloat => .bfloat,
7285 .float => .float,
7286 .double => .double,
7287 .fp128 => .fp128,
7288 .x86_fp80 => .x86_fp80,
7289 .ppc_fp128 => .ppc_fp128,
7290 .null,
7291 .none,
7292 .zeroinitializer,
7293 .undef,
7294 .poison,
7295 => @enumFromInt(item.data),
7296 .structure,
7297 .packed_structure,
7298 .array,
7299 .vector,
7300 => builder.constantExtraData(Aggregate, item.data).type,
7301 .splat => builder.constantExtraData(Splat, item.data).type,
7302 .string => builder.arrayTypeAssumeCapacity(
7303 @as(String, @enumFromInt(item.data)).slice(builder).?.len,
7304 .i8,
7305 ),
7306 .blockaddress => builder.ptrTypeAssumeCapacity(
7307 builder.constantExtraData(BlockAddress, item.data)
7308 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
7309 ),
7310 .dso_local_equivalent,
7311 .no_cfi,
7312 => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
7313 .ptrConst(builder).global.ptrConst(builder).addr_space),
7314 .trunc,
7315 .ptrtoint,
7316 .inttoptr,
7317 .bitcast,
7318 .addrspacecast,
7319 => builder.constantExtraData(Cast, item.data).type,
7320 .getelementptr,
7321 .@"getelementptr inbounds",
7322 => {
7323 var extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
7324 const indices =
7325 extra.trail.next(extra.data.info.indices_len, Constant, builder);
7326 const base_ty = extra.data.base.typeOf(builder);
7327 if (!base_ty.isVector(builder)) for (indices) |index| {
7328 const index_ty = index.typeOf(builder);
7329 if (!index_ty.isVector(builder)) continue;
7330 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
7331 };
7332 return base_ty;
7333 },
7334 .add,
7335 .@"add nsw",
7336 .@"add nuw",
7337 .sub,
7338 .@"sub nsw",
7339 .@"sub nuw",
7340 .shl,
7341 .xor,
7342 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
7343 .@"asm",
7344 .@"asm sideeffect",
7345 .@"asm alignstack",
7346 .@"asm sideeffect alignstack",
7347 .@"asm inteldialect",
7348 .@"asm sideeffect inteldialect",
7349 .@"asm alignstack inteldialect",
7350 .@"asm sideeffect alignstack inteldialect",
7351 .@"asm unwind",
7352 .@"asm sideeffect unwind",
7353 .@"asm alignstack unwind",
7354 .@"asm sideeffect alignstack unwind",
7355 .@"asm inteldialect unwind",
7356 .@"asm sideeffect inteldialect unwind",
7357 .@"asm alignstack inteldialect unwind",
7358 .@"asm sideeffect alignstack inteldialect unwind",
7359 => .ptr,
7360 };
7361 },
7362 .global => |global| return builder.ptrTypeAssumeCapacity(
7363 global.ptrConst(builder).addr_space,
7364 ),
7365 }
7366 }
7367
7368 pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
7369 switch (self.unwrap()) {
7370 .constant => |constant| {
7371 const item = builder.constant_items.get(constant);
7372 return switch (item.tag) {
7373 .positive_integer => {
7374 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
7375 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
7376 const limbs = builder.constant_limbs
7377 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
7378 return std.mem.eql(std.math.big.Limb, limbs, &.{0});
7379 },
7380 .half, .bfloat, .float => item.data == 0,
7381 .double => {
7382 const extra = builder.constantExtraData(Constant.Double, item.data);
7383 return extra.lo == 0 and extra.hi == 0;
7384 },
7385 .fp128, .ppc_fp128 => {
7386 const extra = builder.constantExtraData(Constant.Fp128, item.data);
7387 return extra.lo_lo == 0 and extra.lo_hi == 0 and
7388 extra.hi_lo == 0 and extra.hi_hi == 0;
7389 },
7390 .x86_fp80 => {
7391 const extra = builder.constantExtraData(Constant.Fp80, item.data);
7392 return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
7393 },
7394 .vector => {
7395 var extra = builder.constantExtraDataTrail(Aggregate, item.data);
7396 const len: u32 = @intCast(extra.data.type.aggregateLen(builder));
7397 const vals = extra.trail.next(len, Constant, builder);
7398 for (vals) |val| if (!val.isZeroInit(builder)) return false;
7399 return true;
7400 },
7401 .null, .zeroinitializer => true,
7402 else => false,
7403 };
7404 },
7405 .global => return false,
7406 }
7407 }
7408
7409 pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
7410 var cur = self;
7411 while (true) switch (cur.unwrap()) {
7412 .constant => |constant| {
7413 const item = builder.constant_items.get(constant);
7414 switch (item.tag) {
7415 .ptrtoint,
7416 .inttoptr,
7417 .bitcast,
7418 => cur = builder.constantExtraData(Cast, item.data).val,
7419 .getelementptr => cur = builder.constantExtraData(GetElementPtr, item.data).base,
7420 .add => {
7421 const extra = builder.constantExtraData(Binary, item.data);
7422 const lhs_base = extra.lhs.getBase(builder);
7423 const rhs_base = extra.rhs.getBase(builder);
7424 return if (lhs_base != .none and rhs_base != .none)
7425 .none
7426 else if (lhs_base != .none) lhs_base else rhs_base;
7427 },
7428 .sub => {
7429 const extra = builder.constantExtraData(Binary, item.data);
7430 if (extra.rhs.getBase(builder) != .none) return .none;
7431 cur = extra.lhs;
7432 },
7433 else => return .none,
7434 }
7435 },
7436 .global => |global| switch (global.ptrConst(builder).kind) {
7437 .alias => |alias| cur = alias.ptrConst(builder).aliasee,
7438 .variable, .function => return global,
7439 .replaced => unreachable,
7440 },
7441 };
7442 }
7443
7444 const FormatData = struct {
7445 constant: Constant,
7446 builder: *Builder,
7447 };
7448 fn format(
7449 data: FormatData,
7450 comptime fmt_str: []const u8,
7451 _: std.fmt.FormatOptions,
7452 writer: anytype,
7453 ) @TypeOf(writer).Error!void {
7454 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
7455 @compileError("invalid format string: '" ++ fmt_str ++ "'");
7456 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
7457 if (data.constant == .no_init) return;
7458 try writer.writeByte(',');
7459 }
7460 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
7461 if (data.constant == .no_init) return;
7462 try writer.writeByte(' ');
7463 }
7464 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
7465 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
7466 assert(data.constant != .no_init);
7467 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
7468 switch (data.constant.unwrap()) {
7469 .constant => |constant| {
7470 const item = data.builder.constant_items.get(constant);
7471 switch (item.tag) {
7472 .positive_integer,
7473 .negative_integer,
7474 => |tag| {
7475 const extra: *align(@alignOf(std.math.big.Limb)) const Integer =
7476 @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
7477 const limbs = data.builder.constant_limbs
7478 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
7479 const bigint: std.math.big.int.Const = .{
7480 .limbs = limbs,
7481 .positive = switch (tag) {
7482 .positive_integer => true,
7483 .negative_integer => false,
7484 else => unreachable,
7485 },
7486 };
7487 const ExpectedContents = extern struct {
7488 const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
7489 string: [
7490 (std.math.big.int.Const{
7491 .limbs = &([1]std.math.big.Limb{
7492 std.math.maxInt(std.math.big.Limb),
7493 } ** expected_limbs),
7494 .positive = false,
7495 }).sizeInBaseUpperBound(10)
7496 ]u8,
7497 limbs: [
7498 std.math.big.int.calcToStringLimbsBufferLen(expected_limbs, 10)
7499 ]std.math.big.Limb,
7500 };
7501 var stack align(@alignOf(ExpectedContents)) =
7502 std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
7503 const allocator = stack.get();
7504 const str = try bigint.toStringAlloc(allocator, 10, undefined);
7505 defer allocator.free(str);
7506 try writer.writeAll(str);
7507 },
7508 .half,
7509 .bfloat,
7510 => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
7511 .half => 'H',
7512 .bfloat => 'R',
7513 else => unreachable,
7514 }), item.data >> switch (tag) {
7515 .half => 0,
7516 .bfloat => 16,
7517 else => unreachable,
7518 } }),
7519 .float => {
7520 const Float = struct {
7521 fn Repr(comptime T: type) type {
7522 return packed struct(std.meta.Int(.unsigned, @bitSizeOf(T))) {
7523 mantissa: std.meta.Int(.unsigned, std.math.floatMantissaBits(T)),
7524 exponent: std.meta.Int(.unsigned, std.math.floatExponentBits(T)),
7525 sign: u1,
7526 };
7527 }
7528 };
7529 const Mantissa64 = std.meta.FieldType(Float.Repr(f64), .mantissa);
7530 const Exponent32 = std.meta.FieldType(Float.Repr(f32), .exponent);
7531 const Exponent64 = std.meta.FieldType(Float.Repr(f64), .exponent);
7532
7533 const repr: Float.Repr(f32) = @bitCast(item.data);
7534 const denormal_shift = switch (repr.exponent) {
7535 std.math.minInt(Exponent32) => @as(
7536 std.math.Log2Int(Mantissa64),
7537 @clz(repr.mantissa),
7538 ) + 1,
7539 else => 0,
7540 };
7541 try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){
7542 .mantissa = std.math.shl(
7543 Mantissa64,
7544 repr.mantissa,
7545 std.math.floatMantissaBits(f64) - std.math.floatMantissaBits(f32) +
7546 denormal_shift,
7547 ),
7548 .exponent = switch (repr.exponent) {
7549 std.math.minInt(Exponent32) => if (repr.mantissa > 0)
7550 @as(Exponent64, std.math.floatExponentMin(f32) +
7551 std.math.floatExponentMax(f64)) - denormal_shift
7552 else
7553 std.math.minInt(Exponent64),
7554 else => @as(Exponent64, repr.exponent) +
7555 (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
7556 std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),
7557 },
7558 .sign = repr.sign,
7559 }))});
7560 },
7561 .double => {
7562 const extra = data.builder.constantExtraData(Double, item.data);
7563 try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
7564 },
7565 .fp128,
7566 .ppc_fp128,
7567 => |tag| {
7568 const extra = data.builder.constantExtraData(Fp128, item.data);
7569 try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
7570 @as(u8, switch (tag) {
7571 .fp128 => 'L',
7572 .ppc_fp128 => 'M',
7573 else => unreachable,
7574 }),
7575 extra.lo_hi,
7576 extra.lo_lo,
7577 extra.hi_hi,
7578 extra.hi_lo,
7579 });
7580 },
7581 .x86_fp80 => {
7582 const extra = data.builder.constantExtraData(Fp80, item.data);
7583 try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
7584 extra.hi, extra.lo_hi, extra.lo_lo,
7585 });
7586 },
7587 .null,
7588 .none,
7589 .zeroinitializer,
7590 .undef,
7591 .poison,
7592 => |tag| try writer.writeAll(@tagName(tag)),
7593 .structure,
7594 .packed_structure,
7595 .array,
7596 .vector,
7597 => |tag| {
7598 var extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
7599 const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder));
7600 const vals = extra.trail.next(len, Constant, data.builder);
7601 try writer.writeAll(switch (tag) {
7602 .structure => "{ ",
7603 .packed_structure => "<{ ",
7604 .array => "[",
7605 .vector => "<",
7606 else => unreachable,
7607 });
7608 for (vals, 0..) |val, index| {
7609 if (index > 0) try writer.writeAll(", ");
7610 try writer.print("{%}", .{val.fmt(data.builder)});
7611 }
7612 try writer.writeAll(switch (tag) {
7613 .structure => " }",
7614 .packed_structure => " }>",
7615 .array => "]",
7616 .vector => ">",
7617 else => unreachable,
7618 });
7619 },
7620 .splat => {
7621 const extra = data.builder.constantExtraData(Splat, item.data);
7622 const len = extra.type.vectorLen(data.builder);
7623 try writer.writeByte('<');
7624 for (0..len) |index| {
7625 if (index > 0) try writer.writeAll(", ");
7626 try writer.print("{%}", .{extra.value.fmt(data.builder)});
7627 }
7628 try writer.writeByte('>');
7629 },
7630 .string => try writer.print("c{\"}", .{
7631 @as(String, @enumFromInt(item.data)).fmt(data.builder),
7632 }),
7633 .blockaddress => |tag| {
7634 const extra = data.builder.constantExtraData(BlockAddress, item.data);
7635 const function = extra.function.ptrConst(data.builder);
7636 try writer.print("{s}({}, {})", .{
7637 @tagName(tag),
7638 function.global.fmt(data.builder),
7639 extra.block.toInst(function).fmt(extra.function, data.builder),
7640 });
7641 },
7642 .dso_local_equivalent,
7643 .no_cfi,
7644 => |tag| {
7645 const function: Function.Index = @enumFromInt(item.data);
7646 try writer.print("{s} {}", .{
7647 @tagName(tag),
7648 function.ptrConst(data.builder).global.fmt(data.builder),
7649 });
7650 },
7651 .trunc,
7652 .ptrtoint,
7653 .inttoptr,
7654 .bitcast,
7655 .addrspacecast,
7656 => |tag| {
7657 const extra = data.builder.constantExtraData(Cast, item.data);
7658 try writer.print("{s} ({%} to {%})", .{
7659 @tagName(tag),
7660 extra.val.fmt(data.builder),
7661 extra.type.fmt(data.builder),
7662 });
7663 },
7664 .getelementptr,
7665 .@"getelementptr inbounds",
7666 => |tag| {
7667 var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
7668 const indices =
7669 extra.trail.next(extra.data.info.indices_len, Constant, data.builder);
7670 try writer.print("{s} ({%}, {%}", .{
7671 @tagName(tag),
7672 extra.data.type.fmt(data.builder),
7673 extra.data.base.fmt(data.builder),
7674 });
7675 for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
7676 try writer.writeByte(')');
7677 },
7678 .add,
7679 .@"add nsw",
7680 .@"add nuw",
7681 .sub,
7682 .@"sub nsw",
7683 .@"sub nuw",
7684 .shl,
7685 .xor,
7686 => |tag| {
7687 const extra = data.builder.constantExtraData(Binary, item.data);
7688 try writer.print("{s} ({%}, {%})", .{
7689 @tagName(tag),
7690 extra.lhs.fmt(data.builder),
7691 extra.rhs.fmt(data.builder),
7692 });
7693 },
7694 .@"asm",
7695 .@"asm sideeffect",
7696 .@"asm alignstack",
7697 .@"asm sideeffect alignstack",
7698 .@"asm inteldialect",
7699 .@"asm sideeffect inteldialect",
7700 .@"asm alignstack inteldialect",
7701 .@"asm sideeffect alignstack inteldialect",
7702 .@"asm unwind",
7703 .@"asm sideeffect unwind",
7704 .@"asm alignstack unwind",
7705 .@"asm sideeffect alignstack unwind",
7706 .@"asm inteldialect unwind",
7707 .@"asm sideeffect inteldialect unwind",
7708 .@"asm alignstack inteldialect unwind",
7709 .@"asm sideeffect alignstack inteldialect unwind",
7710 => |tag| {
7711 const extra = data.builder.constantExtraData(Assembly, item.data);
7712 try writer.print("{s} {\"}, {\"}", .{
7713 @tagName(tag),
7714 extra.assembly.fmt(data.builder),
7715 extra.constraints.fmt(data.builder),
7716 });
7717 },
7718 }
7719 },
7720 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
7721 }
7722 }
7723 pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
7724 return .{ .data = .{ .constant = self, .builder = builder } };
7725 }
7726};
7727
7728pub const Value = enum(u32) {
7729 none = std.math.maxInt(u31),
7730 false = first_constant + @intFromEnum(Constant.false),
7731 true = first_constant + @intFromEnum(Constant.true),
7732 @"0" = first_constant + @intFromEnum(Constant.@"0"),
7733 @"1" = first_constant + @intFromEnum(Constant.@"1"),
7734 _,
7735
7736 const first_constant = 1 << 30;
7737 const first_metadata = 1 << 31;
7738
7739 pub fn unwrap(self: Value) union(enum) {
7740 instruction: Function.Instruction.Index,
7741 constant: Constant,
7742 metadata: Metadata,
7743 } {
7744 return if (@intFromEnum(self) < first_constant)
7745 .{ .instruction = @enumFromInt(@intFromEnum(self)) }
7746 else if (@intFromEnum(self) < first_metadata)
7747 .{ .constant = @enumFromInt(@intFromEnum(self) - first_constant) }
7748 else
7749 .{ .metadata = @enumFromInt(@intFromEnum(self) - first_metadata) };
7750 }
7751
7752 pub fn typeOfWip(self: Value, wip: *const WipFunction) Type {
7753 return switch (self.unwrap()) {
7754 .instruction => |instruction| instruction.typeOfWip(wip),
7755 .constant => |constant| constant.typeOf(wip.builder),
7756 .metadata => .metadata,
7757 };
7758 }
7759
7760 pub fn typeOf(self: Value, function: Function.Index, builder: *Builder) Type {
7761 return switch (self.unwrap()) {
7762 .instruction => |instruction| instruction.typeOf(function, builder),
7763 .constant => |constant| constant.typeOf(builder),
7764 .metadata => .metadata,
7765 };
7766 }
7767
7768 pub fn toConst(self: Value) ?Constant {
7769 return switch (self.unwrap()) {
7770 .instruction, .metadata => null,
7771 .constant => |constant| constant,
7772 };
7773 }
7774
7775 const FormatData = struct {
7776 value: Value,
7777 function: Function.Index,
7778 builder: *Builder,
7779 };
7780 fn format(
7781 data: FormatData,
7782 comptime fmt_str: []const u8,
7783 fmt_opts: std.fmt.FormatOptions,
7784 writer: anytype,
7785 ) @TypeOf(writer).Error!void {
7786 switch (data.value.unwrap()) {
7787 .instruction => |instruction| try Function.Instruction.Index.format(.{
7788 .instruction = instruction,
7789 .function = data.function,
7790 .builder = data.builder,
7791 }, fmt_str, fmt_opts, writer),
7792 .constant => |constant| try Constant.format(.{
7793 .constant = constant,
7794 .builder = data.builder,
7795 }, fmt_str, fmt_opts, writer),
7796 .metadata => unreachable,
7797 }
7798 }
7799 pub fn fmt(self: Value, function: Function.Index, builder: *Builder) std.fmt.Formatter(format) {
7800 return .{ .data = .{ .value = self, .function = function, .builder = builder } };
7801 }
7802};
7803
7804pub const MetadataString = enum(u32) {
7805 none = 0,
7806 _,
7807
7808 pub fn slice(self: MetadataString, builder: *const Builder) []const u8 {
7809 const index = @intFromEnum(self);
7810 const start = builder.metadata_string_indices.items[index];
7811 const end = builder.metadata_string_indices.items[index + 1];
7812 return builder.metadata_string_bytes.items[start..end];
7813 }
7814
7815 const Adapter = struct {
7816 builder: *const Builder,
7817 pub fn hash(_: Adapter, key: []const u8) u32 {
7818 return @truncate(std.hash.Wyhash.hash(0, key));
7819 }
7820 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
7821 const rhs_metadata_string: MetadataString = @enumFromInt(rhs_index);
7822 return std.mem.eql(u8, lhs_key, rhs_metadata_string.slice(ctx.builder));
7823 }
7824 };
7825
7826 const FormatData = struct {
7827 metadata_string: MetadataString,
7828 builder: *const Builder,
7829 };
7830 fn format(
7831 data: FormatData,
7832 comptime _: []const u8,
7833 _: std.fmt.FormatOptions,
7834 writer: anytype,
7835 ) @TypeOf(writer).Error!void {
7836 try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, writer);
7837 }
7838 fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(format) {
7839 return .{ .data = .{ .metadata_string = self, .builder = builder } };
7840 }
7841};
7842
7843pub const Metadata = enum(u32) {
7844 none = 0,
7845 empty_tuple = 1,
7846 _,
7847
7848 const first_forward_reference = 1 << 29;
7849 const first_local_metadata = 1 << 30;
7850
7851 pub const Tag = enum(u6) {
7852 none,
7853 file,
7854 compile_unit,
7855 @"compile_unit optimized",
7856 subprogram,
7857 @"subprogram local",
7858 @"subprogram definition",
7859 @"subprogram local definition",
7860 @"subprogram optimized",
7861 @"subprogram optimized local",
7862 @"subprogram optimized definition",
7863 @"subprogram optimized local definition",
7864 lexical_block,
7865 location,
7866 basic_bool_type,
7867 basic_unsigned_type,
7868 basic_signed_type,
7869 basic_float_type,
7870 composite_struct_type,
7871 composite_union_type,
7872 composite_enumeration_type,
7873 composite_array_type,
7874 composite_vector_type,
7875 derived_pointer_type,
7876 derived_member_type,
7877 subroutine_type,
7878 enumerator_unsigned,
7879 enumerator_signed_positive,
7880 enumerator_signed_negative,
7881 subrange,
7882 tuple,
7883 str_tuple,
7884 module_flag,
7885 expression,
7886 local_var,
7887 parameter,
7888 global_var,
7889 @"global_var local",
7890 global_var_expression,
7891 constant,
7892
7893 pub fn isInline(tag: Tag) bool {
7894 return switch (tag) {
7895 .none,
7896 .expression,
7897 .constant,
7898 => true,
7899 .file,
7900 .compile_unit,
7901 .@"compile_unit optimized",
7902 .subprogram,
7903 .@"subprogram local",
7904 .@"subprogram definition",
7905 .@"subprogram local definition",
7906 .@"subprogram optimized",
7907 .@"subprogram optimized local",
7908 .@"subprogram optimized definition",
7909 .@"subprogram optimized local definition",
7910 .lexical_block,
7911 .location,
7912 .basic_bool_type,
7913 .basic_unsigned_type,
7914 .basic_signed_type,
7915 .basic_float_type,
7916 .composite_struct_type,
7917 .composite_union_type,
7918 .composite_enumeration_type,
7919 .composite_array_type,
7920 .composite_vector_type,
7921 .derived_pointer_type,
7922 .derived_member_type,
7923 .subroutine_type,
7924 .enumerator_unsigned,
7925 .enumerator_signed_positive,
7926 .enumerator_signed_negative,
7927 .subrange,
7928 .tuple,
7929 .str_tuple,
7930 .module_flag,
7931 .local_var,
7932 .parameter,
7933 .global_var,
7934 .@"global_var local",
7935 .global_var_expression,
7936 => false,
7937 };
7938 }
7939 };
7940
7941 pub fn isInline(self: Metadata, builder: *const Builder) bool {
7942 return builder.metadata_items.items(.tag)[@intFromEnum(self)].isInline();
7943 }
7944
7945 pub fn unwrap(self: Metadata, builder: *const Builder) Metadata {
7946 var metadata = self;
7947 while (@intFromEnum(metadata) >= Metadata.first_forward_reference and
7948 @intFromEnum(metadata) < Metadata.first_local_metadata)
7949 {
7950 const index = @intFromEnum(metadata) - Metadata.first_forward_reference;
7951 metadata = builder.metadata_forward_references.items[index];
7952 assert(metadata != .none);
7953 }
7954 return metadata;
7955 }
7956
7957 pub const Item = struct {
7958 tag: Tag,
7959 data: ExtraIndex,
7960
7961 const ExtraIndex = u32;
7962 };
7963
7964 pub const DIFlags = packed struct(u32) {
7965 Visibility: enum(u2) { Zero, Private, Protected, Public } = .Zero,
7966 FwdDecl: bool = false,
7967 AppleBlock: bool = false,
7968 ReservedBit4: u1 = 0,
7969 Virtual: bool = false,
7970 Artificial: bool = false,
7971 Explicit: bool = false,
7972 Prototyped: bool = false,
7973 ObjcClassComplete: bool = false,
7974 ObjectPointer: bool = false,
7975 Vector: bool = false,
7976 StaticMember: bool = false,
7977 LValueReference: bool = false,
7978 RValueReference: bool = false,
7979 ExportSymbols: bool = false,
7980 Inheritance: enum(u2) {
7981 Zero,
7982 SingleInheritance,
7983 MultipleInheritance,
7984 VirtualInheritance,
7985 } = .Zero,
7986 IntroducedVirtual: bool = false,
7987 BitField: bool = false,
7988 NoReturn: bool = false,
7989 ReservedBit21: u1 = 0,
7990 TypePassbyValue: bool = false,
7991 TypePassbyReference: bool = false,
7992 EnumClass: bool = false,
7993 Thunk: bool = false,
7994 NonTrivial: bool = false,
7995 BigEndian: bool = false,
7996 LittleEndian: bool = false,
7997 AllCallsDescribed: bool = false,
7998 Unused: u2 = 0,
7999
8000 pub fn format(
8001 self: DIFlags,
8002 comptime _: []const u8,
8003 _: std.fmt.FormatOptions,
8004 writer: anytype,
8005 ) @TypeOf(writer).Error!void {
8006 var need_pipe = false;
8007 inline for (@typeInfo(DIFlags).@"struct".fields) |field| {
8008 switch (@typeInfo(field.type)) {
8009 .bool => if (@field(self, field.name)) {
8010 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8011 try writer.print("DIFlag{s}", .{field.name});
8012 },
8013 .@"enum" => if (@field(self, field.name) != .Zero) {
8014 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8015 try writer.print("DIFlag{s}", .{@tagName(@field(self, field.name))});
8016 },
8017 .int => assert(@field(self, field.name) == 0),
8018 else => @compileError("bad field type: " ++ field.name ++ ": " ++
8019 @typeName(field.type)),
8020 }
8021 }
8022 if (!need_pipe) try writer.writeByte('0');
8023 }
8024 };
8025
8026 pub const File = struct {
8027 filename: MetadataString,
8028 directory: MetadataString,
8029 };
8030
8031 pub const CompileUnit = struct {
8032 pub const Options = struct {
8033 optimized: bool,
8034 };
8035
8036 file: Metadata,
8037 producer: MetadataString,
8038 enums: Metadata,
8039 globals: Metadata,
8040 };
8041
8042 pub const Subprogram = struct {
8043 pub const Options = struct {
8044 di_flags: DIFlags,
8045 sp_flags: DISPFlags,
8046 };
8047
8048 pub const DISPFlags = packed struct(u32) {
8049 Virtuality: enum(u2) { Zero, Virtual, PureVirtual } = .Zero,
8050 LocalToUnit: bool = false,
8051 Definition: bool = false,
8052 Optimized: bool = false,
8053 Pure: bool = false,
8054 Elemental: bool = false,
8055 Recursive: bool = false,
8056 MainSubprogram: bool = false,
8057 Deleted: bool = false,
8058 ReservedBit10: u1 = 0,
8059 ObjCDirect: bool = false,
8060 Unused: u20 = 0,
8061
8062 pub fn format(
8063 self: DISPFlags,
8064 comptime _: []const u8,
8065 _: std.fmt.FormatOptions,
8066 writer: anytype,
8067 ) @TypeOf(writer).Error!void {
8068 var need_pipe = false;
8069 inline for (@typeInfo(DISPFlags).@"struct".fields) |field| {
8070 switch (@typeInfo(field.type)) {
8071 .bool => if (@field(self, field.name)) {
8072 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8073 try writer.print("DISPFlag{s}", .{field.name});
8074 },
8075 .@"enum" => if (@field(self, field.name) != .Zero) {
8076 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8077 try writer.print("DISPFlag{s}", .{@tagName(@field(self, field.name))});
8078 },
8079 .int => assert(@field(self, field.name) == 0),
8080 else => @compileError("bad field type: " ++ field.name ++ ": " ++
8081 @typeName(field.type)),
8082 }
8083 }
8084 if (!need_pipe) try writer.writeByte('0');
8085 }
8086 };
8087
8088 file: Metadata,
8089 name: MetadataString,
8090 linkage_name: MetadataString,
8091 line: u32,
8092 scope_line: u32,
8093 ty: Metadata,
8094 di_flags: DIFlags,
8095 compile_unit: Metadata,
8096 };
8097
8098 pub const LexicalBlock = struct {
8099 scope: Metadata,
8100 file: Metadata,
8101 line: u32,
8102 column: u32,
8103 };
8104
8105 pub const Location = struct {
8106 line: u32,
8107 column: u32,
8108 scope: Metadata,
8109 inlined_at: Metadata,
8110 };
8111
8112 pub const BasicType = struct {
8113 name: MetadataString,
8114 size_in_bits_lo: u32,
8115 size_in_bits_hi: u32,
8116
8117 pub fn bitSize(self: BasicType) u64 {
8118 return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
8119 }
8120 };
8121
8122 pub const CompositeType = struct {
8123 name: MetadataString,
8124 file: Metadata,
8125 scope: Metadata,
8126 line: u32,
8127 underlying_type: Metadata,
8128 size_in_bits_lo: u32,
8129 size_in_bits_hi: u32,
8130 align_in_bits_lo: u32,
8131 align_in_bits_hi: u32,
8132 fields_tuple: Metadata,
8133
8134 pub fn bitSize(self: CompositeType) u64 {
8135 return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
8136 }
8137 pub fn bitAlign(self: CompositeType) u64 {
8138 return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo;
8139 }
8140 };
8141
8142 pub const DerivedType = struct {
8143 name: MetadataString,
8144 file: Metadata,
8145 scope: Metadata,
8146 line: u32,
8147 underlying_type: Metadata,
8148 size_in_bits_lo: u32,
8149 size_in_bits_hi: u32,
8150 align_in_bits_lo: u32,
8151 align_in_bits_hi: u32,
8152 offset_in_bits_lo: u32,
8153 offset_in_bits_hi: u32,
8154
8155 pub fn bitSize(self: DerivedType) u64 {
8156 return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
8157 }
8158 pub fn bitAlign(self: DerivedType) u64 {
8159 return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo;
8160 }
8161 pub fn bitOffset(self: DerivedType) u64 {
8162 return @as(u64, self.offset_in_bits_hi) << 32 | self.offset_in_bits_lo;
8163 }
8164 };
8165
8166 pub const SubroutineType = struct {
8167 types_tuple: Metadata,
8168 };
8169
8170 pub const Enumerator = struct {
8171 name: MetadataString,
8172 bit_width: u32,
8173 limbs_index: u32,
8174 limbs_len: u32,
8175 };
8176
8177 pub const Subrange = struct {
8178 lower_bound: Metadata,
8179 count: Metadata,
8180 };
8181
8182 pub const Expression = struct {
8183 elements_len: u32,
8184
8185 // elements: [elements_len]u32
8186 };
8187
8188 pub const Tuple = struct {
8189 elements_len: u32,
8190
8191 // elements: [elements_len]Metadata
8192 };
8193
8194 pub const StrTuple = struct {
8195 str: MetadataString,
8196 elements_len: u32,
8197
8198 // elements: [elements_len]Metadata
8199 };
8200
8201 pub const ModuleFlag = struct {
8202 behavior: Metadata,
8203 name: MetadataString,
8204 constant: Metadata,
8205 };
8206
8207 pub const LocalVar = struct {
8208 name: MetadataString,
8209 file: Metadata,
8210 scope: Metadata,
8211 line: u32,
8212 ty: Metadata,
8213 };
8214
8215 pub const Parameter = struct {
8216 name: MetadataString,
8217 file: Metadata,
8218 scope: Metadata,
8219 line: u32,
8220 ty: Metadata,
8221 arg_no: u32,
8222 };
8223
8224 pub const GlobalVar = struct {
8225 pub const Options = struct {
8226 local: bool,
8227 };
8228
8229 name: MetadataString,
8230 linkage_name: MetadataString,
8231 file: Metadata,
8232 scope: Metadata,
8233 line: u32,
8234 ty: Metadata,
8235 variable: Variable.Index,
8236 };
8237
8238 pub const GlobalVarExpression = struct {
8239 variable: Metadata,
8240 expression: Metadata,
8241 };
8242
8243 pub fn toValue(self: Metadata) Value {
8244 return @enumFromInt(Value.first_metadata + @intFromEnum(self));
8245 }
8246
8247 const Formatter = struct {
8248 builder: *Builder,
8249 need_comma: bool,
8250 map: std.AutoArrayHashMapUnmanaged(union(enum) {
8251 metadata: Metadata,
8252 debug_location: DebugLocation.Location,
8253 }, void) = .{},
8254
8255 const FormatData = struct {
8256 formatter: *Formatter,
8257 prefix: []const u8 = "",
8258 node: Node,
8259
8260 const Node = union(enum) {
8261 none,
8262 @"inline": Metadata,
8263 index: u32,
8264
8265 local_value: ValueData,
8266 local_metadata: ValueData,
8267 local_inline: Metadata,
8268 local_index: u32,
8269
8270 string: MetadataString,
8271 bool: bool,
8272 u32: u32,
8273 u64: u64,
8274 di_flags: DIFlags,
8275 sp_flags: Subprogram.DISPFlags,
8276 raw: []const u8,
8277
8278 const ValueData = struct {
8279 value: Value,
8280 function: Function.Index,
8281 };
8282 };
8283 };
8284 fn format(
8285 data: FormatData,
8286 comptime fmt_str: []const u8,
8287 fmt_opts: std.fmt.FormatOptions,
8288 writer: anytype,
8289 ) @TypeOf(writer).Error!void {
8290 if (data.node == .none) return;
8291
8292 const is_specialized = fmt_str.len > 0 and fmt_str[0] == 'S';
8293 const recurse_fmt_str = if (is_specialized) fmt_str[1..] else fmt_str;
8294
8295 if (data.formatter.need_comma) try writer.writeAll(", ");
8296 defer data.formatter.need_comma = true;
8297 try writer.writeAll(data.prefix);
8298
8299 const builder = data.formatter.builder;
8300 switch (data.node) {
8301 .none => unreachable,
8302 .@"inline" => |node| {
8303 const needed_comma = data.formatter.need_comma;
8304 defer data.formatter.need_comma = needed_comma;
8305 data.formatter.need_comma = false;
8306
8307 const item = builder.metadata_items.get(@intFromEnum(node));
8308 switch (item.tag) {
8309 .expression => {
8310 var extra = builder.metadataExtraDataTrail(Expression, item.data);
8311 const elements = extra.trail.next(extra.data.elements_len, u32, builder);
8312 try writer.writeAll("!DIExpression(");
8313 for (elements) |element| try format(.{
8314 .formatter = data.formatter,
8315 .node = .{ .u64 = element },
8316 }, "%", fmt_opts, writer);
8317 try writer.writeByte(')');
8318 },
8319 .constant => try Constant.format(.{
8320 .constant = @enumFromInt(item.data),
8321 .builder = builder,
8322 }, recurse_fmt_str, fmt_opts, writer),
8323 else => unreachable,
8324 }
8325 },
8326 .index => |node| try writer.print("!{d}", .{node}),
8327 inline .local_value, .local_metadata => |node, tag| try Value.format(.{
8328 .value = node.value,
8329 .function = node.function,
8330 .builder = builder,
8331 }, switch (tag) {
8332 .local_value => recurse_fmt_str,
8333 .local_metadata => "%",
8334 else => unreachable,
8335 }, fmt_opts, writer),
8336 inline .local_inline, .local_index => |node, tag| {
8337 if (comptime std.mem.eql(u8, recurse_fmt_str, "%"))
8338 try writer.print("{%} ", .{Type.metadata.fmt(builder)});
8339 try format(.{
8340 .formatter = data.formatter,
8341 .node = @unionInit(FormatData.Node, @tagName(tag)["local_".len..], node),
8342 }, "%", fmt_opts, writer);
8343 },
8344 .string => |node| try writer.print((if (is_specialized) "" else "!") ++ "{}", .{
8345 node.fmt(builder),
8346 }),
8347 inline .bool,
8348 .u32,
8349 .u64,
8350 .di_flags,
8351 .sp_flags,
8352 => |node| try writer.print("{}", .{node}),
8353 .raw => |node| try writer.writeAll(node),
8354 }
8355 }
8356 inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype) switch (@TypeOf(node)) {
8357 Metadata => Allocator.Error,
8358 else => error{},
8359 }!std.fmt.Formatter(format) {
8360 const Node = @TypeOf(node);
8361 const MaybeNode = switch (@typeInfo(Node)) {
8362 .optional => Node,
8363 .null => ?noreturn,
8364 else => ?Node,
8365 };
8366 const Some = @typeInfo(MaybeNode).optional.child;
8367 return .{ .data = .{
8368 .formatter = formatter,
8369 .prefix = prefix,
8370 .node = if (@as(MaybeNode, node)) |some| switch (@typeInfo(Some)) {
8371 .@"enum" => |enum_info| switch (Some) {
8372 Metadata => switch (some) {
8373 .none => .none,
8374 else => try formatter.refUnwrapped(some.unwrap(formatter.builder)),
8375 },
8376 MetadataString => .{ .string = some },
8377 else => if (enum_info.is_exhaustive)
8378 .{ .raw = @tagName(some) }
8379 else
8380 @compileError("unknown type to format: " ++ @typeName(Node)),
8381 },
8382 .enum_literal => .{ .raw = @tagName(some) },
8383 .bool => .{ .bool = some },
8384 .@"struct" => switch (Some) {
8385 DIFlags => .{ .di_flags = some },
8386 Subprogram.DISPFlags => .{ .sp_flags = some },
8387 else => @compileError("unknown type to format: " ++ @typeName(Node)),
8388 },
8389 .int, .comptime_int => .{ .u64 = some },
8390 .pointer => .{ .raw = some },
8391 else => @compileError("unknown type to format: " ++ @typeName(Node)),
8392 } else switch (@typeInfo(Node)) {
8393 .optional, .null => .none,
8394 else => unreachable,
8395 },
8396 } };
8397 }
8398 inline fn fmtLocal(
8399 formatter: *Formatter,
8400 prefix: []const u8,
8401 value: Value,
8402 function: Function.Index,
8403 ) Allocator.Error!std.fmt.Formatter(format) {
8404 return .{ .data = .{
8405 .formatter = formatter,
8406 .prefix = prefix,
8407 .node = switch (value.unwrap()) {
8408 .instruction, .constant => .{ .local_value = .{
8409 .value = value,
8410 .function = function,
8411 } },
8412 .metadata => |metadata| if (value == .none) .none else node: {
8413 const unwrapped = metadata.unwrap(formatter.builder);
8414 break :node if (@intFromEnum(unwrapped) >= first_local_metadata)
8415 .{ .local_metadata = .{
8416 .value = function.ptrConst(formatter.builder).debug_values[
8417 @intFromEnum(unwrapped) - first_local_metadata
8418 ].toValue(),
8419 .function = function,
8420 } }
8421 else switch (try formatter.refUnwrapped(unwrapped)) {
8422 .@"inline" => |node| .{ .local_inline = node },
8423 .index => |node| .{ .local_index = node },
8424 else => unreachable,
8425 };
8426 },
8427 },
8428 } };
8429 }
8430 fn refUnwrapped(formatter: *Formatter, node: Metadata) Allocator.Error!FormatData.Node {
8431 assert(node != .none);
8432 assert(@intFromEnum(node) < first_forward_reference);
8433 const builder = formatter.builder;
8434 const unwrapped_metadata = node.unwrap(builder);
8435 const tag = formatter.builder.metadata_items.items(.tag)[@intFromEnum(unwrapped_metadata)];
8436 switch (tag) {
8437 .none => unreachable,
8438 .expression, .constant => return .{ .@"inline" = unwrapped_metadata },
8439 else => {
8440 assert(!tag.isInline());
8441 const gop = try formatter.map.getOrPut(builder.gpa, .{ .metadata = unwrapped_metadata });
8442 return .{ .index = @intCast(gop.index) };
8443 },
8444 }
8445 }
8446
8447 inline fn specialized(
8448 formatter: *Formatter,
8449 distinct: enum { @"!", @"distinct !" },
8450 node: enum {
8451 DIFile,
8452 DICompileUnit,
8453 DISubprogram,
8454 DILexicalBlock,
8455 DILocation,
8456 DIBasicType,
8457 DICompositeType,
8458 DIDerivedType,
8459 DISubroutineType,
8460 DIEnumerator,
8461 DISubrange,
8462 DILocalVariable,
8463 DIGlobalVariable,
8464 DIGlobalVariableExpression,
8465 },
8466 nodes: anytype,
8467 writer: anytype,
8468 ) !void {
8469 comptime var fmt_str: []const u8 = "";
8470 const names = comptime std.meta.fieldNames(@TypeOf(nodes));
8471 comptime var fields: [2 + names.len]std.builtin.Type.StructField = undefined;
8472 inline for (fields[0..2], .{ "distinct", "node" }) |*field, name| {
8473 fmt_str = fmt_str ++ "{[" ++ name ++ "]s}";
8474 field.* = .{
8475 .name = name,
8476 .type = []const u8,
8477 .default_value_ptr = null,
8478 .is_comptime = false,
8479 .alignment = 0,
8480 };
8481 }
8482 fmt_str = fmt_str ++ "(";
8483 inline for (fields[2..], names) |*field, name| {
8484 fmt_str = fmt_str ++ "{[" ++ name ++ "]S}";
8485 field.* = .{
8486 .name = name,
8487 .type = std.fmt.Formatter(format),
8488 .default_value_ptr = null,
8489 .is_comptime = false,
8490 .alignment = 0,
8491 };
8492 }
8493 fmt_str = fmt_str ++ ")\n";
8494
8495 var fmt_args: @Type(.{ .@"struct" = .{
8496 .layout = .auto,
8497 .fields = &fields,
8498 .decls = &.{},
8499 .is_tuple = false,
8500 } }) = undefined;
8501 fmt_args.distinct = @tagName(distinct);
8502 fmt_args.node = @tagName(node);
8503 inline for (names) |name| @field(fmt_args, name) = try formatter.fmt(
8504 name ++ ": ",
8505 @field(nodes, name),
8506 );
8507 try writer.print(fmt_str, fmt_args);
8508 }
8509 };
8510};
8511
8512pub fn init(options: Options) Allocator.Error!Builder {
8513 var self: Builder = .{
8514 .gpa = options.allocator,
8515 .strip = options.strip,
8516
8517 .source_filename = .none,
8518 .data_layout = .none,
8519 .target_triple = .none,
8520 .module_asm = .{},
8521
8522 .string_map = .{},
8523 .string_indices = .{},
8524 .string_bytes = .{},
8525
8526 .types = .{},
8527 .next_unnamed_type = @enumFromInt(0),
8528 .next_unique_type_id = .{},
8529 .type_map = .{},
8530 .type_items = .{},
8531 .type_extra = .{},
8532
8533 .attributes = .{},
8534 .attributes_map = .{},
8535 .attributes_indices = .{},
8536 .attributes_extra = .{},
8537
8538 .function_attributes_set = .{},
8539
8540 .globals = .{},
8541 .next_unnamed_global = @enumFromInt(0),
8542 .next_replaced_global = .none,
8543 .next_unique_global_id = .{},
8544 .aliases = .{},
8545 .variables = .{},
8546 .functions = .{},
8547
8548 .strtab_string_map = .{},
8549 .strtab_string_indices = .{},
8550 .strtab_string_bytes = .{},
8551
8552 .constant_map = .{},
8553 .constant_items = .{},
8554 .constant_extra = .{},
8555 .constant_limbs = .{},
8556
8557 .metadata_map = .{},
8558 .metadata_items = .{},
8559 .metadata_extra = .{},
8560 .metadata_limbs = .{},
8561 .metadata_forward_references = .{},
8562 .metadata_named = .{},
8563 .metadata_string_map = .{},
8564 .metadata_string_indices = .{},
8565 .metadata_string_bytes = .{},
8566 };
8567 errdefer self.deinit();
8568
8569 try self.string_indices.append(self.gpa, 0);
8570 assert(try self.string("") == .empty);
8571
8572 try self.strtab_string_indices.append(self.gpa, 0);
8573 assert(try self.strtabString("") == .empty);
8574
8575 if (options.name.len > 0) self.source_filename = try self.string(options.name);
8576
8577 if (options.triple.len > 0) {
8578 self.target_triple = try self.string(options.triple);
8579 }
8580
8581 {
8582 const static_len = @typeInfo(Type).@"enum".fields.len - 1;
8583 try self.type_map.ensureTotalCapacity(self.gpa, static_len);
8584 try self.type_items.ensureTotalCapacity(self.gpa, static_len);
8585 inline for (@typeInfo(Type.Simple).@"enum".fields) |simple_field| {
8586 const result = self.getOrPutTypeNoExtraAssumeCapacity(
8587 .{ .tag = .simple, .data = simple_field.value },
8588 );
8589 assert(result.new and result.type == @field(Type, simple_field.name));
8590 }
8591 inline for (.{ 1, 8, 16, 29, 32, 64, 80, 128 }) |bits|
8592 assert(self.intTypeAssumeCapacity(bits) ==
8593 @field(Type, std.fmt.comptimePrint("i{d}", .{bits})));
8594 inline for (.{ 0, 4 }) |addr_space_index| {
8595 const addr_space: AddrSpace = @enumFromInt(addr_space_index);
8596 assert(self.ptrTypeAssumeCapacity(addr_space) ==
8597 @field(Type, std.fmt.comptimePrint("ptr{ }", .{addr_space})));
8598 }
8599 }
8600
8601 {
8602 try self.attributes_indices.append(self.gpa, 0);
8603 assert(try self.attrs(&.{}) == .none);
8604 assert(try self.fnAttrs(&.{}) == .none);
8605 }
8606
8607 assert(try self.intConst(.i1, 0) == .false);
8608 assert(try self.intConst(.i1, 1) == .true);
8609 assert(try self.intConst(.i32, 0) == .@"0");
8610 assert(try self.intConst(.i32, 1) == .@"1");
8611 assert(try self.noneConst(.token) == .none);
8612
8613 assert(try self.metadataNone() == .none);
8614 assert(try self.metadataTuple(&.{}) == .empty_tuple);
8615
8616 try self.metadata_string_indices.append(self.gpa, 0);
8617 assert(try self.metadataString("") == .none);
8618
8619 return self;
8620}
8621
8622pub fn clearAndFree(self: *Builder) void {
8623 self.module_asm.clearAndFree(self.gpa);
8624
8625 self.string_map.clearAndFree(self.gpa);
8626 self.string_indices.clearAndFree(self.gpa);
8627 self.string_bytes.clearAndFree(self.gpa);
8628
8629 self.types.clearAndFree(self.gpa);
8630 self.next_unique_type_id.clearAndFree(self.gpa);
8631 self.type_map.clearAndFree(self.gpa);
8632 self.type_items.clearAndFree(self.gpa);
8633 self.type_extra.clearAndFree(self.gpa);
8634
8635 self.attributes.clearAndFree(self.gpa);
8636 self.attributes_map.clearAndFree(self.gpa);
8637 self.attributes_indices.clearAndFree(self.gpa);
8638 self.attributes_extra.clearAndFree(self.gpa);
8639
8640 self.function_attributes_set.clearAndFree(self.gpa);
8641
8642 self.globals.clearAndFree(self.gpa);
8643 self.next_unique_global_id.clearAndFree(self.gpa);
8644 self.aliases.clearAndFree(self.gpa);
8645 self.variables.clearAndFree(self.gpa);
8646 for (self.functions.items) |*function| function.deinit(self.gpa);
8647 self.functions.clearAndFree(self.gpa);
8648
8649 self.strtab_string_map.clearAndFree(self.gpa);
8650 self.strtab_string_indices.clearAndFree(self.gpa);
8651 self.strtab_string_bytes.clearAndFree(self.gpa);
8652
8653 self.constant_map.clearAndFree(self.gpa);
8654 self.constant_items.shrinkAndFree(self.gpa, 0);
8655 self.constant_extra.clearAndFree(self.gpa);
8656 self.constant_limbs.clearAndFree(self.gpa);
8657
8658 self.metadata_map.clearAndFree(self.gpa);
8659 self.metadata_items.shrinkAndFree(self.gpa, 0);
8660 self.metadata_extra.clearAndFree(self.gpa);
8661 self.metadata_limbs.clearAndFree(self.gpa);
8662 self.metadata_forward_references.clearAndFree(self.gpa);
8663 self.metadata_named.clearAndFree(self.gpa);
8664
8665 self.metadata_string_map.clearAndFree(self.gpa);
8666 self.metadata_string_indices.clearAndFree(self.gpa);
8667 self.metadata_string_bytes.clearAndFree(self.gpa);
8668}
8669
8670pub fn deinit(self: *Builder) void {
8671 self.module_asm.deinit(self.gpa);
8672
8673 self.string_map.deinit(self.gpa);
8674 self.string_indices.deinit(self.gpa);
8675 self.string_bytes.deinit(self.gpa);
8676
8677 self.types.deinit(self.gpa);
8678 self.next_unique_type_id.deinit(self.gpa);
8679 self.type_map.deinit(self.gpa);
8680 self.type_items.deinit(self.gpa);
8681 self.type_extra.deinit(self.gpa);
8682
8683 self.attributes.deinit(self.gpa);
8684 self.attributes_map.deinit(self.gpa);
8685 self.attributes_indices.deinit(self.gpa);
8686 self.attributes_extra.deinit(self.gpa);
8687
8688 self.function_attributes_set.deinit(self.gpa);
8689
8690 self.globals.deinit(self.gpa);
8691 self.next_unique_global_id.deinit(self.gpa);
8692 self.aliases.deinit(self.gpa);
8693 self.variables.deinit(self.gpa);
8694 for (self.functions.items) |*function| function.deinit(self.gpa);
8695 self.functions.deinit(self.gpa);
8696
8697 self.strtab_string_map.deinit(self.gpa);
8698 self.strtab_string_indices.deinit(self.gpa);
8699 self.strtab_string_bytes.deinit(self.gpa);
8700
8701 self.constant_map.deinit(self.gpa);
8702 self.constant_items.deinit(self.gpa);
8703 self.constant_extra.deinit(self.gpa);
8704 self.constant_limbs.deinit(self.gpa);
8705
8706 self.metadata_map.deinit(self.gpa);
8707 self.metadata_items.deinit(self.gpa);
8708 self.metadata_extra.deinit(self.gpa);
8709 self.metadata_limbs.deinit(self.gpa);
8710 self.metadata_forward_references.deinit(self.gpa);
8711 self.metadata_named.deinit(self.gpa);
8712
8713 self.metadata_string_map.deinit(self.gpa);
8714 self.metadata_string_indices.deinit(self.gpa);
8715 self.metadata_string_bytes.deinit(self.gpa);
8716
8717 self.* = undefined;
8718}
8719
8720pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
8721 self.module_asm.clearRetainingCapacity();
8722 return self.appendModuleAsm();
8723}
8724
8725pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
8726 return self.module_asm.writer(self.gpa);
8727}
8728
8729pub fn finishModuleAsm(self: *Builder) Allocator.Error!void {
8730 if (self.module_asm.getLastOrNull()) |last| if (last != '\n')
8731 try self.module_asm.append(self.gpa, '\n');
8732}
8733
8734pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {
8735 try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len);
8736 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8737 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8738
8739 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
8740 if (!gop.found_existing) {
8741 self.string_bytes.appendSliceAssumeCapacity(bytes);
8742 self.string_indices.appendAssumeCapacity(@intCast(self.string_bytes.items.len));
8743 }
8744 return String.fromIndex(gop.index);
8745}
8746
8747pub fn stringNull(self: *Builder, bytes: [:0]const u8) Allocator.Error!String {
8748 return self.string(bytes[0 .. bytes.len + 1]);
8749}
8750
8751pub fn stringIfExists(self: *const Builder, bytes: []const u8) ?String {
8752 return String.fromIndex(
8753 self.string_map.getIndexAdapted(bytes, String.Adapter{ .builder = self }) orelse return null,
8754 );
8755}
8756
8757pub fn fmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allocator.Error!String {
8758 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8759 try self.string_bytes.ensureUnusedCapacity(self.gpa, @intCast(std.fmt.count(fmt_str, fmt_args)));
8760 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8761 return self.fmtAssumeCapacity(fmt_str, fmt_args);
8762}
8763
8764pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) String {
8765 self.string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
8766 return self.trailingStringAssumeCapacity();
8767}
8768
8769pub fn trailingString(self: *Builder) Allocator.Error!String {
8770 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8771 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8772 return self.trailingStringAssumeCapacity();
8773}
8774
8775pub fn trailingStringAssumeCapacity(self: *Builder) String {
8776 const start = self.string_indices.getLast();
8777 const bytes: []const u8 = self.string_bytes.items[start..];
8778 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
8779 if (gop.found_existing) {
8780 self.string_bytes.shrinkRetainingCapacity(start);
8781 } else {
8782 self.string_indices.appendAssumeCapacity(@intCast(self.string_bytes.items.len));
8783 }
8784 return String.fromIndex(gop.index);
8785}
8786
8787pub fn fnType(
8788 self: *Builder,
8789 ret: Type,
8790 params: []const Type,
8791 kind: Type.Function.Kind,
8792) Allocator.Error!Type {
8793 try self.ensureUnusedTypeCapacity(1, Type.Function, params.len);
8794 switch (kind) {
8795 inline else => |comptime_kind| return self.fnTypeAssumeCapacity(ret, params, comptime_kind),
8796 }
8797}
8798
8799pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
8800 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8801 return self.intTypeAssumeCapacity(bits);
8802}
8803
8804pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
8805 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8806 return self.ptrTypeAssumeCapacity(addr_space);
8807}
8808
8809pub fn vectorType(
8810 self: *Builder,
8811 kind: Type.Vector.Kind,
8812 len: u32,
8813 child: Type,
8814) Allocator.Error!Type {
8815 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
8816 switch (kind) {
8817 inline else => |comptime_kind| return self.vectorTypeAssumeCapacity(comptime_kind, len, child),
8818 }
8819}
8820
8821pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {
8822 comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector));
8823 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
8824 return self.arrayTypeAssumeCapacity(len, child);
8825}
8826
8827pub fn structType(
8828 self: *Builder,
8829 kind: Type.Structure.Kind,
8830 fields: []const Type,
8831) Allocator.Error!Type {
8832 try self.ensureUnusedTypeCapacity(1, Type.Structure, fields.len);
8833 switch (kind) {
8834 inline else => |comptime_kind| return self.structTypeAssumeCapacity(comptime_kind, fields),
8835 }
8836}
8837
8838pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
8839 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8840 if (name.slice(self)) |id| {
8841 const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});
8842 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
8843 }
8844 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8845 try self.types.ensureUnusedCapacity(self.gpa, 1);
8846 try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);
8847 try self.ensureUnusedTypeCapacity(1, Type.NamedStructure, 0);
8848 return self.opaqueTypeAssumeCapacity(name);
8849}
8850
8851pub fn namedTypeSetBody(
8852 self: *Builder,
8853 named_type: Type,
8854 body_type: Type,
8855) void {
8856 const named_item = self.type_items.items[@intFromEnum(named_type)];
8857 self.type_extra.items[named_item.data + std.meta.fieldIndex(Type.NamedStructure, "body").?] =
8858 @intFromEnum(body_type);
8859}
8860
8861pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Index {
8862 try self.attributes.ensureUnusedCapacity(self.gpa, 1);
8863
8864 const gop = self.attributes.getOrPutAssumeCapacity(attribute.toStorage());
8865 if (!gop.found_existing) gop.value_ptr.* = {};
8866 return @enumFromInt(gop.index);
8867}
8868
8869pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attributes {
8870 std.sort.heap(Attribute.Index, attributes, self, struct {
8871 pub fn lessThan(builder: *const Builder, lhs: Attribute.Index, rhs: Attribute.Index) bool {
8872 const lhs_kind = lhs.getKind(builder);
8873 const rhs_kind = rhs.getKind(builder);
8874 assert(lhs_kind != rhs_kind);
8875 return @intFromEnum(lhs_kind) < @intFromEnum(rhs_kind);
8876 }
8877 }.lessThan);
8878 return @enumFromInt(try self.attrGeneric(@ptrCast(attributes)));
8879}
8880
8881pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes {
8882 try self.function_attributes_set.ensureUnusedCapacity(self.gpa, 1);
8883 const function_attributes: FunctionAttributes = @enumFromInt(try self.attrGeneric(@ptrCast(
8884 fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last|
8885 last + 1
8886 else
8887 0],
8888 )));
8889
8890 _ = self.function_attributes_set.getOrPutAssumeCapacity(function_attributes);
8891 return function_attributes;
8892}
8893
8894pub fn addGlobal(self: *Builder, name: StrtabString, global: Global) Allocator.Error!Global.Index {
8895 assert(!name.isAnon());
8896 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8897 try self.ensureUnusedGlobalCapacity(name);
8898 return self.addGlobalAssumeCapacity(name, global);
8899}
8900
8901pub fn addGlobalAssumeCapacity(self: *Builder, name: StrtabString, global: Global) Global.Index {
8902 _ = self.ptrTypeAssumeCapacity(global.addr_space);
8903 var id = name;
8904 if (name == .empty) {
8905 id = self.next_unnamed_global;
8906 assert(id != self.next_replaced_global);
8907 self.next_unnamed_global = @enumFromInt(@intFromEnum(id) + 1);
8908 }
8909 while (true) {
8910 const global_gop = self.globals.getOrPutAssumeCapacity(id);
8911 if (!global_gop.found_existing) {
8912 global_gop.value_ptr.* = global;
8913 const global_index: Global.Index = @enumFromInt(global_gop.index);
8914 global_index.updateDsoLocal(self);
8915 return global_index;
8916 }
8917
8918 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
8919 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
8920 id = self.strtabStringFmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
8921 unique_gop.value_ptr.* += 1;
8922 }
8923}
8924
8925pub fn getGlobal(self: *const Builder, name: StrtabString) ?Global.Index {
8926 return @enumFromInt(self.globals.getIndex(name) orelse return null);
8927}
8928
8929pub fn addAlias(
8930 self: *Builder,
8931 name: StrtabString,
8932 ty: Type,
8933 addr_space: AddrSpace,
8934 aliasee: Constant,
8935) Allocator.Error!Alias.Index {
8936 assert(!name.isAnon());
8937 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8938 try self.ensureUnusedGlobalCapacity(name);
8939 try self.aliases.ensureUnusedCapacity(self.gpa, 1);
8940 return self.addAliasAssumeCapacity(name, ty, addr_space, aliasee);
8941}
8942
8943pub fn addAliasAssumeCapacity(
8944 self: *Builder,
8945 name: StrtabString,
8946 ty: Type,
8947 addr_space: AddrSpace,
8948 aliasee: Constant,
8949) Alias.Index {
8950 const alias_index: Alias.Index = @enumFromInt(self.aliases.items.len);
8951 self.aliases.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
8952 .addr_space = addr_space,
8953 .type = ty,
8954 .kind = .{ .alias = alias_index },
8955 }), .aliasee = aliasee });
8956 return alias_index;
8957}
8958
8959pub fn addVariable(
8960 self: *Builder,
8961 name: StrtabString,
8962 ty: Type,
8963 addr_space: AddrSpace,
8964) Allocator.Error!Variable.Index {
8965 assert(!name.isAnon());
8966 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8967 try self.ensureUnusedGlobalCapacity(name);
8968 try self.variables.ensureUnusedCapacity(self.gpa, 1);
8969 return self.addVariableAssumeCapacity(ty, name, addr_space);
8970}
8971
8972pub fn addVariableAssumeCapacity(
8973 self: *Builder,
8974 ty: Type,
8975 name: StrtabString,
8976 addr_space: AddrSpace,
8977) Variable.Index {
8978 const variable_index: Variable.Index = @enumFromInt(self.variables.items.len);
8979 self.variables.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
8980 .addr_space = addr_space,
8981 .type = ty,
8982 .kind = .{ .variable = variable_index },
8983 }) });
8984 return variable_index;
8985}
8986
8987pub fn addFunction(
8988 self: *Builder,
8989 ty: Type,
8990 name: StrtabString,
8991 addr_space: AddrSpace,
8992) Allocator.Error!Function.Index {
8993 assert(!name.isAnon());
8994 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8995 try self.ensureUnusedGlobalCapacity(name);
8996 try self.functions.ensureUnusedCapacity(self.gpa, 1);
8997 return self.addFunctionAssumeCapacity(ty, name, addr_space);
8998}
8999
9000pub fn addFunctionAssumeCapacity(
9001 self: *Builder,
9002 ty: Type,
9003 name: StrtabString,
9004 addr_space: AddrSpace,
9005) Function.Index {
9006 assert(ty.isFunction(self));
9007 const function_index: Function.Index = @enumFromInt(self.functions.items.len);
9008 self.functions.appendAssumeCapacity(.{
9009 .global = self.addGlobalAssumeCapacity(name, .{
9010 .addr_space = addr_space,
9011 .type = ty,
9012 .kind = .{ .function = function_index },
9013 }),
9014 .strip = undefined,
9015 });
9016 return function_index;
9017}
9018
9019pub fn getIntrinsic(
9020 self: *Builder,
9021 id: Intrinsic,
9022 overload: []const Type,
9023) Allocator.Error!Function.Index {
9024 const ExpectedContents = extern union {
9025 attrs: extern struct {
9026 params: [expected_args_len]Type,
9027 fn_attrs: [FunctionAttributes.params_index + expected_args_len]Attributes,
9028 attrs: [expected_attrs_len]Attribute.Index,
9029 fields: [expected_fields_len]Type,
9030 },
9031 };
9032 var stack align(@max(@alignOf(std.heap.StackFallbackAllocator(0)), @alignOf(ExpectedContents))) =
9033 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
9034 const allocator = stack.get();
9035
9036 const name = name: {
9037 const writer = self.strtab_string_bytes.writer(self.gpa);
9038 try writer.print("llvm.{s}", .{@tagName(id)});
9039 for (overload) |ty| try writer.print(".{m}", .{ty.fmt(self)});
9040 break :name try self.trailingStrtabString();
9041 };
9042 if (self.getGlobal(name)) |global| return global.ptrConst(self).kind.function;
9043
9044 const signature = Intrinsic.signatures.get(id);
9045 const param_types = try allocator.alloc(Type, signature.params.len);
9046 defer allocator.free(param_types);
9047 const function_attributes = try allocator.alloc(
9048 Attributes,
9049 FunctionAttributes.params_index + (signature.params.len - signature.ret_len),
9050 );
9051 defer allocator.free(function_attributes);
9052
9053 var attributes: struct {
9054 builder: *Builder,
9055 list: std.ArrayList(Attribute.Index),
9056
9057 fn deinit(state: *@This()) void {
9058 state.list.deinit();
9059 state.* = undefined;
9060 }
9061
9062 fn get(state: *@This(), attributes: []const Attribute) Allocator.Error!Attributes {
9063 try state.list.resize(attributes.len);
9064 for (state.list.items, attributes) |*item, attribute|
9065 item.* = try state.builder.attr(attribute);
9066 return state.builder.attrs(state.list.items);
9067 }
9068 } = .{ .builder = self, .list = std.ArrayList(Attribute.Index).init(allocator) };
9069 defer attributes.deinit();
9070
9071 var overload_index: usize = 0;
9072 function_attributes[FunctionAttributes.function_index] = try attributes.get(signature.attrs);
9073 function_attributes[FunctionAttributes.return_index] = .none; // needed for void return
9074 for (0.., param_types, signature.params) |param_index, *param_type, signature_param| {
9075 switch (signature_param.kind) {
9076 .type => |ty| param_type.* = ty,
9077 .overloaded => {
9078 param_type.* = overload[overload_index];
9079 overload_index += 1;
9080 },
9081 .matches, .matches_scalar, .matches_changed_scalar => {},
9082 }
9083 function_attributes[
9084 if (param_index < signature.ret_len)
9085 FunctionAttributes.return_index
9086 else
9087 FunctionAttributes.params_index + (param_index - signature.ret_len)
9088 ] = try attributes.get(signature_param.attrs);
9089 }
9090 assert(overload_index == overload.len);
9091 for (param_types, signature.params) |*param_type, signature_param| {
9092 param_type.* = switch (signature_param.kind) {
9093 .type, .overloaded => continue,
9094 .matches => |param_index| param_types[param_index],
9095 .matches_scalar => |param_index| param_types[param_index].scalarType(self),
9096 .matches_changed_scalar => |info| try param_types[info.index]
9097 .changeScalar(info.scalar, self),
9098 };
9099 }
9100
9101 const function_index = try self.addFunction(try self.fnType(switch (signature.ret_len) {
9102 0 => .void,
9103 1 => param_types[0],
9104 else => try self.structType(.normal, param_types[0..signature.ret_len]),
9105 }, param_types[signature.ret_len..], .normal), name, .default);
9106 function_index.ptr(self).attributes = try self.fnAttrs(function_attributes);
9107 return function_index;
9108}
9109
9110pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Constant {
9111 const int_value = switch (@typeInfo(@TypeOf(value))) {
9112 .int, .comptime_int => value,
9113 .@"enum" => @intFromEnum(value),
9114 else => @compileError("intConst expected an integral value, got " ++ @typeName(@TypeOf(value))),
9115 };
9116 var limbs: [
9117 switch (@typeInfo(@TypeOf(int_value))) {
9118 .int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
9119 .comptime_int => std.math.big.int.calcLimbLen(int_value),
9120 else => unreachable,
9121 }
9122 ]std.math.big.Limb = undefined;
9123 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, int_value).toConst());
9124}
9125
9126pub fn intValue(self: *Builder, ty: Type, value: anytype) Allocator.Error!Value {
9127 return (try self.intConst(ty, value)).toValue();
9128}
9129
9130pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Constant {
9131 try self.constant_map.ensureUnusedCapacity(self.gpa, 1);
9132 try self.constant_items.ensureUnusedCapacity(self.gpa, 1);
9133 try self.constant_limbs.ensureUnusedCapacity(self.gpa, Constant.Integer.limbs + value.limbs.len);
9134 return self.bigIntConstAssumeCapacity(ty, value);
9135}
9136
9137pub fn bigIntValue(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Value {
9138 return (try self.bigIntConst(ty, value)).toValue();
9139}
9140
9141pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {
9142 return switch (ty) {
9143 .half => try self.halfConst(val),
9144 .bfloat => try self.bfloatConst(val),
9145 .float => try self.floatConst(val),
9146 .double => try self.doubleConst(val),
9147 .fp128 => try self.fp128Const(val),
9148 .x86_fp80 => try self.x86_fp80Const(val),
9149 .ppc_fp128 => try self.ppc_fp128Const(.{ val, -0.0 }),
9150 else => unreachable,
9151 };
9152}
9153
9154pub fn fpValue(self: *Builder, ty: Type, comptime value: comptime_float) Allocator.Error!Value {
9155 return (try self.fpConst(ty, value)).toValue();
9156}
9157
9158pub fn nanConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9159 return switch (ty) {
9160 .half => try self.halfConst(std.math.nan(f16)),
9161 .bfloat => try self.bfloatConst(std.math.nan(f32)),
9162 .float => try self.floatConst(std.math.nan(f32)),
9163 .double => try self.doubleConst(std.math.nan(f64)),
9164 .fp128 => try self.fp128Const(std.math.nan(f128)),
9165 .x86_fp80 => try self.x86_fp80Const(std.math.nan(f80)),
9166 .ppc_fp128 => try self.ppc_fp128Const(.{std.math.nan(f64)} ** 2),
9167 else => unreachable,
9168 };
9169}
9170
9171pub fn nanValue(self: *Builder, ty: Type) Allocator.Error!Value {
9172 return (try self.nanConst(ty)).toValue();
9173}
9174
9175pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {
9176 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9177 return self.halfConstAssumeCapacity(val);
9178}
9179
9180pub fn halfValue(self: *Builder, ty: Type, value: f16) Allocator.Error!Value {
9181 return (try self.halfConst(ty, value)).toValue();
9182}
9183
9184pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {
9185 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9186 return self.bfloatConstAssumeCapacity(val);
9187}
9188
9189pub fn bfloatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
9190 return (try self.bfloatConst(ty, value)).toValue();
9191}
9192
9193pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {
9194 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9195 return self.floatConstAssumeCapacity(val);
9196}
9197
9198pub fn floatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
9199 return (try self.floatConst(ty, value)).toValue();
9200}
9201
9202pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {
9203 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);
9204 return self.doubleConstAssumeCapacity(val);
9205}
9206
9207pub fn doubleValue(self: *Builder, ty: Type, value: f64) Allocator.Error!Value {
9208 return (try self.doubleConst(ty, value)).toValue();
9209}
9210
9211pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {
9212 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
9213 return self.fp128ConstAssumeCapacity(val);
9214}
9215
9216pub fn fp128Value(self: *Builder, ty: Type, value: f128) Allocator.Error!Value {
9217 return (try self.fp128Const(ty, value)).toValue();
9218}
9219
9220pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {
9221 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);
9222 return self.x86_fp80ConstAssumeCapacity(val);
9223}
9224
9225pub fn x86_fp80Value(self: *Builder, ty: Type, value: f80) Allocator.Error!Value {
9226 return (try self.x86_fp80Const(ty, value)).toValue();
9227}
9228
9229pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {
9230 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
9231 return self.ppc_fp128ConstAssumeCapacity(val);
9232}
9233
9234pub fn ppc_fp128Value(self: *Builder, ty: Type, value: [2]f64) Allocator.Error!Value {
9235 return (try self.ppc_fp128Const(ty, value)).toValue();
9236}
9237
9238pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9239 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9240 return self.nullConstAssumeCapacity(ty);
9241}
9242
9243pub fn nullValue(self: *Builder, ty: Type) Allocator.Error!Value {
9244 return (try self.nullConst(ty)).toValue();
9245}
9246
9247pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9248 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9249 return self.noneConstAssumeCapacity(ty);
9250}
9251
9252pub fn noneValue(self: *Builder, ty: Type) Allocator.Error!Value {
9253 return (try self.noneConst(ty)).toValue();
9254}
9255
9256pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
9257 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
9258 return self.structConstAssumeCapacity(ty, vals);
9259}
9260
9261pub fn structValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
9262 return (try self.structConst(ty, vals)).toValue();
9263}
9264
9265pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
9266 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
9267 return self.arrayConstAssumeCapacity(ty, vals);
9268}
9269
9270pub fn arrayValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
9271 return (try self.arrayConst(ty, vals)).toValue();
9272}
9273
9274pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {
9275 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
9276 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9277 return self.stringConstAssumeCapacity(val);
9278}
9279
9280pub fn stringValue(self: *Builder, val: String) Allocator.Error!Value {
9281 return (try self.stringConst(val)).toValue();
9282}
9283
9284pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
9285 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
9286 return self.vectorConstAssumeCapacity(ty, vals);
9287}
9288
9289pub fn vectorValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
9290 return (try self.vectorConst(ty, vals)).toValue();
9291}
9292
9293pub fn splatConst(self: *Builder, ty: Type, val: Constant) Allocator.Error!Constant {
9294 try self.ensureUnusedConstantCapacity(1, Constant.Splat, 0);
9295 return self.splatConstAssumeCapacity(ty, val);
9296}
9297
9298pub fn splatValue(self: *Builder, ty: Type, val: Constant) Allocator.Error!Value {
9299 return (try self.splatConst(ty, val)).toValue();
9300}
9301
9302pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9303 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
9304 try self.constant_limbs.ensureUnusedCapacity(
9305 self.gpa,
9306 Constant.Integer.limbs + comptime std.math.big.int.calcLimbLen(0),
9307 );
9308 return self.zeroInitConstAssumeCapacity(ty);
9309}
9310
9311pub fn zeroInitValue(self: *Builder, ty: Type) Allocator.Error!Value {
9312 return (try self.zeroInitConst(ty)).toValue();
9313}
9314
9315pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9316 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9317 return self.undefConstAssumeCapacity(ty);
9318}
9319
9320pub fn undefValue(self: *Builder, ty: Type) Allocator.Error!Value {
9321 return (try self.undefConst(ty)).toValue();
9322}
9323
9324pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9325 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9326 return self.poisonConstAssumeCapacity(ty);
9327}
9328
9329pub fn poisonValue(self: *Builder, ty: Type) Allocator.Error!Value {
9330 return (try self.poisonConst(ty)).toValue();
9331}
9332
9333pub fn blockAddrConst(
9334 self: *Builder,
9335 function: Function.Index,
9336 block: Function.Block.Index,
9337) Allocator.Error!Constant {
9338 try self.ensureUnusedConstantCapacity(1, Constant.BlockAddress, 0);
9339 return self.blockAddrConstAssumeCapacity(function, block);
9340}
9341
9342pub fn blockAddrValue(
9343 self: *Builder,
9344 function: Function.Index,
9345 block: Function.Block.Index,
9346) Allocator.Error!Value {
9347 return (try self.blockAddrConst(function, block)).toValue();
9348}
9349
9350pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
9351 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9352 return self.dsoLocalEquivalentConstAssumeCapacity(function);
9353}
9354
9355pub fn dsoLocalEquivalentValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
9356 return (try self.dsoLocalEquivalentConst(function)).toValue();
9357}
9358
9359pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
9360 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9361 return self.noCfiConstAssumeCapacity(function);
9362}
9363
9364pub fn noCfiValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
9365 return (try self.noCfiConst(function)).toValue();
9366}
9367
9368pub fn convConst(
9369 self: *Builder,
9370 val: Constant,
9371 ty: Type,
9372) Allocator.Error!Constant {
9373 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
9374 return self.convConstAssumeCapacity(val, ty);
9375}
9376
9377pub fn convValue(
9378 self: *Builder,
9379 val: Constant,
9380 ty: Type,
9381) Allocator.Error!Value {
9382 return (try self.convConst(val, ty)).toValue();
9383}
9384
9385pub fn castConst(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Constant {
9386 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
9387 return self.castConstAssumeCapacity(tag, val, ty);
9388}
9389
9390pub fn castValue(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Value {
9391 return (try self.castConst(tag, val, ty)).toValue();
9392}
9393
9394pub fn gepConst(
9395 self: *Builder,
9396 comptime kind: Constant.GetElementPtr.Kind,
9397 ty: Type,
9398 base: Constant,
9399 inrange: ?u16,
9400 indices: []const Constant,
9401) Allocator.Error!Constant {
9402 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
9403 try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len);
9404 return self.gepConstAssumeCapacity(kind, ty, base, inrange, indices);
9405}
9406
9407pub fn gepValue(
9408 self: *Builder,
9409 comptime kind: Constant.GetElementPtr.Kind,
9410 ty: Type,
9411 base: Constant,
9412 inrange: ?u16,
9413 indices: []const Constant,
9414) Allocator.Error!Value {
9415 return (try self.gepConst(kind, ty, base, inrange, indices)).toValue();
9416}
9417
9418pub fn binConst(
9419 self: *Builder,
9420 tag: Constant.Tag,
9421 lhs: Constant,
9422 rhs: Constant,
9423) Allocator.Error!Constant {
9424 try self.ensureUnusedConstantCapacity(1, Constant.Binary, 0);
9425 return self.binConstAssumeCapacity(tag, lhs, rhs);
9426}
9427
9428pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant) Allocator.Error!Value {
9429 return (try self.binConst(tag, lhs, rhs)).toValue();
9430}
9431
9432pub fn asmConst(
9433 self: *Builder,
9434 ty: Type,
9435 info: Constant.Assembly.Info,
9436 assembly: String,
9437 constraints: String,
9438) Allocator.Error!Constant {
9439 try self.ensureUnusedConstantCapacity(1, Constant.Assembly, 0);
9440 return self.asmConstAssumeCapacity(ty, info, assembly, constraints);
9441}
9442
9443pub fn asmValue(
9444 self: *Builder,
9445 ty: Type,
9446 info: Constant.Assembly.Info,
9447 assembly: String,
9448 constraints: String,
9449) Allocator.Error!Value {
9450 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
9451}
9452
9453pub fn dump(self: *Builder) void {
9454 self.print(std.io.getStdErr().writer()) catch {};
9455}
9456
9457pub fn printToFile(self: *Builder, path: []const u8) Allocator.Error!bool {
9458 var file = std.fs.cwd().createFile(path, .{}) catch |err| {
9459 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
9460 return false;
9461 };
9462 defer file.close();
9463 self.print(file.writer()) catch |err| {
9464 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
9465 return false;
9466 };
9467 return true;
9468}
9469
9470pub fn print(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
9471 var bw = std.io.bufferedWriter(writer);
9472 try self.printUnbuffered(bw.writer());
9473 try bw.flush();
9474}
9475
9476fn WriterWithErrors(comptime BackingWriter: type, comptime ExtraErrors: type) type {
9477 return struct {
9478 backing_writer: BackingWriter,
9479
9480 pub const Error = BackingWriter.Error || ExtraErrors;
9481 pub const Writer = std.io.Writer(*const Self, Error, write);
9482
9483 const Self = @This();
9484
9485 pub fn writer(self: *const Self) Writer {
9486 return .{ .context = self };
9487 }
9488
9489 pub fn write(self: *const Self, bytes: []const u8) Error!usize {
9490 return self.backing_writer.write(bytes);
9491 }
9492 };
9493}
9494fn writerWithErrors(
9495 backing_writer: anytype,
9496 comptime ExtraErrors: type,
9497) WriterWithErrors(@TypeOf(backing_writer), ExtraErrors) {
9498 return .{ .backing_writer = backing_writer };
9499}
9500
9501pub fn printUnbuffered(
9502 self: *Builder,
9503 backing_writer: anytype,
9504) (@TypeOf(backing_writer).Error || Allocator.Error)!void {
9505 const writer_with_errors = writerWithErrors(backing_writer, Allocator.Error);
9506 const writer = writer_with_errors.writer();
9507
9508 var need_newline = false;
9509 var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined };
9510 defer metadata_formatter.map.deinit(self.gpa);
9511
9512 if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) {
9513 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9514 if (self.source_filename != .none) try writer.print(
9515 \\; ModuleID = '{s}'
9516 \\source_filename = {"}
9517 \\
9518 , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) });
9519 if (self.data_layout != .none) try writer.print(
9520 \\target datalayout = {"}
9521 \\
9522 , .{self.data_layout.fmt(self)});
9523 if (self.target_triple != .none) try writer.print(
9524 \\target triple = {"}
9525 \\
9526 , .{self.target_triple.fmt(self)});
9527 }
9528
9529 if (self.module_asm.items.len > 0) {
9530 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9531 var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n');
9532 while (line_it.next()) |line| {
9533 try writer.writeAll("module asm ");
9534 try printEscapedString(line, .always_quote, writer);
9535 try writer.writeByte('\n');
9536 }
9537 }
9538
9539 if (self.types.count() > 0) {
9540 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9541 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
9542 \\%{} = type {}
9543 \\
9544 , .{ id.fmt(self), ty.fmt(self) });
9545 }
9546
9547 if (self.variables.items.len > 0) {
9548 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9549 for (self.variables.items) |variable| {
9550 if (variable.global.getReplacement(self) != .none) continue;
9551 const global = variable.global.ptrConst(self);
9552 metadata_formatter.need_comma = true;
9553 defer metadata_formatter.need_comma = undefined;
9554 try writer.print(
9555 \\{} ={}{}{}{}{ }{}{ }{} {s} {%}{ }{, }{}
9556 \\
9557 , .{
9558 variable.global.fmt(self),
9559 Linkage.fmtOptional(if (global.linkage == .external and
9560 variable.init != .no_init) null else global.linkage),
9561 global.preemption,
9562 global.visibility,
9563 global.dll_storage_class,
9564 variable.thread_local,
9565 global.unnamed_addr,
9566 global.addr_space,
9567 global.externally_initialized,
9568 @tagName(variable.mutability),
9569 global.type.fmt(self),
9570 variable.init.fmt(self),
9571 variable.alignment,
9572 try metadata_formatter.fmt("!dbg ", global.dbg),
9573 });
9574 }
9575 }
9576
9577 if (self.aliases.items.len > 0) {
9578 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9579 for (self.aliases.items) |alias| {
9580 if (alias.global.getReplacement(self) != .none) continue;
9581 const global = alias.global.ptrConst(self);
9582 metadata_formatter.need_comma = true;
9583 defer metadata_formatter.need_comma = undefined;
9584 try writer.print(
9585 \\{} ={}{}{}{}{ }{} alias {%}, {%}{}
9586 \\
9587 , .{
9588 alias.global.fmt(self),
9589 global.linkage,
9590 global.preemption,
9591 global.visibility,
9592 global.dll_storage_class,
9593 alias.thread_local,
9594 global.unnamed_addr,
9595 global.type.fmt(self),
9596 alias.aliasee.fmt(self),
9597 try metadata_formatter.fmt("!dbg ", global.dbg),
9598 });
9599 }
9600 }
9601
9602 var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .empty;
9603 defer attribute_groups.deinit(self.gpa);
9604
9605 for (0.., self.functions.items) |function_i, function| {
9606 if (function.global.getReplacement(self) != .none) continue;
9607 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9608 const function_index: Function.Index = @enumFromInt(function_i);
9609 const global = function.global.ptrConst(self);
9610 const params_len = global.type.functionParameters(self).len;
9611 const function_attributes = function.attributes.func(self);
9612 if (function_attributes != .none) try writer.print(
9613 \\; Function Attrs:{}
9614 \\
9615 , .{function_attributes.fmt(self)});
9616 try writer.print(
9617 \\{s}{}{}{}{}{}{"} {%} {}(
9618 , .{
9619 if (function.instructions.len > 0) "define" else "declare",
9620 global.linkage,
9621 global.preemption,
9622 global.visibility,
9623 global.dll_storage_class,
9624 function.call_conv,
9625 function.attributes.ret(self).fmt(self),
9626 global.type.functionReturn(self).fmt(self),
9627 function.global.fmt(self),
9628 });
9629 for (0..params_len) |arg| {
9630 if (arg > 0) try writer.writeAll(", ");
9631 try writer.print(
9632 \\{%}{"}
9633 , .{
9634 global.type.functionParameters(self)[arg].fmt(self),
9635 function.attributes.param(arg, self).fmt(self),
9636 });
9637 if (function.instructions.len > 0)
9638 try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)})
9639 else
9640 try writer.print(" %{d}", .{arg});
9641 }
9642 switch (global.type.functionKind(self)) {
9643 .normal => {},
9644 .vararg => {
9645 if (params_len > 0) try writer.writeAll(", ");
9646 try writer.writeAll("...");
9647 },
9648 }
9649 try writer.print("){}{ }", .{ global.unnamed_addr, global.addr_space });
9650 if (function_attributes != .none) try writer.print(" #{d}", .{
9651 (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
9652 });
9653 {
9654 metadata_formatter.need_comma = false;
9655 defer metadata_formatter.need_comma = undefined;
9656 try writer.print("{ }{}", .{
9657 function.alignment,
9658 try metadata_formatter.fmt(" !dbg ", global.dbg),
9659 });
9660 }
9661 if (function.instructions.len > 0) {
9662 var block_incoming_len: u32 = undefined;
9663 try writer.writeAll(" {\n");
9664 var maybe_dbg_index: ?u32 = null;
9665 for (params_len..function.instructions.len) |instruction_i| {
9666 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
9667 const instruction = function.instructions.get(@intFromEnum(instruction_index));
9668 if (function.debug_locations.get(instruction_index)) |debug_location| switch (debug_location) {
9669 .no_location => maybe_dbg_index = null,
9670 .location => |location| {
9671 const gop = try metadata_formatter.map.getOrPut(self.gpa, .{
9672 .debug_location = location,
9673 });
9674 maybe_dbg_index = @intCast(gop.index);
9675 },
9676 };
9677 switch (instruction.tag) {
9678 .add,
9679 .@"add nsw",
9680 .@"add nuw",
9681 .@"add nuw nsw",
9682 .@"and",
9683 .ashr,
9684 .@"ashr exact",
9685 .fadd,
9686 .@"fadd fast",
9687 .@"fcmp false",
9688 .@"fcmp fast false",
9689 .@"fcmp fast oeq",
9690 .@"fcmp fast oge",
9691 .@"fcmp fast ogt",
9692 .@"fcmp fast ole",
9693 .@"fcmp fast olt",
9694 .@"fcmp fast one",
9695 .@"fcmp fast ord",
9696 .@"fcmp fast true",
9697 .@"fcmp fast ueq",
9698 .@"fcmp fast uge",
9699 .@"fcmp fast ugt",
9700 .@"fcmp fast ule",
9701 .@"fcmp fast ult",
9702 .@"fcmp fast une",
9703 .@"fcmp fast uno",
9704 .@"fcmp oeq",
9705 .@"fcmp oge",
9706 .@"fcmp ogt",
9707 .@"fcmp ole",
9708 .@"fcmp olt",
9709 .@"fcmp one",
9710 .@"fcmp ord",
9711 .@"fcmp true",
9712 .@"fcmp ueq",
9713 .@"fcmp uge",
9714 .@"fcmp ugt",
9715 .@"fcmp ule",
9716 .@"fcmp ult",
9717 .@"fcmp une",
9718 .@"fcmp uno",
9719 .fdiv,
9720 .@"fdiv fast",
9721 .fmul,
9722 .@"fmul fast",
9723 .frem,
9724 .@"frem fast",
9725 .fsub,
9726 .@"fsub fast",
9727 .@"icmp eq",
9728 .@"icmp ne",
9729 .@"icmp sge",
9730 .@"icmp sgt",
9731 .@"icmp sle",
9732 .@"icmp slt",
9733 .@"icmp uge",
9734 .@"icmp ugt",
9735 .@"icmp ule",
9736 .@"icmp ult",
9737 .lshr,
9738 .@"lshr exact",
9739 .mul,
9740 .@"mul nsw",
9741 .@"mul nuw",
9742 .@"mul nuw nsw",
9743 .@"or",
9744 .sdiv,
9745 .@"sdiv exact",
9746 .srem,
9747 .shl,
9748 .@"shl nsw",
9749 .@"shl nuw",
9750 .@"shl nuw nsw",
9751 .sub,
9752 .@"sub nsw",
9753 .@"sub nuw",
9754 .@"sub nuw nsw",
9755 .udiv,
9756 .@"udiv exact",
9757 .urem,
9758 .xor,
9759 => |tag| {
9760 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
9761 try writer.print(" %{} = {s} {%}, {}", .{
9762 instruction_index.name(&function).fmt(self),
9763 @tagName(tag),
9764 extra.lhs.fmt(function_index, self),
9765 extra.rhs.fmt(function_index, self),
9766 });
9767 },
9768 .addrspacecast,
9769 .bitcast,
9770 .fpext,
9771 .fptosi,
9772 .fptoui,
9773 .fptrunc,
9774 .inttoptr,
9775 .ptrtoint,
9776 .sext,
9777 .sitofp,
9778 .trunc,
9779 .uitofp,
9780 .zext,
9781 => |tag| {
9782 const extra = function.extraData(Function.Instruction.Cast, instruction.data);
9783 try writer.print(" %{} = {s} {%} to {%}", .{
9784 instruction_index.name(&function).fmt(self),
9785 @tagName(tag),
9786 extra.val.fmt(function_index, self),
9787 extra.type.fmt(self),
9788 });
9789 },
9790 .alloca,
9791 .@"alloca inalloca",
9792 => |tag| {
9793 const extra = function.extraData(Function.Instruction.Alloca, instruction.data);
9794 try writer.print(" %{} = {s} {%}{,%}{, }{, }", .{
9795 instruction_index.name(&function).fmt(self),
9796 @tagName(tag),
9797 extra.type.fmt(self),
9798 Value.fmt(switch (extra.len) {
9799 .@"1" => .none,
9800 else => extra.len,
9801 }, function_index, self),
9802 extra.info.alignment,
9803 extra.info.addr_space,
9804 });
9805 },
9806 .arg => unreachable,
9807 .atomicrmw => |tag| {
9808 const extra =
9809 function.extraData(Function.Instruction.AtomicRmw, instruction.data);
9810 try writer.print(" %{} = {s}{ } {s} {%}, {%}{ }{ }{, }", .{
9811 instruction_index.name(&function).fmt(self),
9812 @tagName(tag),
9813 extra.info.access_kind,
9814 @tagName(extra.info.atomic_rmw_operation),
9815 extra.ptr.fmt(function_index, self),
9816 extra.val.fmt(function_index, self),
9817 extra.info.sync_scope,
9818 extra.info.success_ordering,
9819 extra.info.alignment,
9820 });
9821 },
9822 .block => {
9823 block_incoming_len = instruction.data;
9824 const name = instruction_index.name(&function);
9825 if (@intFromEnum(instruction_index) > params_len)
9826 try writer.writeByte('\n');
9827 try writer.print("{}:\n", .{name.fmt(self)});
9828 continue;
9829 },
9830 .br => |tag| {
9831 const target: Function.Block.Index = @enumFromInt(instruction.data);
9832 try writer.print(" {s} {%}", .{
9833 @tagName(tag), target.toInst(&function).fmt(function_index, self),
9834 });
9835 },
9836 .br_cond => {
9837 const extra = function.extraData(Function.Instruction.BrCond, instruction.data);
9838 try writer.print(" br {%}, {%}, {%}", .{
9839 extra.cond.fmt(function_index, self),
9840 extra.then.toInst(&function).fmt(function_index, self),
9841 extra.@"else".toInst(&function).fmt(function_index, self),
9842 });
9843 metadata_formatter.need_comma = true;
9844 defer metadata_formatter.need_comma = undefined;
9845 switch (extra.weights) {
9846 .none => {},
9847 .unpredictable => try writer.writeAll("!unpredictable !{}"),
9848 _ => try writer.print("{}", .{
9849 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.weights)))),
9850 }),
9851 }
9852 },
9853 .call,
9854 .@"call fast",
9855 .@"musttail call",
9856 .@"musttail call fast",
9857 .@"notail call",
9858 .@"notail call fast",
9859 .@"tail call",
9860 .@"tail call fast",
9861 => |tag| {
9862 var extra =
9863 function.extraDataTrail(Function.Instruction.Call, instruction.data);
9864 const args = extra.trail.next(extra.data.args_len, Value, &function);
9865 try writer.writeAll(" ");
9866 const ret_ty = extra.data.ty.functionReturn(self);
9867 switch (ret_ty) {
9868 .void => {},
9869 else => try writer.print("%{} = ", .{
9870 instruction_index.name(&function).fmt(self),
9871 }),
9872 .none => unreachable,
9873 }
9874 try writer.print("{s}{}{}{} {%} {}(", .{
9875 @tagName(tag),
9876 extra.data.info.call_conv,
9877 extra.data.attributes.ret(self).fmt(self),
9878 extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
9879 switch (extra.data.ty.functionKind(self)) {
9880 .normal => ret_ty,
9881 .vararg => extra.data.ty,
9882 }.fmt(self),
9883 extra.data.callee.fmt(function_index, self),
9884 });
9885 for (0.., args) |arg_index, arg| {
9886 if (arg_index > 0) try writer.writeAll(", ");
9887 metadata_formatter.need_comma = false;
9888 defer metadata_formatter.need_comma = undefined;
9889 try writer.print("{%}{}{}", .{
9890 arg.typeOf(function_index, self).fmt(self),
9891 extra.data.attributes.param(arg_index, self).fmt(self),
9892 try metadata_formatter.fmtLocal(" ", arg, function_index),
9893 });
9894 }
9895 try writer.writeByte(')');
9896 if (extra.data.info.has_op_bundle_cold) {
9897 try writer.writeAll(" [ \"cold\"() ]");
9898 }
9899 const call_function_attributes = extra.data.attributes.func(self);
9900 if (call_function_attributes != .none) try writer.print(" #{d}", .{
9901 (try attribute_groups.getOrPutValue(
9902 self.gpa,
9903 call_function_attributes,
9904 {},
9905 )).index,
9906 });
9907 },
9908 .cmpxchg,
9909 .@"cmpxchg weak",
9910 => |tag| {
9911 const extra =
9912 function.extraData(Function.Instruction.CmpXchg, instruction.data);
9913 try writer.print(" %{} = {s}{ } {%}, {%}, {%}{ }{ }{ }{, }", .{
9914 instruction_index.name(&function).fmt(self),
9915 @tagName(tag),
9916 extra.info.access_kind,
9917 extra.ptr.fmt(function_index, self),
9918 extra.cmp.fmt(function_index, self),
9919 extra.new.fmt(function_index, self),
9920 extra.info.sync_scope,
9921 extra.info.success_ordering,
9922 extra.info.failure_ordering,
9923 extra.info.alignment,
9924 });
9925 },
9926 .extractelement => |tag| {
9927 const extra =
9928 function.extraData(Function.Instruction.ExtractElement, instruction.data);
9929 try writer.print(" %{} = {s} {%}, {%}", .{
9930 instruction_index.name(&function).fmt(self),
9931 @tagName(tag),
9932 extra.val.fmt(function_index, self),
9933 extra.index.fmt(function_index, self),
9934 });
9935 },
9936 .extractvalue => |tag| {
9937 var extra = function.extraDataTrail(
9938 Function.Instruction.ExtractValue,
9939 instruction.data,
9940 );
9941 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
9942 try writer.print(" %{} = {s} {%}", .{
9943 instruction_index.name(&function).fmt(self),
9944 @tagName(tag),
9945 extra.data.val.fmt(function_index, self),
9946 });
9947 for (indices) |index| try writer.print(", {d}", .{index});
9948 },
9949 .fence => |tag| {
9950 const info: MemoryAccessInfo = @bitCast(instruction.data);
9951 try writer.print(" {s}{ }{ }", .{
9952 @tagName(tag),
9953 info.sync_scope,
9954 info.success_ordering,
9955 });
9956 },
9957 .fneg,
9958 .@"fneg fast",
9959 => |tag| {
9960 const val: Value = @enumFromInt(instruction.data);
9961 try writer.print(" %{} = {s} {%}", .{
9962 instruction_index.name(&function).fmt(self),
9963 @tagName(tag),
9964 val.fmt(function_index, self),
9965 });
9966 },
9967 .getelementptr,
9968 .@"getelementptr inbounds",
9969 => |tag| {
9970 var extra = function.extraDataTrail(
9971 Function.Instruction.GetElementPtr,
9972 instruction.data,
9973 );
9974 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
9975 try writer.print(" %{} = {s} {%}, {%}", .{
9976 instruction_index.name(&function).fmt(self),
9977 @tagName(tag),
9978 extra.data.type.fmt(self),
9979 extra.data.base.fmt(function_index, self),
9980 });
9981 for (indices) |index| try writer.print(", {%}", .{
9982 index.fmt(function_index, self),
9983 });
9984 },
9985 .indirectbr => |tag| {
9986 var extra =
9987 function.extraDataTrail(Function.Instruction.IndirectBr, instruction.data);
9988 const targets =
9989 extra.trail.next(extra.data.targets_len, Function.Block.Index, &function);
9990 try writer.print(" {s} {%}, [", .{
9991 @tagName(tag),
9992 extra.data.addr.fmt(function_index, self),
9993 });
9994 for (0.., targets) |target_index, target| {
9995 if (target_index > 0) try writer.writeAll(", ");
9996 try writer.print("{%}", .{
9997 target.toInst(&function).fmt(function_index, self),
9998 });
9999 }
10000 try writer.writeByte(']');
10001 },
10002 .insertelement => |tag| {
10003 const extra =
10004 function.extraData(Function.Instruction.InsertElement, instruction.data);
10005 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10006 instruction_index.name(&function).fmt(self),
10007 @tagName(tag),
10008 extra.val.fmt(function_index, self),
10009 extra.elem.fmt(function_index, self),
10010 extra.index.fmt(function_index, self),
10011 });
10012 },
10013 .insertvalue => |tag| {
10014 var extra =
10015 function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
10016 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
10017 try writer.print(" %{} = {s} {%}, {%}", .{
10018 instruction_index.name(&function).fmt(self),
10019 @tagName(tag),
10020 extra.data.val.fmt(function_index, self),
10021 extra.data.elem.fmt(function_index, self),
10022 });
10023 for (indices) |index| try writer.print(", {d}", .{index});
10024 },
10025 .load,
10026 .@"load atomic",
10027 => |tag| {
10028 const extra = function.extraData(Function.Instruction.Load, instruction.data);
10029 try writer.print(" %{} = {s}{ } {%}, {%}{ }{ }{, }", .{
10030 instruction_index.name(&function).fmt(self),
10031 @tagName(tag),
10032 extra.info.access_kind,
10033 extra.type.fmt(self),
10034 extra.ptr.fmt(function_index, self),
10035 extra.info.sync_scope,
10036 extra.info.success_ordering,
10037 extra.info.alignment,
10038 });
10039 },
10040 .phi,
10041 .@"phi fast",
10042 => |tag| {
10043 var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data);
10044 const vals = extra.trail.next(block_incoming_len, Value, &function);
10045 const blocks =
10046 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
10047 try writer.print(" %{} = {s} {%} ", .{
10048 instruction_index.name(&function).fmt(self),
10049 @tagName(tag),
10050 vals[0].typeOf(function_index, self).fmt(self),
10051 });
10052 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
10053 if (incoming_index > 0) try writer.writeAll(", ");
10054 try writer.print("[ {}, {} ]", .{
10055 incoming_val.fmt(function_index, self),
10056 incoming_block.toInst(&function).fmt(function_index, self),
10057 });
10058 }
10059 },
10060 .ret => |tag| {
10061 const val: Value = @enumFromInt(instruction.data);
10062 try writer.print(" {s} {%}", .{
10063 @tagName(tag),
10064 val.fmt(function_index, self),
10065 });
10066 },
10067 .@"ret void",
10068 .@"unreachable",
10069 => |tag| try writer.print(" {s}", .{@tagName(tag)}),
10070 .select,
10071 .@"select fast",
10072 => |tag| {
10073 const extra = function.extraData(Function.Instruction.Select, instruction.data);
10074 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10075 instruction_index.name(&function).fmt(self),
10076 @tagName(tag),
10077 extra.cond.fmt(function_index, self),
10078 extra.lhs.fmt(function_index, self),
10079 extra.rhs.fmt(function_index, self),
10080 });
10081 },
10082 .shufflevector => |tag| {
10083 const extra =
10084 function.extraData(Function.Instruction.ShuffleVector, instruction.data);
10085 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10086 instruction_index.name(&function).fmt(self),
10087 @tagName(tag),
10088 extra.lhs.fmt(function_index, self),
10089 extra.rhs.fmt(function_index, self),
10090 extra.mask.fmt(function_index, self),
10091 });
10092 },
10093 .store,
10094 .@"store atomic",
10095 => |tag| {
10096 const extra = function.extraData(Function.Instruction.Store, instruction.data);
10097 try writer.print(" {s}{ } {%}, {%}{ }{ }{, }", .{
10098 @tagName(tag),
10099 extra.info.access_kind,
10100 extra.val.fmt(function_index, self),
10101 extra.ptr.fmt(function_index, self),
10102 extra.info.sync_scope,
10103 extra.info.success_ordering,
10104 extra.info.alignment,
10105 });
10106 },
10107 .@"switch" => |tag| {
10108 var extra =
10109 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
10110 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
10111 const blocks =
10112 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
10113 try writer.print(" {s} {%}, {%} [\n", .{
10114 @tagName(tag),
10115 extra.data.val.fmt(function_index, self),
10116 extra.data.default.toInst(&function).fmt(function_index, self),
10117 });
10118 for (vals, blocks) |case_val, case_block| try writer.print(
10119 " {%}, {%}\n",
10120 .{
10121 case_val.fmt(self),
10122 case_block.toInst(&function).fmt(function_index, self),
10123 },
10124 );
10125 try writer.writeAll(" ]");
10126 metadata_formatter.need_comma = true;
10127 defer metadata_formatter.need_comma = undefined;
10128 switch (extra.data.weights) {
10129 .none => {},
10130 .unpredictable => try writer.writeAll("!unpredictable !{}"),
10131 _ => try writer.print("{}", .{
10132 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.data.weights)))),
10133 }),
10134 }
10135 },
10136 .va_arg => |tag| {
10137 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
10138 try writer.print(" %{} = {s} {%}, {%}", .{
10139 instruction_index.name(&function).fmt(self),
10140 @tagName(tag),
10141 extra.list.fmt(function_index, self),
10142 extra.type.fmt(self),
10143 });
10144 },
10145 }
10146
10147 if (maybe_dbg_index) |dbg_index| {
10148 try writer.print(", !dbg !{}", .{dbg_index});
10149 }
10150 try writer.writeByte('\n');
10151 }
10152 try writer.writeByte('}');
10153 }
10154 try writer.writeByte('\n');
10155 }
10156
10157 if (attribute_groups.count() > 0) {
10158 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10159 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
10160 try writer.print(
10161 \\attributes #{d} = {{{#"} }}
10162 \\
10163 , .{ attribute_group_index, attribute_group.fmt(self) });
10164 }
10165
10166 if (self.metadata_named.count() > 0) {
10167 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10168 for (self.metadata_named.keys(), self.metadata_named.values()) |name, data| {
10169 const elements: []const Metadata =
10170 @ptrCast(self.metadata_extra.items[data.index..][0..data.len]);
10171 try writer.writeByte('!');
10172 try printEscapedString(name.slice(self), .quote_unless_valid_identifier, writer);
10173 try writer.writeAll(" = !{");
10174 metadata_formatter.need_comma = false;
10175 defer metadata_formatter.need_comma = undefined;
10176 for (elements) |element| try writer.print("{}", .{try metadata_formatter.fmt("", element)});
10177 try writer.writeAll("}\n");
10178 }
10179 }
10180
10181 if (metadata_formatter.map.count() > 0) {
10182 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10183 var metadata_index: usize = 0;
10184 while (metadata_index < metadata_formatter.map.count()) : (metadata_index += 1) {
10185 @setEvalBranchQuota(10_000);
10186 try writer.print("!{} = ", .{metadata_index});
10187 metadata_formatter.need_comma = false;
10188 defer metadata_formatter.need_comma = undefined;
10189
10190 const key = metadata_formatter.map.keys()[metadata_index];
10191 const metadata_item = switch (key) {
10192 .debug_location => |location| {
10193 try metadata_formatter.specialized(.@"!", .DILocation, .{
10194 .line = location.line,
10195 .column = location.column,
10196 .scope = location.scope,
10197 .inlinedAt = location.inlined_at,
10198 .isImplicitCode = false,
10199 }, writer);
10200 continue;
10201 },
10202 .metadata => |metadata| self.metadata_items.get(@intFromEnum(metadata)),
10203 };
10204
10205 switch (metadata_item.tag) {
10206 .none, .expression, .constant => unreachable,
10207 .file => {
10208 const extra = self.metadataExtraData(Metadata.File, metadata_item.data);
10209 try metadata_formatter.specialized(.@"!", .DIFile, .{
10210 .filename = extra.filename,
10211 .directory = extra.directory,
10212 .checksumkind = null,
10213 .checksum = null,
10214 .source = null,
10215 }, writer);
10216 },
10217 .compile_unit,
10218 .@"compile_unit optimized",
10219 => |kind| {
10220 const extra = self.metadataExtraData(Metadata.CompileUnit, metadata_item.data);
10221 try metadata_formatter.specialized(.@"distinct !", .DICompileUnit, .{
10222 .language = .DW_LANG_C99,
10223 .file = extra.file,
10224 .producer = extra.producer,
10225 .isOptimized = switch (kind) {
10226 .compile_unit => false,
10227 .@"compile_unit optimized" => true,
10228 else => unreachable,
10229 },
10230 .flags = null,
10231 .runtimeVersion = 0,
10232 .splitDebugFilename = null,
10233 .emissionKind = .FullDebug,
10234 .enums = extra.enums,
10235 .retainedTypes = null,
10236 .globals = extra.globals,
10237 .imports = null,
10238 .macros = null,
10239 .dwoId = null,
10240 .splitDebugInlining = false,
10241 .debugInfoForProfiling = null,
10242 .nameTableKind = null,
10243 .rangesBaseAddress = null,
10244 .sysroot = null,
10245 .sdk = null,
10246 }, writer);
10247 },
10248 .subprogram,
10249 .@"subprogram local",
10250 .@"subprogram definition",
10251 .@"subprogram local definition",
10252 .@"subprogram optimized",
10253 .@"subprogram optimized local",
10254 .@"subprogram optimized definition",
10255 .@"subprogram optimized local definition",
10256 => |kind| {
10257 const extra = self.metadataExtraData(Metadata.Subprogram, metadata_item.data);
10258 try metadata_formatter.specialized(.@"distinct !", .DISubprogram, .{
10259 .name = extra.name,
10260 .linkageName = extra.linkage_name,
10261 .scope = extra.file,
10262 .file = extra.file,
10263 .line = extra.line,
10264 .type = extra.ty,
10265 .scopeLine = extra.scope_line,
10266 .containingType = null,
10267 .virtualIndex = null,
10268 .thisAdjustment = null,
10269 .flags = extra.di_flags,
10270 .spFlags = @as(Metadata.Subprogram.DISPFlags, @bitCast(@as(u32, @as(u3, @intCast(
10271 @intFromEnum(kind) - @intFromEnum(Metadata.Tag.subprogram),
10272 ))) << 2)),
10273 .unit = extra.compile_unit,
10274 .templateParams = null,
10275 .declaration = null,
10276 .retainedNodes = null,
10277 .thrownTypes = null,
10278 .annotations = null,
10279 .targetFuncName = null,
10280 }, writer);
10281 },
10282 .lexical_block => {
10283 const extra = self.metadataExtraData(Metadata.LexicalBlock, metadata_item.data);
10284 try metadata_formatter.specialized(.@"distinct !", .DILexicalBlock, .{
10285 .scope = extra.scope,
10286 .file = extra.file,
10287 .line = extra.line,
10288 .column = extra.column,
10289 }, writer);
10290 },
10291 .location => {
10292 const extra = self.metadataExtraData(Metadata.Location, metadata_item.data);
10293 try metadata_formatter.specialized(.@"!", .DILocation, .{
10294 .line = extra.line,
10295 .column = extra.column,
10296 .scope = extra.scope,
10297 .inlinedAt = extra.inlined_at,
10298 .isImplicitCode = false,
10299 }, writer);
10300 },
10301 .basic_bool_type,
10302 .basic_unsigned_type,
10303 .basic_signed_type,
10304 .basic_float_type,
10305 => |kind| {
10306 const extra = self.metadataExtraData(Metadata.BasicType, metadata_item.data);
10307 try metadata_formatter.specialized(.@"!", .DIBasicType, .{
10308 .tag = null,
10309 .name = switch (extra.name) {
10310 .none => null,
10311 else => extra.name,
10312 },
10313 .size = extra.bitSize(),
10314 .@"align" = null,
10315 .encoding = @as(enum {
10316 DW_ATE_boolean,
10317 DW_ATE_unsigned,
10318 DW_ATE_signed,
10319 DW_ATE_float,
10320 }, switch (kind) {
10321 .basic_bool_type => .DW_ATE_boolean,
10322 .basic_unsigned_type => .DW_ATE_unsigned,
10323 .basic_signed_type => .DW_ATE_signed,
10324 .basic_float_type => .DW_ATE_float,
10325 else => unreachable,
10326 }),
10327 .flags = null,
10328 }, writer);
10329 },
10330 .composite_struct_type,
10331 .composite_union_type,
10332 .composite_enumeration_type,
10333 .composite_array_type,
10334 .composite_vector_type,
10335 => |kind| {
10336 const extra = self.metadataExtraData(Metadata.CompositeType, metadata_item.data);
10337 try metadata_formatter.specialized(.@"!", .DICompositeType, .{
10338 .tag = @as(enum {
10339 DW_TAG_structure_type,
10340 DW_TAG_union_type,
10341 DW_TAG_enumeration_type,
10342 DW_TAG_array_type,
10343 }, switch (kind) {
10344 .composite_struct_type => .DW_TAG_structure_type,
10345 .composite_union_type => .DW_TAG_union_type,
10346 .composite_enumeration_type => .DW_TAG_enumeration_type,
10347 .composite_array_type, .composite_vector_type => .DW_TAG_array_type,
10348 else => unreachable,
10349 }),
10350 .name = switch (extra.name) {
10351 .none => null,
10352 else => extra.name,
10353 },
10354 .scope = extra.scope,
10355 .file = null,
10356 .line = null,
10357 .baseType = extra.underlying_type,
10358 .size = extra.bitSize(),
10359 .@"align" = extra.bitAlign(),
10360 .offset = null,
10361 .flags = null,
10362 .elements = extra.fields_tuple,
10363 .runtimeLang = null,
10364 .vtableHolder = null,
10365 .templateParams = null,
10366 .identifier = null,
10367 .discriminator = null,
10368 .dataLocation = null,
10369 .associated = null,
10370 .allocated = null,
10371 .rank = null,
10372 .annotations = null,
10373 }, writer);
10374 },
10375 .derived_pointer_type,
10376 .derived_member_type,
10377 => |kind| {
10378 const extra = self.metadataExtraData(Metadata.DerivedType, metadata_item.data);
10379 try metadata_formatter.specialized(.@"!", .DIDerivedType, .{
10380 .tag = @as(enum {
10381 DW_TAG_pointer_type,
10382 DW_TAG_member,
10383 }, switch (kind) {
10384 .derived_pointer_type => .DW_TAG_pointer_type,
10385 .derived_member_type => .DW_TAG_member,
10386 else => unreachable,
10387 }),
10388 .name = switch (extra.name) {
10389 .none => null,
10390 else => extra.name,
10391 },
10392 .scope = extra.scope,
10393 .file = null,
10394 .line = null,
10395 .baseType = extra.underlying_type,
10396 .size = extra.bitSize(),
10397 .@"align" = extra.bitAlign(),
10398 .offset = switch (extra.bitOffset()) {
10399 0 => null,
10400 else => |bit_offset| bit_offset,
10401 },
10402 .flags = null,
10403 .extraData = null,
10404 .dwarfAddressSpace = null,
10405 .annotations = null,
10406 }, writer);
10407 },
10408 .subroutine_type => {
10409 const extra = self.metadataExtraData(Metadata.SubroutineType, metadata_item.data);
10410 try metadata_formatter.specialized(.@"!", .DISubroutineType, .{
10411 .flags = null,
10412 .cc = null,
10413 .types = extra.types_tuple,
10414 }, writer);
10415 },
10416 .enumerator_unsigned,
10417 .enumerator_signed_positive,
10418 .enumerator_signed_negative,
10419 => |kind| {
10420 const extra = self.metadataExtraData(Metadata.Enumerator, metadata_item.data);
10421
10422 const ExpectedContents = extern struct {
10423 const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
10424 string: [
10425 (std.math.big.int.Const{
10426 .limbs = &([1]std.math.big.Limb{
10427 std.math.maxInt(std.math.big.Limb),
10428 } ** expected_limbs),
10429 .positive = false,
10430 }).sizeInBaseUpperBound(10)
10431 ]u8,
10432 limbs: [
10433 std.math.big.int.calcToStringLimbsBufferLen(expected_limbs, 10)
10434 ]std.math.big.Limb,
10435 };
10436 var stack align(@alignOf(ExpectedContents)) =
10437 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
10438 const allocator = stack.get();
10439
10440 const limbs = self.metadata_limbs.items[extra.limbs_index..][0..extra.limbs_len];
10441 const bigint: std.math.big.int.Const = .{
10442 .limbs = limbs,
10443 .positive = switch (kind) {
10444 .enumerator_unsigned,
10445 .enumerator_signed_positive,
10446 => true,
10447 .enumerator_signed_negative => false,
10448 else => unreachable,
10449 },
10450 };
10451 const str = try bigint.toStringAlloc(allocator, 10, undefined);
10452 defer allocator.free(str);
10453
10454 try metadata_formatter.specialized(.@"!", .DIEnumerator, .{
10455 .name = extra.name,
10456 .value = str,
10457 .isUnsigned = switch (kind) {
10458 .enumerator_unsigned => true,
10459 .enumerator_signed_positive,
10460 .enumerator_signed_negative,
10461 => false,
10462 else => unreachable,
10463 },
10464 }, writer);
10465 },
10466 .subrange => {
10467 const extra = self.metadataExtraData(Metadata.Subrange, metadata_item.data);
10468 try metadata_formatter.specialized(.@"!", .DISubrange, .{
10469 .count = extra.count,
10470 .lowerBound = extra.lower_bound,
10471 .upperBound = null,
10472 .stride = null,
10473 }, writer);
10474 },
10475 .tuple => {
10476 var extra = self.metadataExtraDataTrail(Metadata.Tuple, metadata_item.data);
10477 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
10478 try writer.writeAll("!{");
10479 for (elements) |element| try writer.print("{[element]%}", .{
10480 .element = try metadata_formatter.fmt("", element),
10481 });
10482 try writer.writeAll("}\n");
10483 },
10484 .str_tuple => {
10485 var extra = self.metadataExtraDataTrail(Metadata.StrTuple, metadata_item.data);
10486 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
10487 try writer.print("!{{{[str]%}", .{
10488 .str = try metadata_formatter.fmt("", extra.data.str),
10489 });
10490 for (elements) |element| try writer.print("{[element]%}", .{
10491 .element = try metadata_formatter.fmt("", element),
10492 });
10493 try writer.writeAll("}\n");
10494 },
10495 .module_flag => {
10496 const extra = self.metadataExtraData(Metadata.ModuleFlag, metadata_item.data);
10497 try writer.print("!{{{[behavior]%}{[name]%}{[constant]%}}}\n", .{
10498 .behavior = try metadata_formatter.fmt("", extra.behavior),
10499 .name = try metadata_formatter.fmt("", extra.name),
10500 .constant = try metadata_formatter.fmt("", extra.constant),
10501 });
10502 },
10503 .local_var => {
10504 const extra = self.metadataExtraData(Metadata.LocalVar, metadata_item.data);
10505 try metadata_formatter.specialized(.@"!", .DILocalVariable, .{
10506 .name = extra.name,
10507 .arg = null,
10508 .scope = extra.scope,
10509 .file = extra.file,
10510 .line = extra.line,
10511 .type = extra.ty,
10512 .flags = null,
10513 .@"align" = null,
10514 .annotations = null,
10515 }, writer);
10516 },
10517 .parameter => {
10518 const extra = self.metadataExtraData(Metadata.Parameter, metadata_item.data);
10519 try metadata_formatter.specialized(.@"!", .DILocalVariable, .{
10520 .name = extra.name,
10521 .arg = extra.arg_no,
10522 .scope = extra.scope,
10523 .file = extra.file,
10524 .line = extra.line,
10525 .type = extra.ty,
10526 .flags = null,
10527 .@"align" = null,
10528 .annotations = null,
10529 }, writer);
10530 },
10531 .global_var,
10532 .@"global_var local",
10533 => |kind| {
10534 const extra = self.metadataExtraData(Metadata.GlobalVar, metadata_item.data);
10535 try metadata_formatter.specialized(.@"distinct !", .DIGlobalVariable, .{
10536 .name = extra.name,
10537 .linkageName = extra.linkage_name,
10538 .scope = extra.scope,
10539 .file = extra.file,
10540 .line = extra.line,
10541 .type = extra.ty,
10542 .isLocal = switch (kind) {
10543 .global_var => false,
10544 .@"global_var local" => true,
10545 else => unreachable,
10546 },
10547 .isDefinition = true,
10548 .declaration = null,
10549 .templateParams = null,
10550 .@"align" = null,
10551 .annotations = null,
10552 }, writer);
10553 },
10554 .global_var_expression => {
10555 const extra =
10556 self.metadataExtraData(Metadata.GlobalVarExpression, metadata_item.data);
10557 try metadata_formatter.specialized(.@"!", .DIGlobalVariableExpression, .{
10558 .@"var" = extra.variable,
10559 .expr = extra.expression,
10560 }, writer);
10561 },
10562 }
10563 }
10564 }
10565}
10566
10567const NoExtra = struct {};
10568
10569fn isValidIdentifier(id: []const u8) bool {
10570 for (id, 0..) |byte, index| switch (byte) {
10571 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
10572 '0'...'9' => if (index == 0) return false,
10573 else => return false,
10574 };
10575 return true;
10576}
10577
10578const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier };
10579fn printEscapedString(
10580 slice: []const u8,
10581 quotes: QuoteBehavior,
10582 writer: anytype,
10583) @TypeOf(writer).Error!void {
10584 const need_quotes = switch (quotes) {
10585 .always_quote => true,
10586 .quote_unless_valid_identifier => !isValidIdentifier(slice),
10587 };
10588 if (need_quotes) try writer.writeByte('"');
10589 for (slice) |byte| switch (byte) {
10590 '\\' => try writer.writeAll("\\\\"),
10591 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte),
10592 else => try writer.print("\\{X:0>2}", .{byte}),
10593 };
10594 if (need_quotes) try writer.writeByte('"');
10595}
10596
10597fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void {
10598 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
10599 if (name.slice(self)) |id| {
10600 const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});
10601 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
10602 }
10603 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
10604 try self.globals.ensureUnusedCapacity(self.gpa, 1);
10605 try self.next_unique_global_id.ensureUnusedCapacity(self.gpa, 1);
10606}
10607
10608fn fnTypeAssumeCapacity(
10609 self: *Builder,
10610 ret: Type,
10611 params: []const Type,
10612 comptime kind: Type.Function.Kind,
10613) Type {
10614 const tag: Type.Tag = switch (kind) {
10615 .normal => .function,
10616 .vararg => .vararg_function,
10617 };
10618 const Key = struct { ret: Type, params: []const Type };
10619 const Adapter = struct {
10620 builder: *const Builder,
10621 pub fn hash(_: @This(), key: Key) u32 {
10622 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
10623 hasher.update(std.mem.asBytes(&key.ret));
10624 hasher.update(std.mem.sliceAsBytes(key.params));
10625 return @truncate(hasher.final());
10626 }
10627 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
10628 const rhs_data = ctx.builder.type_items.items[rhs_index];
10629 if (rhs_data.tag != tag) return false;
10630 var rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data);
10631 const rhs_params = rhs_extra.trail.next(rhs_extra.data.params_len, Type, ctx.builder);
10632 return lhs_key.ret == rhs_extra.data.ret and std.mem.eql(Type, lhs_key.params, rhs_params);
10633 }
10634 };
10635 const gop = self.type_map.getOrPutAssumeCapacityAdapted(
10636 Key{ .ret = ret, .params = params },
10637 Adapter{ .builder = self },
10638 );
10639 if (!gop.found_existing) {
10640 gop.key_ptr.* = {};
10641 gop.value_ptr.* = {};
10642 self.type_items.appendAssumeCapacity(.{
10643 .tag = tag,
10644 .data = self.addTypeExtraAssumeCapacity(Type.Function{
10645 .ret = ret,
10646 .params_len = @intCast(params.len),
10647 }),
10648 });
10649 self.type_extra.appendSliceAssumeCapacity(@ptrCast(params));
10650 }
10651 return @enumFromInt(gop.index);
10652}
10653
10654fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
10655 assert(bits > 0);
10656 const result = self.getOrPutTypeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
10657 return result.type;
10658}
10659
10660fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {
10661 const result = self.getOrPutTypeNoExtraAssumeCapacity(
10662 .{ .tag = .pointer, .data = @intFromEnum(addr_space) },
10663 );
10664 return result.type;
10665}
10666
10667fn vectorTypeAssumeCapacity(
10668 self: *Builder,
10669 comptime kind: Type.Vector.Kind,
10670 len: u32,
10671 child: Type,
10672) Type {
10673 assert(child.isFloatingPoint() or child.isInteger(self) or child.isPointer(self));
10674 const tag: Type.Tag = switch (kind) {
10675 .normal => .vector,
10676 .scalable => .scalable_vector,
10677 };
10678 const Adapter = struct {
10679 builder: *const Builder,
10680 pub fn hash(_: @This(), key: Type.Vector) u32 {
10681 return @truncate(std.hash.Wyhash.hash(
10682 comptime std.hash.uint32(@intFromEnum(tag)),
10683 std.mem.asBytes(&key),
10684 ));
10685 }
10686 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
10687 const rhs_data = ctx.builder.type_items.items[rhs_index];
10688 return rhs_data.tag == tag and
10689 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
10690 }
10691 };
10692 const data = Type.Vector{ .len = len, .child = child };
10693 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10694 if (!gop.found_existing) {
10695 gop.key_ptr.* = {};
10696 gop.value_ptr.* = {};
10697 self.type_items.appendAssumeCapacity(.{
10698 .tag = tag,
10699 .data = self.addTypeExtraAssumeCapacity(data),
10700 });
10701 }
10702 return @enumFromInt(gop.index);
10703}
10704
10705fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
10706 if (std.math.cast(u32, len)) |small_len| {
10707 const Adapter = struct {
10708 builder: *const Builder,
10709 pub fn hash(_: @This(), key: Type.Vector) u32 {
10710 return @truncate(std.hash.Wyhash.hash(
10711 comptime std.hash.uint32(@intFromEnum(Type.Tag.small_array)),
10712 std.mem.asBytes(&key),
10713 ));
10714 }
10715 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
10716 const rhs_data = ctx.builder.type_items.items[rhs_index];
10717 return rhs_data.tag == .small_array and
10718 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
10719 }
10720 };
10721 const data = Type.Vector{ .len = small_len, .child = child };
10722 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10723 if (!gop.found_existing) {
10724 gop.key_ptr.* = {};
10725 gop.value_ptr.* = {};
10726 self.type_items.appendAssumeCapacity(.{
10727 .tag = .small_array,
10728 .data = self.addTypeExtraAssumeCapacity(data),
10729 });
10730 }
10731 return @enumFromInt(gop.index);
10732 } else {
10733 const Adapter = struct {
10734 builder: *const Builder,
10735 pub fn hash(_: @This(), key: Type.Array) u32 {
10736 return @truncate(std.hash.Wyhash.hash(
10737 comptime std.hash.uint32(@intFromEnum(Type.Tag.array)),
10738 std.mem.asBytes(&key),
10739 ));
10740 }
10741 pub fn eql(ctx: @This(), lhs_key: Type.Array, _: void, rhs_index: usize) bool {
10742 const rhs_data = ctx.builder.type_items.items[rhs_index];
10743 return rhs_data.tag == .array and
10744 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Array, rhs_data.data));
10745 }
10746 };
10747 const data = Type.Array{
10748 .len_lo = @truncate(len),
10749 .len_hi = @intCast(len >> 32),
10750 .child = child,
10751 };
10752 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10753 if (!gop.found_existing) {
10754 gop.key_ptr.* = {};
10755 gop.value_ptr.* = {};
10756 self.type_items.appendAssumeCapacity(.{
10757 .tag = .array,
10758 .data = self.addTypeExtraAssumeCapacity(data),
10759 });
10760 }
10761 return @enumFromInt(gop.index);
10762 }
10763}
10764
10765fn structTypeAssumeCapacity(
10766 self: *Builder,
10767 comptime kind: Type.Structure.Kind,
10768 fields: []const Type,
10769) Type {
10770 const tag: Type.Tag = switch (kind) {
10771 .normal => .structure,
10772 .@"packed" => .packed_structure,
10773 };
10774 const Adapter = struct {
10775 builder: *const Builder,
10776 pub fn hash(_: @This(), key: []const Type) u32 {
10777 return @truncate(std.hash.Wyhash.hash(
10778 comptime std.hash.uint32(@intFromEnum(tag)),
10779 std.mem.sliceAsBytes(key),
10780 ));
10781 }
10782 pub fn eql(ctx: @This(), lhs_key: []const Type, _: void, rhs_index: usize) bool {
10783 const rhs_data = ctx.builder.type_items.items[rhs_index];
10784 if (rhs_data.tag != tag) return false;
10785 var rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data);
10786 const rhs_fields = rhs_extra.trail.next(rhs_extra.data.fields_len, Type, ctx.builder);
10787 return std.mem.eql(Type, lhs_key, rhs_fields);
10788 }
10789 };
10790 const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self });
10791 if (!gop.found_existing) {
10792 gop.key_ptr.* = {};
10793 gop.value_ptr.* = {};
10794 self.type_items.appendAssumeCapacity(.{
10795 .tag = tag,
10796 .data = self.addTypeExtraAssumeCapacity(Type.Structure{
10797 .fields_len = @intCast(fields.len),
10798 }),
10799 });
10800 self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
10801 }
10802 return @enumFromInt(gop.index);
10803}
10804
10805fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
10806 const Adapter = struct {
10807 builder: *const Builder,
10808 pub fn hash(_: @This(), key: String) u32 {
10809 return @truncate(std.hash.Wyhash.hash(
10810 comptime std.hash.uint32(@intFromEnum(Type.Tag.named_structure)),
10811 std.mem.asBytes(&key),
10812 ));
10813 }
10814 pub fn eql(ctx: @This(), lhs_key: String, _: void, rhs_index: usize) bool {
10815 const rhs_data = ctx.builder.type_items.items[rhs_index];
10816 return rhs_data.tag == .named_structure and
10817 lhs_key == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
10818 }
10819 };
10820 var id = name;
10821 if (name == .empty) {
10822 id = self.next_unnamed_type;
10823 assert(id != .none);
10824 self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1);
10825 } else assert(!name.isAnon());
10826 while (true) {
10827 const type_gop = self.types.getOrPutAssumeCapacity(id);
10828 if (!type_gop.found_existing) {
10829 const gop = self.type_map.getOrPutAssumeCapacityAdapted(id, Adapter{ .builder = self });
10830 assert(!gop.found_existing);
10831 gop.key_ptr.* = {};
10832 gop.value_ptr.* = {};
10833 self.type_items.appendAssumeCapacity(.{
10834 .tag = .named_structure,
10835 .data = self.addTypeExtraAssumeCapacity(Type.NamedStructure{
10836 .id = id,
10837 .body = .none,
10838 }),
10839 });
10840 const result: Type = @enumFromInt(gop.index);
10841 type_gop.value_ptr.* = result;
10842 return result;
10843 }
10844
10845 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
10846 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
10847 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
10848 unique_gop.value_ptr.* += 1;
10849 }
10850}
10851
10852fn ensureUnusedTypeCapacity(
10853 self: *Builder,
10854 count: usize,
10855 comptime Extra: type,
10856 trail_len: usize,
10857) Allocator.Error!void {
10858 try self.type_map.ensureUnusedCapacity(self.gpa, count);
10859 try self.type_items.ensureUnusedCapacity(self.gpa, count);
10860 try self.type_extra.ensureUnusedCapacity(
10861 self.gpa,
10862 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
10863 );
10864}
10865
10866fn getOrPutTypeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {
10867 const Adapter = struct {
10868 builder: *const Builder,
10869 pub fn hash(_: @This(), key: Type.Item) u32 {
10870 return @truncate(std.hash.Wyhash.hash(
10871 comptime std.hash.uint32(@intFromEnum(Type.Tag.simple)),
10872 std.mem.asBytes(&key),
10873 ));
10874 }
10875 pub fn eql(ctx: @This(), lhs_key: Type.Item, _: void, rhs_index: usize) bool {
10876 const lhs_bits: u32 = @bitCast(lhs_key);
10877 const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]);
10878 return lhs_bits == rhs_bits;
10879 }
10880 };
10881 const gop = self.type_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
10882 if (!gop.found_existing) {
10883 gop.key_ptr.* = {};
10884 gop.value_ptr.* = {};
10885 self.type_items.appendAssumeCapacity(item);
10886 }
10887 return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) };
10888}
10889
10890fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.Item.ExtraIndex {
10891 const result: Type.Item.ExtraIndex = @intCast(self.type_extra.items.len);
10892 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
10893 const value = @field(extra, field.name);
10894 self.type_extra.appendAssumeCapacity(switch (field.type) {
10895 u32 => value,
10896 String, Type => @intFromEnum(value),
10897 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
10898 });
10899 }
10900 return result;
10901}
10902
10903const TypeExtraDataTrail = struct {
10904 index: Type.Item.ExtraIndex,
10905
10906 fn nextMut(self: *TypeExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
10907 const items: []Item = @ptrCast(builder.type_extra.items[self.index..][0..len]);
10908 self.index += @intCast(len);
10909 return items;
10910 }
10911
10912 fn next(
10913 self: *TypeExtraDataTrail,
10914 len: u32,
10915 comptime Item: type,
10916 builder: *const Builder,
10917 ) []const Item {
10918 const items: []const Item = @ptrCast(builder.type_extra.items[self.index..][0..len]);
10919 self.index += @intCast(len);
10920 return items;
10921 }
10922};
10923
10924fn typeExtraDataTrail(
10925 self: *const Builder,
10926 comptime T: type,
10927 index: Type.Item.ExtraIndex,
10928) struct { data: T, trail: TypeExtraDataTrail } {
10929 var result: T = undefined;
10930 const fields = @typeInfo(T).@"struct".fields;
10931 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, value|
10932 @field(result, field.name) = switch (field.type) {
10933 u32 => value,
10934 String, Type => @enumFromInt(value),
10935 else => @compileError("bad field type: " ++ @typeName(field.type)),
10936 };
10937 return .{
10938 .data = result,
10939 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
10940 };
10941}
10942
10943fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraIndex) T {
10944 return self.typeExtraDataTrail(T, index).data;
10945}
10946
10947fn attrGeneric(self: *Builder, data: []const u32) Allocator.Error!u32 {
10948 try self.attributes_map.ensureUnusedCapacity(self.gpa, 1);
10949 try self.attributes_indices.ensureUnusedCapacity(self.gpa, 1);
10950 try self.attributes_extra.ensureUnusedCapacity(self.gpa, data.len);
10951
10952 const Adapter = struct {
10953 builder: *const Builder,
10954 pub fn hash(_: @This(), key: []const u32) u32 {
10955 return @truncate(std.hash.Wyhash.hash(1, std.mem.sliceAsBytes(key)));
10956 }
10957 pub fn eql(ctx: @This(), lhs_key: []const u32, _: void, rhs_index: usize) bool {
10958 const start = ctx.builder.attributes_indices.items[rhs_index];
10959 const end = ctx.builder.attributes_indices.items[rhs_index + 1];
10960 return std.mem.eql(u32, lhs_key, ctx.builder.attributes_extra.items[start..end]);
10961 }
10962 };
10963 const gop = self.attributes_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10964 if (!gop.found_existing) {
10965 self.attributes_extra.appendSliceAssumeCapacity(data);
10966 self.attributes_indices.appendAssumeCapacity(@intCast(self.attributes_extra.items.len));
10967 }
10968 return @intCast(gop.index);
10969}
10970
10971fn bigIntConstAssumeCapacity(
10972 self: *Builder,
10973 ty: Type,
10974 value: std.math.big.int.Const,
10975) Allocator.Error!Constant {
10976 const type_item = self.type_items.items[@intFromEnum(ty)];
10977 assert(type_item.tag == .integer);
10978 const bits = type_item.data;
10979
10980 const ExpectedContents = [64 / @sizeOf(std.math.big.Limb)]std.math.big.Limb;
10981 var stack align(@alignOf(ExpectedContents)) =
10982 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
10983 const allocator = stack.get();
10984
10985 var limbs: []std.math.big.Limb = &.{};
10986 defer allocator.free(limbs);
10987 const canonical_value = if (value.fitsInTwosComp(.signed, bits)) value else canon: {
10988 assert(value.fitsInTwosComp(.unsigned, bits));
10989 limbs = try allocator.alloc(std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(bits));
10990 var temp_value = std.math.big.int.Mutable.init(limbs, 0);
10991 temp_value.truncate(value, .signed, bits);
10992 break :canon temp_value.toConst();
10993 };
10994 assert(canonical_value.fitsInTwosComp(.signed, bits));
10995
10996 const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer;
10997 const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb };
10998 const tag: Constant.Tag = switch (canonical_value.positive) {
10999 true => .positive_integer,
11000 false => .negative_integer,
11001 };
11002 const Adapter = struct {
11003 builder: *const Builder,
11004 pub fn hash(_: @This(), key: Key) u32 {
11005 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
11006 hasher.update(std.mem.asBytes(&key.type));
11007 hasher.update(std.mem.sliceAsBytes(key.limbs));
11008 return @truncate(hasher.final());
11009 }
11010 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11011 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11012 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11013 const rhs_extra: ExtraPtr =
11014 @ptrCast(ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs]);
11015 const rhs_limbs = ctx.builder.constant_limbs
11016 .items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len];
11017 return lhs_key.type == rhs_extra.type and
11018 std.mem.eql(std.math.big.Limb, lhs_key.limbs, rhs_limbs);
11019 }
11020 };
11021
11022 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
11023 Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs },
11024 Adapter{ .builder = self },
11025 );
11026 if (!gop.found_existing) {
11027 gop.key_ptr.* = {};
11028 gop.value_ptr.* = {};
11029 self.constant_items.appendAssumeCapacity(.{
11030 .tag = tag,
11031 .data = @intCast(self.constant_limbs.items.len),
11032 });
11033 const extra: ExtraPtr =
11034 @ptrCast(self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs));
11035 extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) };
11036 self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs);
11037 }
11038 return @enumFromInt(gop.index);
11039}
11040
11041fn halfConstAssumeCapacity(self: *Builder, val: f16) Constant {
11042 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11043 .{ .tag = .half, .data = @as(u16, @bitCast(val)) },
11044 );
11045 return result.constant;
11046}
11047
11048fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant {
11049 assert(@as(u16, @truncate(@as(u32, @bitCast(val)))) == 0);
11050 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11051 .{ .tag = .bfloat, .data = @bitCast(val) },
11052 );
11053 return result.constant;
11054}
11055
11056fn floatConstAssumeCapacity(self: *Builder, val: f32) Constant {
11057 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11058 .{ .tag = .float, .data = @bitCast(val) },
11059 );
11060 return result.constant;
11061}
11062
11063fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant {
11064 const Adapter = struct {
11065 builder: *const Builder,
11066 pub fn hash(_: @This(), key: f64) u32 {
11067 return @truncate(std.hash.Wyhash.hash(
11068 comptime std.hash.uint32(@intFromEnum(Constant.Tag.double)),
11069 std.mem.asBytes(&key),
11070 ));
11071 }
11072 pub fn eql(ctx: @This(), lhs_key: f64, _: void, rhs_index: usize) bool {
11073 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .double) return false;
11074 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11075 const rhs_extra = ctx.builder.constantExtraData(Constant.Double, rhs_data);
11076 return @as(u64, @bitCast(lhs_key)) == @as(u64, rhs_extra.hi) << 32 | rhs_extra.lo;
11077 }
11078 };
11079 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11080 if (!gop.found_existing) {
11081 gop.key_ptr.* = {};
11082 gop.value_ptr.* = {};
11083 self.constant_items.appendAssumeCapacity(.{
11084 .tag = .double,
11085 .data = self.addConstantExtraAssumeCapacity(Constant.Double{
11086 .lo = @truncate(@as(u64, @bitCast(val))),
11087 .hi = @intCast(@as(u64, @bitCast(val)) >> 32),
11088 }),
11089 });
11090 }
11091 return @enumFromInt(gop.index);
11092}
11093
11094fn fp128ConstAssumeCapacity(self: *Builder, val: f128) Constant {
11095 const Adapter = struct {
11096 builder: *const Builder,
11097 pub fn hash(_: @This(), key: f128) u32 {
11098 return @truncate(std.hash.Wyhash.hash(
11099 comptime std.hash.uint32(@intFromEnum(Constant.Tag.fp128)),
11100 std.mem.asBytes(&key),
11101 ));
11102 }
11103 pub fn eql(ctx: @This(), lhs_key: f128, _: void, rhs_index: usize) bool {
11104 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fp128) return false;
11105 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11106 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
11107 return @as(u128, @bitCast(lhs_key)) == @as(u128, rhs_extra.hi_hi) << 96 |
11108 @as(u128, rhs_extra.hi_lo) << 64 | @as(u128, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
11109 }
11110 };
11111 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11112 if (!gop.found_existing) {
11113 gop.key_ptr.* = {};
11114 gop.value_ptr.* = {};
11115 self.constant_items.appendAssumeCapacity(.{
11116 .tag = .fp128,
11117 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
11118 .lo_lo = @truncate(@as(u128, @bitCast(val))),
11119 .lo_hi = @truncate(@as(u128, @bitCast(val)) >> 32),
11120 .hi_lo = @truncate(@as(u128, @bitCast(val)) >> 64),
11121 .hi_hi = @intCast(@as(u128, @bitCast(val)) >> 96),
11122 }),
11123 });
11124 }
11125 return @enumFromInt(gop.index);
11126}
11127
11128fn x86_fp80ConstAssumeCapacity(self: *Builder, val: f80) Constant {
11129 const Adapter = struct {
11130 builder: *const Builder,
11131 pub fn hash(_: @This(), key: f80) u32 {
11132 return @truncate(std.hash.Wyhash.hash(
11133 comptime std.hash.uint32(@intFromEnum(Constant.Tag.x86_fp80)),
11134 std.mem.asBytes(&key)[0..10],
11135 ));
11136 }
11137 pub fn eql(ctx: @This(), lhs_key: f80, _: void, rhs_index: usize) bool {
11138 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .x86_fp80) return false;
11139 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11140 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp80, rhs_data);
11141 return @as(u80, @bitCast(lhs_key)) == @as(u80, rhs_extra.hi) << 64 |
11142 @as(u80, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
11143 }
11144 };
11145 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11146 if (!gop.found_existing) {
11147 gop.key_ptr.* = {};
11148 gop.value_ptr.* = {};
11149 self.constant_items.appendAssumeCapacity(.{
11150 .tag = .x86_fp80,
11151 .data = self.addConstantExtraAssumeCapacity(Constant.Fp80{
11152 .lo_lo = @truncate(@as(u80, @bitCast(val))),
11153 .lo_hi = @truncate(@as(u80, @bitCast(val)) >> 32),
11154 .hi = @intCast(@as(u80, @bitCast(val)) >> 64),
11155 }),
11156 });
11157 }
11158 return @enumFromInt(gop.index);
11159}
11160
11161fn ppc_fp128ConstAssumeCapacity(self: *Builder, val: [2]f64) Constant {
11162 const Adapter = struct {
11163 builder: *const Builder,
11164 pub fn hash(_: @This(), key: [2]f64) u32 {
11165 return @truncate(std.hash.Wyhash.hash(
11166 comptime std.hash.uint32(@intFromEnum(Constant.Tag.ppc_fp128)),
11167 std.mem.asBytes(&key),
11168 ));
11169 }
11170 pub fn eql(ctx: @This(), lhs_key: [2]f64, _: void, rhs_index: usize) bool {
11171 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .ppc_fp128) return false;
11172 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11173 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
11174 return @as(u64, @bitCast(lhs_key[0])) == @as(u64, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo and
11175 @as(u64, @bitCast(lhs_key[1])) == @as(u64, rhs_extra.hi_hi) << 32 | rhs_extra.hi_lo;
11176 }
11177 };
11178 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11179 if (!gop.found_existing) {
11180 gop.key_ptr.* = {};
11181 gop.value_ptr.* = {};
11182 self.constant_items.appendAssumeCapacity(.{
11183 .tag = .ppc_fp128,
11184 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
11185 .lo_lo = @truncate(@as(u64, @bitCast(val[0]))),
11186 .lo_hi = @intCast(@as(u64, @bitCast(val[0])) >> 32),
11187 .hi_lo = @truncate(@as(u64, @bitCast(val[1]))),
11188 .hi_hi = @intCast(@as(u64, @bitCast(val[1])) >> 32),
11189 }),
11190 });
11191 }
11192 return @enumFromInt(gop.index);
11193}
11194
11195fn nullConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11196 assert(self.type_items.items[@intFromEnum(ty)].tag == .pointer);
11197 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11198 .{ .tag = .null, .data = @intFromEnum(ty) },
11199 );
11200 return result.constant;
11201}
11202
11203fn noneConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11204 assert(ty == .token);
11205 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11206 .{ .tag = .none, .data = @intFromEnum(ty) },
11207 );
11208 return result.constant;
11209}
11210
11211fn structConstAssumeCapacity(self: *Builder, ty: Type, vals: []const Constant) Constant {
11212 const type_item = self.type_items.items[@intFromEnum(ty)];
11213 var extra = self.typeExtraDataTrail(Type.Structure, switch (type_item.tag) {
11214 .structure, .packed_structure => type_item.data,
11215 .named_structure => data: {
11216 const body_ty = self.typeExtraData(Type.NamedStructure, type_item.data).body;
11217 const body_item = self.type_items.items[@intFromEnum(body_ty)];
11218 switch (body_item.tag) {
11219 .structure, .packed_structure => break :data body_item.data,
11220 else => unreachable,
11221 }
11222 },
11223 else => unreachable,
11224 });
11225 const fields = extra.trail.next(extra.data.fields_len, Type, self);
11226 for (fields, vals) |field, val| assert(field == val.typeOf(self));
11227
11228 for (vals) |val| {
11229 if (!val.isZeroInit(self)) break;
11230 } else return self.zeroInitConstAssumeCapacity(ty);
11231
11232 const tag: Constant.Tag = switch (ty.unnamedTag(self)) {
11233 .structure => .structure,
11234 .packed_structure => .packed_structure,
11235 else => unreachable,
11236 };
11237 const result = self.getOrPutConstantAggregateAssumeCapacity(tag, ty, vals);
11238 return result.constant;
11239}
11240
11241fn arrayConstAssumeCapacity(self: *Builder, ty: Type, vals: []const Constant) Constant {
11242 const type_item = self.type_items.items[@intFromEnum(ty)];
11243 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
11244 inline .small_array, .array => |kind| extra: {
11245 const extra = self.typeExtraData(switch (kind) {
11246 .small_array => Type.Vector,
11247 .array => Type.Array,
11248 else => unreachable,
11249 }, type_item.data);
11250 break :extra .{ .len = extra.length(), .child = extra.child };
11251 },
11252 else => unreachable,
11253 };
11254 assert(type_extra.len == vals.len);
11255 for (vals) |val| assert(type_extra.child == val.typeOf(self));
11256
11257 for (vals) |val| {
11258 if (!val.isZeroInit(self)) break;
11259 } else return self.zeroInitConstAssumeCapacity(ty);
11260
11261 const result = self.getOrPutConstantAggregateAssumeCapacity(.array, ty, vals);
11262 return result.constant;
11263}
11264
11265fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
11266 const slice = val.slice(self).?;
11267 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
11268 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
11269 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11270 .{ .tag = .string, .data = @intFromEnum(val) },
11271 );
11272 return result.constant;
11273}
11274
11275fn vectorConstAssumeCapacity(self: *Builder, ty: Type, vals: []const Constant) Constant {
11276 assert(ty.isVector(self));
11277 assert(ty.vectorLen(self) == vals.len);
11278 for (vals) |val| assert(ty.childType(self) == val.typeOf(self));
11279
11280 for (vals[1..]) |val| {
11281 if (vals[0] != val) break;
11282 } else return self.splatConstAssumeCapacity(ty, vals[0]);
11283 for (vals) |val| {
11284 if (!val.isZeroInit(self)) break;
11285 } else return self.zeroInitConstAssumeCapacity(ty);
11286
11287 const result = self.getOrPutConstantAggregateAssumeCapacity(.vector, ty, vals);
11288 return result.constant;
11289}
11290
11291fn splatConstAssumeCapacity(self: *Builder, ty: Type, val: Constant) Constant {
11292 assert(ty.scalarType(self) == val.typeOf(self));
11293
11294 if (!ty.isVector(self)) return val;
11295 if (val.isZeroInit(self)) return self.zeroInitConstAssumeCapacity(ty);
11296
11297 const Adapter = struct {
11298 builder: *const Builder,
11299 pub fn hash(_: @This(), key: Constant.Splat) u32 {
11300 return @truncate(std.hash.Wyhash.hash(
11301 comptime std.hash.uint32(@intFromEnum(Constant.Tag.splat)),
11302 std.mem.asBytes(&key),
11303 ));
11304 }
11305 pub fn eql(ctx: @This(), lhs_key: Constant.Splat, _: void, rhs_index: usize) bool {
11306 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .splat) return false;
11307 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11308 const rhs_extra = ctx.builder.constantExtraData(Constant.Splat, rhs_data);
11309 return std.meta.eql(lhs_key, rhs_extra);
11310 }
11311 };
11312 const data = Constant.Splat{ .type = ty, .value = val };
11313 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11314 if (!gop.found_existing) {
11315 gop.key_ptr.* = {};
11316 gop.value_ptr.* = {};
11317 self.constant_items.appendAssumeCapacity(.{
11318 .tag = .splat,
11319 .data = self.addConstantExtraAssumeCapacity(data),
11320 });
11321 }
11322 return @enumFromInt(gop.index);
11323}
11324
11325fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11326 switch (ty) {
11327 inline .half,
11328 .bfloat,
11329 .float,
11330 .double,
11331 .fp128,
11332 .x86_fp80,
11333 => |tag| return @field(Builder, @tagName(tag) ++ "ConstAssumeCapacity")(self, 0.0),
11334 .ppc_fp128 => return self.ppc_fp128ConstAssumeCapacity(.{ 0.0, 0.0 }),
11335 .token => return .none,
11336 .i1 => return .false,
11337 else => switch (self.type_items.items[@intFromEnum(ty)].tag) {
11338 .simple,
11339 .function,
11340 .vararg_function,
11341 => unreachable,
11342 .integer => {
11343 var limbs: [std.math.big.int.calcLimbLen(0)]std.math.big.Limb = undefined;
11344 const bigint = std.math.big.int.Mutable.init(&limbs, 0);
11345 return self.bigIntConstAssumeCapacity(ty, bigint.toConst()) catch unreachable;
11346 },
11347 .pointer => return self.nullConstAssumeCapacity(ty),
11348 .target,
11349 .vector,
11350 .scalable_vector,
11351 .small_array,
11352 .array,
11353 .structure,
11354 .packed_structure,
11355 .named_structure,
11356 => {},
11357 },
11358 }
11359 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11360 .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) },
11361 );
11362 return result.constant;
11363}
11364
11365fn undefConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11366 switch (self.type_items.items[@intFromEnum(ty)].tag) {
11367 .simple => switch (ty) {
11368 .void, .label => unreachable,
11369 else => {},
11370 },
11371 .function, .vararg_function => unreachable,
11372 else => {},
11373 }
11374 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11375 .{ .tag = .undef, .data = @intFromEnum(ty) },
11376 );
11377 return result.constant;
11378}
11379
11380fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11381 switch (self.type_items.items[@intFromEnum(ty)].tag) {
11382 .simple => switch (ty) {
11383 .void, .label => unreachable,
11384 else => {},
11385 },
11386 .function, .vararg_function => unreachable,
11387 else => {},
11388 }
11389 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11390 .{ .tag = .poison, .data = @intFromEnum(ty) },
11391 );
11392 return result.constant;
11393}
11394
11395fn blockAddrConstAssumeCapacity(
11396 self: *Builder,
11397 function: Function.Index,
11398 block: Function.Block.Index,
11399) Constant {
11400 const Adapter = struct {
11401 builder: *const Builder,
11402 pub fn hash(_: @This(), key: Constant.BlockAddress) u32 {
11403 return @truncate(std.hash.Wyhash.hash(
11404 comptime std.hash.uint32(@intFromEnum(Constant.Tag.blockaddress)),
11405 std.mem.asBytes(&key),
11406 ));
11407 }
11408 pub fn eql(ctx: @This(), lhs_key: Constant.BlockAddress, _: void, rhs_index: usize) bool {
11409 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .blockaddress) return false;
11410 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11411 const rhs_extra = ctx.builder.constantExtraData(Constant.BlockAddress, rhs_data);
11412 return std.meta.eql(lhs_key, rhs_extra);
11413 }
11414 };
11415 const data = Constant.BlockAddress{ .function = function, .block = block };
11416 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11417 if (!gop.found_existing) {
11418 gop.key_ptr.* = {};
11419 gop.value_ptr.* = {};
11420 self.constant_items.appendAssumeCapacity(.{
11421 .tag = .blockaddress,
11422 .data = self.addConstantExtraAssumeCapacity(data),
11423 });
11424 }
11425 return @enumFromInt(gop.index);
11426}
11427
11428fn dsoLocalEquivalentConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
11429 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11430 .{ .tag = .dso_local_equivalent, .data = @intFromEnum(function) },
11431 );
11432 return result.constant;
11433}
11434
11435fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
11436 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11437 .{ .tag = .no_cfi, .data = @intFromEnum(function) },
11438 );
11439 return result.constant;
11440}
11441
11442fn convTag(
11443 self: *Builder,
11444 signedness: Constant.Cast.Signedness,
11445 val_ty: Type,
11446 ty: Type,
11447) Function.Instruction.Tag {
11448 assert(val_ty != ty);
11449 return switch (val_ty.scalarTag(self)) {
11450 .simple => switch (ty.scalarTag(self)) {
11451 .simple => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
11452 .lt => .fpext,
11453 .eq => unreachable,
11454 .gt => .fptrunc,
11455 },
11456 .integer => switch (signedness) {
11457 .unsigned => .fptoui,
11458 .signed => .fptosi,
11459 .unneeded => unreachable,
11460 },
11461 else => unreachable,
11462 },
11463 .integer => switch (ty.scalarTag(self)) {
11464 .simple => switch (signedness) {
11465 .unsigned => .uitofp,
11466 .signed => .sitofp,
11467 .unneeded => unreachable,
11468 },
11469 .integer => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
11470 .lt => switch (signedness) {
11471 .unsigned => .zext,
11472 .signed => .sext,
11473 .unneeded => unreachable,
11474 },
11475 .eq => unreachable,
11476 .gt => .trunc,
11477 },
11478 .pointer => .inttoptr,
11479 else => unreachable,
11480 },
11481 .pointer => switch (ty.scalarTag(self)) {
11482 .integer => .ptrtoint,
11483 .pointer => .addrspacecast,
11484 else => unreachable,
11485 },
11486 else => unreachable,
11487 };
11488}
11489
11490fn convConstTag(
11491 self: *Builder,
11492 val_ty: Type,
11493 ty: Type,
11494) Constant.Tag {
11495 assert(val_ty != ty);
11496 return switch (val_ty.scalarTag(self)) {
11497 .integer => switch (ty.scalarTag(self)) {
11498 .integer => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
11499 .gt => .trunc,
11500 else => unreachable,
11501 },
11502 .pointer => .inttoptr,
11503 else => unreachable,
11504 },
11505 .pointer => switch (ty.scalarTag(self)) {
11506 .integer => .ptrtoint,
11507 .pointer => .addrspacecast,
11508 else => unreachable,
11509 },
11510 else => unreachable,
11511 };
11512}
11513
11514fn convConstAssumeCapacity(
11515 self: *Builder,
11516 val: Constant,
11517 ty: Type,
11518) Constant {
11519 const val_ty = val.typeOf(self);
11520 if (val_ty == ty) return val;
11521 return self.castConstAssumeCapacity(self.convConstTag(val_ty, ty), val, ty);
11522}
11523
11524fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Constant {
11525 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };
11526 const Adapter = struct {
11527 builder: *const Builder,
11528 pub fn hash(_: @This(), key: Key) u32 {
11529 return @truncate(std.hash.Wyhash.hash(
11530 std.hash.uint32(@intFromEnum(key.tag)),
11531 std.mem.asBytes(&key.cast),
11532 ));
11533 }
11534 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11535 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11536 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11537 const rhs_extra = ctx.builder.constantExtraData(Constant.Cast, rhs_data);
11538 return std.meta.eql(lhs_key.cast, rhs_extra);
11539 }
11540 };
11541 const data = Key{ .tag = tag, .cast = .{ .val = val, .type = ty } };
11542 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11543 if (!gop.found_existing) {
11544 gop.key_ptr.* = {};
11545 gop.value_ptr.* = {};
11546 self.constant_items.appendAssumeCapacity(.{
11547 .tag = tag,
11548 .data = self.addConstantExtraAssumeCapacity(data.cast),
11549 });
11550 }
11551 return @enumFromInt(gop.index);
11552}
11553
11554fn gepConstAssumeCapacity(
11555 self: *Builder,
11556 comptime kind: Constant.GetElementPtr.Kind,
11557 ty: Type,
11558 base: Constant,
11559 inrange: ?u16,
11560 indices: []const Constant,
11561) Constant {
11562 const tag: Constant.Tag = switch (kind) {
11563 .normal => .getelementptr,
11564 .inbounds => .@"getelementptr inbounds",
11565 };
11566 const base_ty = base.typeOf(self);
11567 const base_is_vector = base_ty.isVector(self);
11568
11569 const VectorInfo = struct {
11570 kind: Type.Vector.Kind,
11571 len: u32,
11572
11573 fn init(vector_ty: Type, builder: *const Builder) @This() {
11574 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
11575 }
11576 };
11577 var vector_info: ?VectorInfo = if (base_is_vector) VectorInfo.init(base_ty, self) else null;
11578 for (indices) |index| {
11579 const index_ty = index.typeOf(self);
11580 switch (index_ty.tag(self)) {
11581 .integer => {},
11582 .vector, .scalable_vector => {
11583 const index_info = VectorInfo.init(index_ty, self);
11584 if (vector_info) |info|
11585 assert(std.meta.eql(info, index_info))
11586 else
11587 vector_info = index_info;
11588 },
11589 else => unreachable,
11590 }
11591 }
11592 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
11593 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
11594 };
11595
11596 const Key = struct {
11597 type: Type,
11598 base: Constant,
11599 inrange: Constant.GetElementPtr.InRangeIndex,
11600 indices: []const Constant,
11601 };
11602 const Adapter = struct {
11603 builder: *const Builder,
11604 pub fn hash(_: @This(), key: Key) u32 {
11605 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
11606 hasher.update(std.mem.asBytes(&key.type));
11607 hasher.update(std.mem.asBytes(&key.base));
11608 hasher.update(std.mem.asBytes(&key.inrange));
11609 hasher.update(std.mem.sliceAsBytes(key.indices));
11610 return @truncate(hasher.final());
11611 }
11612 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11613 if (ctx.builder.constant_items.items(.tag)[rhs_index] != tag) return false;
11614 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11615 var rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
11616 const rhs_indices =
11617 rhs_extra.trail.next(rhs_extra.data.info.indices_len, Constant, ctx.builder);
11618 return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and
11619 lhs_key.inrange == rhs_extra.data.info.inrange and
11620 std.mem.eql(Constant, lhs_key.indices, rhs_indices);
11621 }
11622 };
11623 const data = Key{
11624 .type = ty,
11625 .base = base,
11626 .inrange = if (inrange) |index| @enumFromInt(index) else .none,
11627 .indices = indices,
11628 };
11629 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11630 if (!gop.found_existing) {
11631 gop.key_ptr.* = {};
11632 gop.value_ptr.* = {};
11633 self.constant_items.appendAssumeCapacity(.{
11634 .tag = tag,
11635 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
11636 .type = ty,
11637 .base = base,
11638 .info = .{ .indices_len = @intCast(indices.len), .inrange = data.inrange },
11639 }),
11640 });
11641 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
11642 }
11643 return @enumFromInt(gop.index);
11644}
11645
11646fn binConstAssumeCapacity(
11647 self: *Builder,
11648 tag: Constant.Tag,
11649 lhs: Constant,
11650 rhs: Constant,
11651) Constant {
11652 switch (tag) {
11653 .add,
11654 .@"add nsw",
11655 .@"add nuw",
11656 .sub,
11657 .@"sub nsw",
11658 .@"sub nuw",
11659 .shl,
11660 .xor,
11661 => {},
11662 else => unreachable,
11663 }
11664 const Key = struct { tag: Constant.Tag, extra: Constant.Binary };
11665 const Adapter = struct {
11666 builder: *const Builder,
11667 pub fn hash(_: @This(), key: Key) u32 {
11668 return @truncate(std.hash.Wyhash.hash(
11669 std.hash.uint32(@intFromEnum(key.tag)),
11670 std.mem.asBytes(&key.extra),
11671 ));
11672 }
11673 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11674 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11675 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11676 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
11677 return std.meta.eql(lhs_key.extra, rhs_extra);
11678 }
11679 };
11680 const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } };
11681 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11682 if (!gop.found_existing) {
11683 gop.key_ptr.* = {};
11684 gop.value_ptr.* = {};
11685 self.constant_items.appendAssumeCapacity(.{
11686 .tag = tag,
11687 .data = self.addConstantExtraAssumeCapacity(data.extra),
11688 });
11689 }
11690 return @enumFromInt(gop.index);
11691}
11692
11693fn asmConstAssumeCapacity(
11694 self: *Builder,
11695 ty: Type,
11696 info: Constant.Assembly.Info,
11697 assembly: String,
11698 constraints: String,
11699) Constant {
11700 assert(ty.functionKind(self) == .normal);
11701
11702 const Key = struct { tag: Constant.Tag, extra: Constant.Assembly };
11703 const Adapter = struct {
11704 builder: *const Builder,
11705 pub fn hash(_: @This(), key: Key) u32 {
11706 return @truncate(std.hash.Wyhash.hash(
11707 std.hash.uint32(@intFromEnum(key.tag)),
11708 std.mem.asBytes(&key.extra),
11709 ));
11710 }
11711 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11712 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11713 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11714 const rhs_extra = ctx.builder.constantExtraData(Constant.Assembly, rhs_data);
11715 return std.meta.eql(lhs_key.extra, rhs_extra);
11716 }
11717 };
11718
11719 const data = Key{
11720 .tag = @enumFromInt(@intFromEnum(Constant.Tag.@"asm") + @as(u4, @bitCast(info))),
11721 .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints },
11722 };
11723 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11724 if (!gop.found_existing) {
11725 gop.key_ptr.* = {};
11726 gop.value_ptr.* = {};
11727 self.constant_items.appendAssumeCapacity(.{
11728 .tag = data.tag,
11729 .data = self.addConstantExtraAssumeCapacity(data.extra),
11730 });
11731 }
11732 return @enumFromInt(gop.index);
11733}
11734
11735fn ensureUnusedConstantCapacity(
11736 self: *Builder,
11737 count: usize,
11738 comptime Extra: type,
11739 trail_len: usize,
11740) Allocator.Error!void {
11741 try self.constant_map.ensureUnusedCapacity(self.gpa, count);
11742 try self.constant_items.ensureUnusedCapacity(self.gpa, count);
11743 try self.constant_extra.ensureUnusedCapacity(
11744 self.gpa,
11745 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
11746 );
11747}
11748
11749fn getOrPutConstantNoExtraAssumeCapacity(
11750 self: *Builder,
11751 item: Constant.Item,
11752) struct { new: bool, constant: Constant } {
11753 const Adapter = struct {
11754 builder: *const Builder,
11755 pub fn hash(_: @This(), key: Constant.Item) u32 {
11756 return @truncate(std.hash.Wyhash.hash(
11757 std.hash.uint32(@intFromEnum(key.tag)),
11758 std.mem.asBytes(&key.data),
11759 ));
11760 }
11761 pub fn eql(ctx: @This(), lhs_key: Constant.Item, _: void, rhs_index: usize) bool {
11762 return std.meta.eql(lhs_key, ctx.builder.constant_items.get(rhs_index));
11763 }
11764 };
11765 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
11766 if (!gop.found_existing) {
11767 gop.key_ptr.* = {};
11768 gop.value_ptr.* = {};
11769 self.constant_items.appendAssumeCapacity(item);
11770 }
11771 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
11772}
11773
11774fn getOrPutConstantAggregateAssumeCapacity(
11775 self: *Builder,
11776 tag: Constant.Tag,
11777 ty: Type,
11778 vals: []const Constant,
11779) struct { new: bool, constant: Constant } {
11780 switch (tag) {
11781 .structure, .packed_structure, .array, .vector => {},
11782 else => unreachable,
11783 }
11784 const Key = struct { tag: Constant.Tag, type: Type, vals: []const Constant };
11785 const Adapter = struct {
11786 builder: *const Builder,
11787 pub fn hash(_: @This(), key: Key) u32 {
11788 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
11789 hasher.update(std.mem.asBytes(&key.type));
11790 hasher.update(std.mem.sliceAsBytes(key.vals));
11791 return @truncate(hasher.final());
11792 }
11793 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11794 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11795 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11796 var rhs_extra = ctx.builder.constantExtraDataTrail(Constant.Aggregate, rhs_data);
11797 if (lhs_key.type != rhs_extra.data.type) return false;
11798 const rhs_vals = rhs_extra.trail.next(@intCast(lhs_key.vals.len), Constant, ctx.builder);
11799 return std.mem.eql(Constant, lhs_key.vals, rhs_vals);
11800 }
11801 };
11802 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
11803 Key{ .tag = tag, .type = ty, .vals = vals },
11804 Adapter{ .builder = self },
11805 );
11806 if (!gop.found_existing) {
11807 gop.key_ptr.* = {};
11808 gop.value_ptr.* = {};
11809 self.constant_items.appendAssumeCapacity(.{
11810 .tag = tag,
11811 .data = self.addConstantExtraAssumeCapacity(Constant.Aggregate{ .type = ty }),
11812 });
11813 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(vals));
11814 }
11815 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
11816}
11817
11818fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.ExtraIndex {
11819 const result: Constant.Item.ExtraIndex = @intCast(self.constant_extra.items.len);
11820 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
11821 const value = @field(extra, field.name);
11822 self.constant_extra.appendAssumeCapacity(switch (field.type) {
11823 u32 => value,
11824 String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
11825 Constant.GetElementPtr.Info => @bitCast(value),
11826 else => @compileError("bad field type: " ++ @typeName(field.type)),
11827 });
11828 }
11829 return result;
11830}
11831
11832const ConstantExtraDataTrail = struct {
11833 index: Constant.Item.ExtraIndex,
11834
11835 fn nextMut(self: *ConstantExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
11836 const items: []Item = @ptrCast(builder.constant_extra.items[self.index..][0..len]);
11837 self.index += @intCast(len);
11838 return items;
11839 }
11840
11841 fn next(
11842 self: *ConstantExtraDataTrail,
11843 len: u32,
11844 comptime Item: type,
11845 builder: *const Builder,
11846 ) []const Item {
11847 const items: []const Item = @ptrCast(builder.constant_extra.items[self.index..][0..len]);
11848 self.index += @intCast(len);
11849 return items;
11850 }
11851};
11852
11853fn constantExtraDataTrail(
11854 self: *const Builder,
11855 comptime T: type,
11856 index: Constant.Item.ExtraIndex,
11857) struct { data: T, trail: ConstantExtraDataTrail } {
11858 var result: T = undefined;
11859 const fields = @typeInfo(T).@"struct".fields;
11860 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
11861 @field(result, field.name) = switch (field.type) {
11862 u32 => value,
11863 String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
11864 Constant.GetElementPtr.Info => @bitCast(value),
11865 else => @compileError("bad field type: " ++ @typeName(field.type)),
11866 };
11867 return .{
11868 .data = result,
11869 .trail = .{ .index = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) },
11870 };
11871}
11872
11873fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Item.ExtraIndex) T {
11874 return self.constantExtraDataTrail(T, index).data;
11875}
11876
11877fn ensureUnusedMetadataCapacity(
11878 self: *Builder,
11879 count: usize,
11880 comptime Extra: type,
11881 trail_len: usize,
11882) Allocator.Error!void {
11883 try self.metadata_map.ensureUnusedCapacity(self.gpa, count);
11884 try self.metadata_items.ensureUnusedCapacity(self.gpa, count);
11885 try self.metadata_extra.ensureUnusedCapacity(
11886 self.gpa,
11887 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
11888 );
11889}
11890
11891fn addMetadataExtraAssumeCapacity(self: *Builder, extra: anytype) Metadata.Item.ExtraIndex {
11892 const result: Metadata.Item.ExtraIndex = @intCast(self.metadata_extra.items.len);
11893 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
11894 const value = @field(extra, field.name);
11895 self.metadata_extra.appendAssumeCapacity(switch (field.type) {
11896 u32 => value,
11897 MetadataString, Metadata, Variable.Index, Value => @intFromEnum(value),
11898 Metadata.DIFlags => @bitCast(value),
11899 else => @compileError("bad field type: " ++ @typeName(field.type)),
11900 });
11901 }
11902 return result;
11903}
11904
11905const MetadataExtraDataTrail = struct {
11906 index: Metadata.Item.ExtraIndex,
11907
11908 fn nextMut(self: *MetadataExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
11909 const items: []Item = @ptrCast(builder.metadata_extra.items[self.index..][0..len]);
11910 self.index += @intCast(len);
11911 return items;
11912 }
11913
11914 fn next(
11915 self: *MetadataExtraDataTrail,
11916 len: u32,
11917 comptime Item: type,
11918 builder: *const Builder,
11919 ) []const Item {
11920 const items: []const Item = @ptrCast(builder.metadata_extra.items[self.index..][0..len]);
11921 self.index += @intCast(len);
11922 return items;
11923 }
11924};
11925
11926fn metadataExtraDataTrail(
11927 self: *const Builder,
11928 comptime T: type,
11929 index: Metadata.Item.ExtraIndex,
11930) struct { data: T, trail: MetadataExtraDataTrail } {
11931 var result: T = undefined;
11932 const fields = @typeInfo(T).@"struct".fields;
11933 inline for (fields, self.metadata_extra.items[index..][0..fields.len]) |field, value|
11934 @field(result, field.name) = switch (field.type) {
11935 u32 => value,
11936 MetadataString, Metadata, Variable.Index, Value => @enumFromInt(value),
11937 Metadata.DIFlags => @bitCast(value),
11938 else => @compileError("bad field type: " ++ @typeName(field.type)),
11939 };
11940 return .{
11941 .data = result,
11942 .trail = .{ .index = index + @as(Metadata.Item.ExtraIndex, @intCast(fields.len)) },
11943 };
11944}
11945
11946fn metadataExtraData(self: *const Builder, comptime T: type, index: Metadata.Item.ExtraIndex) T {
11947 return self.metadataExtraDataTrail(T, index).data;
11948}
11949
11950pub fn metadataString(self: *Builder, bytes: []const u8) Allocator.Error!MetadataString {
11951 try self.metadata_string_bytes.ensureUnusedCapacity(self.gpa, bytes.len);
11952 try self.metadata_string_indices.ensureUnusedCapacity(self.gpa, 1);
11953 try self.metadata_string_map.ensureUnusedCapacity(self.gpa, 1);
11954
11955 const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(
11956 bytes,
11957 MetadataString.Adapter{ .builder = self },
11958 );
11959 if (!gop.found_existing) {
11960 self.metadata_string_bytes.appendSliceAssumeCapacity(bytes);
11961 self.metadata_string_indices.appendAssumeCapacity(@intCast(self.metadata_string_bytes.items.len));
11962 }
11963 return @enumFromInt(gop.index);
11964}
11965
11966pub fn metadataStringFromStrtabString(self: *Builder, str: StrtabString) Allocator.Error!MetadataString {
11967 if (str == .none or str == .empty) return MetadataString.none;
11968 return try self.metadataString(str.slice(self).?);
11969}
11970
11971pub fn metadataStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allocator.Error!MetadataString {
11972 try self.metadata_string_map.ensureUnusedCapacity(self.gpa, 1);
11973 try self.metadata_string_bytes.ensureUnusedCapacity(self.gpa, @intCast(std.fmt.count(fmt_str, fmt_args)));
11974 try self.metadata_string_indices.ensureUnusedCapacity(self.gpa, 1);
11975 return self.metadataStringFmtAssumeCapacity(fmt_str, fmt_args);
11976}
11977
11978pub fn metadataStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) MetadataString {
11979 self.metadata_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
11980 return self.trailingMetadataStringAssumeCapacity();
11981}
11982
11983pub fn trailingMetadataString(self: *Builder) Allocator.Error!MetadataString {
11984 try self.metadata_string_indices.ensureUnusedCapacity(self.gpa, 1);
11985 try self.metadata_string_map.ensureUnusedCapacity(self.gpa, 1);
11986 return self.trailingMetadataStringAssumeCapacity();
11987}
11988
11989pub fn trailingMetadataStringAssumeCapacity(self: *Builder) MetadataString {
11990 const start = self.metadata_string_indices.getLast();
11991 const bytes: []const u8 = self.metadata_string_bytes.items[start..];
11992 const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
11993 if (gop.found_existing) {
11994 self.metadata_string_bytes.shrinkRetainingCapacity(start);
11995 } else {
11996 self.metadata_string_indices.appendAssumeCapacity(@intCast(self.metadata_string_bytes.items.len));
11997 }
11998 return @enumFromInt(gop.index);
11999}
12000
12001pub fn metadataNamed(self: *Builder, name: MetadataString, operands: []const Metadata) Allocator.Error!void {
12002 try self.metadata_extra.ensureUnusedCapacity(self.gpa, operands.len);
12003 try self.metadata_named.ensureUnusedCapacity(self.gpa, 1);
12004 self.metadataNamedAssumeCapacity(name, operands);
12005}
12006
12007fn metadataNone(self: *Builder) Allocator.Error!Metadata {
12008 try self.ensureUnusedMetadataCapacity(1, NoExtra, 0);
12009 return self.metadataNoneAssumeCapacity();
12010}
12011
12012pub fn debugFile(
12013 self: *Builder,
12014 filename: MetadataString,
12015 directory: MetadataString,
12016) Allocator.Error!Metadata {
12017 try self.ensureUnusedMetadataCapacity(1, Metadata.File, 0);
12018 return self.debugFileAssumeCapacity(filename, directory);
12019}
12020
12021pub fn debugCompileUnit(
12022 self: *Builder,
12023 file: Metadata,
12024 producer: MetadataString,
12025 enums: Metadata,
12026 globals: Metadata,
12027 options: Metadata.CompileUnit.Options,
12028) Allocator.Error!Metadata {
12029 try self.ensureUnusedMetadataCapacity(1, Metadata.CompileUnit, 0);
12030 return self.debugCompileUnitAssumeCapacity(file, producer, enums, globals, options);
12031}
12032
12033pub fn debugSubprogram(
12034 self: *Builder,
12035 file: Metadata,
12036 name: MetadataString,
12037 linkage_name: MetadataString,
12038 line: u32,
12039 scope_line: u32,
12040 ty: Metadata,
12041 options: Metadata.Subprogram.Options,
12042 compile_unit: Metadata,
12043) Allocator.Error!Metadata {
12044 try self.ensureUnusedMetadataCapacity(1, Metadata.Subprogram, 0);
12045 return self.debugSubprogramAssumeCapacity(
12046 file,
12047 name,
12048 linkage_name,
12049 line,
12050 scope_line,
12051 ty,
12052 options,
12053 compile_unit,
12054 );
12055}
12056
12057pub fn debugLexicalBlock(self: *Builder, scope: Metadata, file: Metadata, line: u32, column: u32) Allocator.Error!Metadata {
12058 try self.ensureUnusedMetadataCapacity(1, Metadata.LexicalBlock, 0);
12059 return self.debugLexicalBlockAssumeCapacity(scope, file, line, column);
12060}
12061
12062pub fn debugLocation(self: *Builder, line: u32, column: u32, scope: Metadata, inlined_at: Metadata) Allocator.Error!Metadata {
12063 try self.ensureUnusedMetadataCapacity(1, Metadata.Location, 0);
12064 return self.debugLocationAssumeCapacity(line, column, scope, inlined_at);
12065}
12066
12067pub fn debugBoolType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12068 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12069 return self.debugBoolTypeAssumeCapacity(name, size_in_bits);
12070}
12071
12072pub fn debugUnsignedType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12073 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12074 return self.debugUnsignedTypeAssumeCapacity(name, size_in_bits);
12075}
12076
12077pub fn debugSignedType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12078 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12079 return self.debugSignedTypeAssumeCapacity(name, size_in_bits);
12080}
12081
12082pub fn debugFloatType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12083 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12084 return self.debugFloatTypeAssumeCapacity(name, size_in_bits);
12085}
12086
12087pub fn debugForwardReference(self: *Builder) Allocator.Error!Metadata {
12088 try self.metadata_forward_references.ensureUnusedCapacity(self.gpa, 1);
12089 return self.debugForwardReferenceAssumeCapacity();
12090}
12091
12092pub fn debugStructType(
12093 self: *Builder,
12094 name: MetadataString,
12095 file: Metadata,
12096 scope: Metadata,
12097 line: u32,
12098 underlying_type: Metadata,
12099 size_in_bits: u64,
12100 align_in_bits: u64,
12101 fields_tuple: Metadata,
12102) Allocator.Error!Metadata {
12103 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12104 return self.debugStructTypeAssumeCapacity(
12105 name,
12106 file,
12107 scope,
12108 line,
12109 underlying_type,
12110 size_in_bits,
12111 align_in_bits,
12112 fields_tuple,
12113 );
12114}
12115
12116pub fn debugUnionType(
12117 self: *Builder,
12118 name: MetadataString,
12119 file: Metadata,
12120 scope: Metadata,
12121 line: u32,
12122 underlying_type: Metadata,
12123 size_in_bits: u64,
12124 align_in_bits: u64,
12125 fields_tuple: Metadata,
12126) Allocator.Error!Metadata {
12127 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12128 return self.debugUnionTypeAssumeCapacity(
12129 name,
12130 file,
12131 scope,
12132 line,
12133 underlying_type,
12134 size_in_bits,
12135 align_in_bits,
12136 fields_tuple,
12137 );
12138}
12139
12140pub fn debugEnumerationType(
12141 self: *Builder,
12142 name: MetadataString,
12143 file: Metadata,
12144 scope: Metadata,
12145 line: u32,
12146 underlying_type: Metadata,
12147 size_in_bits: u64,
12148 align_in_bits: u64,
12149 fields_tuple: Metadata,
12150) Allocator.Error!Metadata {
12151 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12152 return self.debugEnumerationTypeAssumeCapacity(
12153 name,
12154 file,
12155 scope,
12156 line,
12157 underlying_type,
12158 size_in_bits,
12159 align_in_bits,
12160 fields_tuple,
12161 );
12162}
12163
12164pub fn debugArrayType(
12165 self: *Builder,
12166 name: MetadataString,
12167 file: Metadata,
12168 scope: Metadata,
12169 line: u32,
12170 underlying_type: Metadata,
12171 size_in_bits: u64,
12172 align_in_bits: u64,
12173 fields_tuple: Metadata,
12174) Allocator.Error!Metadata {
12175 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12176 return self.debugArrayTypeAssumeCapacity(
12177 name,
12178 file,
12179 scope,
12180 line,
12181 underlying_type,
12182 size_in_bits,
12183 align_in_bits,
12184 fields_tuple,
12185 );
12186}
12187
12188pub fn debugVectorType(
12189 self: *Builder,
12190 name: MetadataString,
12191 file: Metadata,
12192 scope: Metadata,
12193 line: u32,
12194 underlying_type: Metadata,
12195 size_in_bits: u64,
12196 align_in_bits: u64,
12197 fields_tuple: Metadata,
12198) Allocator.Error!Metadata {
12199 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12200 return self.debugVectorTypeAssumeCapacity(
12201 name,
12202 file,
12203 scope,
12204 line,
12205 underlying_type,
12206 size_in_bits,
12207 align_in_bits,
12208 fields_tuple,
12209 );
12210}
12211
12212pub fn debugPointerType(
12213 self: *Builder,
12214 name: MetadataString,
12215 file: Metadata,
12216 scope: Metadata,
12217 line: u32,
12218 underlying_type: Metadata,
12219 size_in_bits: u64,
12220 align_in_bits: u64,
12221 offset_in_bits: u64,
12222) Allocator.Error!Metadata {
12223 try self.ensureUnusedMetadataCapacity(1, Metadata.DerivedType, 0);
12224 return self.debugPointerTypeAssumeCapacity(
12225 name,
12226 file,
12227 scope,
12228 line,
12229 underlying_type,
12230 size_in_bits,
12231 align_in_bits,
12232 offset_in_bits,
12233 );
12234}
12235
12236pub fn debugMemberType(
12237 self: *Builder,
12238 name: MetadataString,
12239 file: Metadata,
12240 scope: Metadata,
12241 line: u32,
12242 underlying_type: Metadata,
12243 size_in_bits: u64,
12244 align_in_bits: u64,
12245 offset_in_bits: u64,
12246) Allocator.Error!Metadata {
12247 try self.ensureUnusedMetadataCapacity(1, Metadata.DerivedType, 0);
12248 return self.debugMemberTypeAssumeCapacity(
12249 name,
12250 file,
12251 scope,
12252 line,
12253 underlying_type,
12254 size_in_bits,
12255 align_in_bits,
12256 offset_in_bits,
12257 );
12258}
12259
12260pub fn debugSubroutineType(
12261 self: *Builder,
12262 types_tuple: Metadata,
12263) Allocator.Error!Metadata {
12264 try self.ensureUnusedMetadataCapacity(1, Metadata.SubroutineType, 0);
12265 return self.debugSubroutineTypeAssumeCapacity(types_tuple);
12266}
12267
12268pub fn debugEnumerator(
12269 self: *Builder,
12270 name: MetadataString,
12271 unsigned: bool,
12272 bit_width: u32,
12273 value: std.math.big.int.Const,
12274) Allocator.Error!Metadata {
12275 assert(!(unsigned and !value.positive));
12276 try self.ensureUnusedMetadataCapacity(1, Metadata.Enumerator, 0);
12277 try self.metadata_limbs.ensureUnusedCapacity(self.gpa, value.limbs.len);
12278 return self.debugEnumeratorAssumeCapacity(name, unsigned, bit_width, value);
12279}
12280
12281pub fn debugSubrange(
12282 self: *Builder,
12283 lower_bound: Metadata,
12284 count: Metadata,
12285) Allocator.Error!Metadata {
12286 try self.ensureUnusedMetadataCapacity(1, Metadata.Subrange, 0);
12287 return self.debugSubrangeAssumeCapacity(lower_bound, count);
12288}
12289
12290pub fn debugExpression(
12291 self: *Builder,
12292 elements: []const u32,
12293) Allocator.Error!Metadata {
12294 try self.ensureUnusedMetadataCapacity(1, Metadata.Expression, elements.len);
12295 return self.debugExpressionAssumeCapacity(elements);
12296}
12297
12298pub fn metadataTuple(
12299 self: *Builder,
12300 elements: []const Metadata,
12301) Allocator.Error!Metadata {
12302 try self.ensureUnusedMetadataCapacity(1, Metadata.Tuple, elements.len);
12303 return self.metadataTupleAssumeCapacity(elements);
12304}
12305
12306pub fn strTuple(
12307 self: *Builder,
12308 str: MetadataString,
12309 elements: []const Metadata,
12310) Allocator.Error!Metadata {
12311 try self.ensureUnusedMetadataCapacity(1, Metadata.StrTuple, elements.len);
12312 return self.strTupleAssumeCapacity(str, elements);
12313}
12314
12315pub fn metadataModuleFlag(
12316 self: *Builder,
12317 behavior: Metadata,
12318 name: MetadataString,
12319 constant: Metadata,
12320) Allocator.Error!Metadata {
12321 try self.ensureUnusedMetadataCapacity(1, Metadata.ModuleFlag, 0);
12322 return self.metadataModuleFlagAssumeCapacity(behavior, name, constant);
12323}
12324
12325pub fn debugLocalVar(
12326 self: *Builder,
12327 name: MetadataString,
12328 file: Metadata,
12329 scope: Metadata,
12330 line: u32,
12331 ty: Metadata,
12332) Allocator.Error!Metadata {
12333 try self.ensureUnusedMetadataCapacity(1, Metadata.LocalVar, 0);
12334 return self.debugLocalVarAssumeCapacity(name, file, scope, line, ty);
12335}
12336
12337pub fn debugParameter(
12338 self: *Builder,
12339 name: MetadataString,
12340 file: Metadata,
12341 scope: Metadata,
12342 line: u32,
12343 ty: Metadata,
12344 arg_no: u32,
12345) Allocator.Error!Metadata {
12346 try self.ensureUnusedMetadataCapacity(1, Metadata.Parameter, 0);
12347 return self.debugParameterAssumeCapacity(name, file, scope, line, ty, arg_no);
12348}
12349
12350pub fn debugGlobalVar(
12351 self: *Builder,
12352 name: MetadataString,
12353 linkage_name: MetadataString,
12354 file: Metadata,
12355 scope: Metadata,
12356 line: u32,
12357 ty: Metadata,
12358 variable: Variable.Index,
12359 options: Metadata.GlobalVar.Options,
12360) Allocator.Error!Metadata {
12361 try self.ensureUnusedMetadataCapacity(1, Metadata.GlobalVar, 0);
12362 return self.debugGlobalVarAssumeCapacity(
12363 name,
12364 linkage_name,
12365 file,
12366 scope,
12367 line,
12368 ty,
12369 variable,
12370 options,
12371 );
12372}
12373
12374pub fn debugGlobalVarExpression(
12375 self: *Builder,
12376 variable: Metadata,
12377 expression: Metadata,
12378) Allocator.Error!Metadata {
12379 try self.ensureUnusedMetadataCapacity(1, Metadata.GlobalVarExpression, 0);
12380 return self.debugGlobalVarExpressionAssumeCapacity(variable, expression);
12381}
12382
12383pub fn metadataConstant(self: *Builder, value: Constant) Allocator.Error!Metadata {
12384 try self.ensureUnusedMetadataCapacity(1, NoExtra, 0);
12385 return self.metadataConstantAssumeCapacity(value);
12386}
12387
12388pub fn debugForwardReferenceSetType(self: *Builder, fwd_ref: Metadata, ty: Metadata) void {
12389 assert(
12390 @intFromEnum(fwd_ref) >= Metadata.first_forward_reference and
12391 @intFromEnum(fwd_ref) <= Metadata.first_local_metadata,
12392 );
12393 const index = @intFromEnum(fwd_ref) - Metadata.first_forward_reference;
12394 self.metadata_forward_references.items[index] = ty;
12395}
12396
12397fn metadataSimpleAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytype) Metadata {
12398 const Key = struct {
12399 tag: Metadata.Tag,
12400 value: @TypeOf(value),
12401 };
12402 const Adapter = struct {
12403 builder: *const Builder,
12404 pub fn hash(_: @This(), key: Key) u32 {
12405 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
12406 inline for (std.meta.fields(@TypeOf(value))) |field| {
12407 hasher.update(std.mem.asBytes(&@field(key.value, field.name)));
12408 }
12409 return @truncate(hasher.final());
12410 }
12411
12412 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12413 if (lhs_key.tag != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12414 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12415 const rhs_extra = ctx.builder.metadataExtraData(@TypeOf(value), rhs_data);
12416 return std.meta.eql(lhs_key.value, rhs_extra);
12417 }
12418 };
12419
12420 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12421 Key{ .tag = tag, .value = value },
12422 Adapter{ .builder = self },
12423 );
12424
12425 if (!gop.found_existing) {
12426 gop.key_ptr.* = {};
12427 gop.value_ptr.* = {};
12428 self.metadata_items.appendAssumeCapacity(.{
12429 .tag = tag,
12430 .data = self.addMetadataExtraAssumeCapacity(value),
12431 });
12432 }
12433 return @enumFromInt(gop.index);
12434}
12435
12436fn metadataDistinctAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytype) Metadata {
12437 const Key = struct { tag: Metadata.Tag, index: Metadata };
12438 const Adapter = struct {
12439 pub fn hash(_: @This(), key: Key) u32 {
12440 return @truncate(std.hash.Wyhash.hash(
12441 std.hash.uint32(@intFromEnum(key.tag)),
12442 std.mem.asBytes(&key.index),
12443 ));
12444 }
12445
12446 pub fn eql(_: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12447 return @intFromEnum(lhs_key.index) == rhs_index;
12448 }
12449 };
12450
12451 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12452 Key{ .tag = tag, .index = @enumFromInt(self.metadata_map.count()) },
12453 Adapter{},
12454 );
12455
12456 if (!gop.found_existing) {
12457 gop.key_ptr.* = {};
12458 gop.value_ptr.* = {};
12459 self.metadata_items.appendAssumeCapacity(.{
12460 .tag = tag,
12461 .data = self.addMetadataExtraAssumeCapacity(value),
12462 });
12463 }
12464 return @enumFromInt(gop.index);
12465}
12466
12467fn metadataNamedAssumeCapacity(self: *Builder, name: MetadataString, operands: []const Metadata) void {
12468 assert(name != .none);
12469 const extra_index: u32 = @intCast(self.metadata_extra.items.len);
12470 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(operands));
12471
12472 const gop = self.metadata_named.getOrPutAssumeCapacity(name);
12473 gop.value_ptr.* = .{
12474 .index = extra_index,
12475 .len = @intCast(operands.len),
12476 };
12477}
12478
12479pub fn metadataNoneAssumeCapacity(self: *Builder) Metadata {
12480 return self.metadataSimpleAssumeCapacity(.none, .{});
12481}
12482
12483fn debugFileAssumeCapacity(
12484 self: *Builder,
12485 filename: MetadataString,
12486 directory: MetadataString,
12487) Metadata {
12488 assert(!self.strip);
12489 return self.metadataSimpleAssumeCapacity(.file, Metadata.File{
12490 .filename = filename,
12491 .directory = directory,
12492 });
12493}
12494
12495pub fn debugCompileUnitAssumeCapacity(
12496 self: *Builder,
12497 file: Metadata,
12498 producer: MetadataString,
12499 enums: Metadata,
12500 globals: Metadata,
12501 options: Metadata.CompileUnit.Options,
12502) Metadata {
12503 assert(!self.strip);
12504 return self.metadataDistinctAssumeCapacity(
12505 if (options.optimized) .@"compile_unit optimized" else .compile_unit,
12506 Metadata.CompileUnit{
12507 .file = file,
12508 .producer = producer,
12509 .enums = enums,
12510 .globals = globals,
12511 },
12512 );
12513}
12514
12515fn debugSubprogramAssumeCapacity(
12516 self: *Builder,
12517 file: Metadata,
12518 name: MetadataString,
12519 linkage_name: MetadataString,
12520 line: u32,
12521 scope_line: u32,
12522 ty: Metadata,
12523 options: Metadata.Subprogram.Options,
12524 compile_unit: Metadata,
12525) Metadata {
12526 assert(!self.strip);
12527 const tag: Metadata.Tag = @enumFromInt(@intFromEnum(Metadata.Tag.subprogram) +
12528 @as(u3, @truncate(@as(u32, @bitCast(options.sp_flags)) >> 2)));
12529 return self.metadataDistinctAssumeCapacity(tag, Metadata.Subprogram{
12530 .file = file,
12531 .name = name,
12532 .linkage_name = linkage_name,
12533 .line = line,
12534 .scope_line = scope_line,
12535 .ty = ty,
12536 .di_flags = options.di_flags,
12537 .compile_unit = compile_unit,
12538 });
12539}
12540
12541fn debugLexicalBlockAssumeCapacity(self: *Builder, scope: Metadata, file: Metadata, line: u32, column: u32) Metadata {
12542 assert(!self.strip);
12543 return self.metadataSimpleAssumeCapacity(.lexical_block, Metadata.LexicalBlock{
12544 .scope = scope,
12545 .file = file,
12546 .line = line,
12547 .column = column,
12548 });
12549}
12550
12551fn debugLocationAssumeCapacity(self: *Builder, line: u32, column: u32, scope: Metadata, inlined_at: Metadata) Metadata {
12552 assert(!self.strip);
12553 return self.metadataSimpleAssumeCapacity(.location, Metadata.Location{
12554 .line = line,
12555 .column = column,
12556 .scope = scope,
12557 .inlined_at = inlined_at,
12558 });
12559}
12560
12561fn debugBoolTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12562 assert(!self.strip);
12563 return self.metadataSimpleAssumeCapacity(.basic_bool_type, Metadata.BasicType{
12564 .name = name,
12565 .size_in_bits_lo = @truncate(size_in_bits),
12566 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12567 });
12568}
12569
12570fn debugUnsignedTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12571 assert(!self.strip);
12572 return self.metadataSimpleAssumeCapacity(.basic_unsigned_type, Metadata.BasicType{
12573 .name = name,
12574 .size_in_bits_lo = @truncate(size_in_bits),
12575 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12576 });
12577}
12578
12579fn debugSignedTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12580 assert(!self.strip);
12581 return self.metadataSimpleAssumeCapacity(.basic_signed_type, Metadata.BasicType{
12582 .name = name,
12583 .size_in_bits_lo = @truncate(size_in_bits),
12584 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12585 });
12586}
12587
12588fn debugFloatTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12589 assert(!self.strip);
12590 return self.metadataSimpleAssumeCapacity(.basic_float_type, Metadata.BasicType{
12591 .name = name,
12592 .size_in_bits_lo = @truncate(size_in_bits),
12593 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12594 });
12595}
12596
12597fn debugForwardReferenceAssumeCapacity(self: *Builder) Metadata {
12598 assert(!self.strip);
12599 const index = Metadata.first_forward_reference + self.metadata_forward_references.items.len;
12600 self.metadata_forward_references.appendAssumeCapacity(.none);
12601 return @enumFromInt(index);
12602}
12603
12604fn debugStructTypeAssumeCapacity(
12605 self: *Builder,
12606 name: MetadataString,
12607 file: Metadata,
12608 scope: Metadata,
12609 line: u32,
12610 underlying_type: Metadata,
12611 size_in_bits: u64,
12612 align_in_bits: u64,
12613 fields_tuple: Metadata,
12614) Metadata {
12615 assert(!self.strip);
12616 return self.debugCompositeTypeAssumeCapacity(
12617 .composite_struct_type,
12618 name,
12619 file,
12620 scope,
12621 line,
12622 underlying_type,
12623 size_in_bits,
12624 align_in_bits,
12625 fields_tuple,
12626 );
12627}
12628
12629fn debugUnionTypeAssumeCapacity(
12630 self: *Builder,
12631 name: MetadataString,
12632 file: Metadata,
12633 scope: Metadata,
12634 line: u32,
12635 underlying_type: Metadata,
12636 size_in_bits: u64,
12637 align_in_bits: u64,
12638 fields_tuple: Metadata,
12639) Metadata {
12640 assert(!self.strip);
12641 return self.debugCompositeTypeAssumeCapacity(
12642 .composite_union_type,
12643 name,
12644 file,
12645 scope,
12646 line,
12647 underlying_type,
12648 size_in_bits,
12649 align_in_bits,
12650 fields_tuple,
12651 );
12652}
12653
12654fn debugEnumerationTypeAssumeCapacity(
12655 self: *Builder,
12656 name: MetadataString,
12657 file: Metadata,
12658 scope: Metadata,
12659 line: u32,
12660 underlying_type: Metadata,
12661 size_in_bits: u64,
12662 align_in_bits: u64,
12663 fields_tuple: Metadata,
12664) Metadata {
12665 assert(!self.strip);
12666 return self.debugCompositeTypeAssumeCapacity(
12667 .composite_enumeration_type,
12668 name,
12669 file,
12670 scope,
12671 line,
12672 underlying_type,
12673 size_in_bits,
12674 align_in_bits,
12675 fields_tuple,
12676 );
12677}
12678
12679fn debugArrayTypeAssumeCapacity(
12680 self: *Builder,
12681 name: MetadataString,
12682 file: Metadata,
12683 scope: Metadata,
12684 line: u32,
12685 underlying_type: Metadata,
12686 size_in_bits: u64,
12687 align_in_bits: u64,
12688 fields_tuple: Metadata,
12689) Metadata {
12690 assert(!self.strip);
12691 return self.debugCompositeTypeAssumeCapacity(
12692 .composite_array_type,
12693 name,
12694 file,
12695 scope,
12696 line,
12697 underlying_type,
12698 size_in_bits,
12699 align_in_bits,
12700 fields_tuple,
12701 );
12702}
12703
12704fn debugVectorTypeAssumeCapacity(
12705 self: *Builder,
12706 name: MetadataString,
12707 file: Metadata,
12708 scope: Metadata,
12709 line: u32,
12710 underlying_type: Metadata,
12711 size_in_bits: u64,
12712 align_in_bits: u64,
12713 fields_tuple: Metadata,
12714) Metadata {
12715 assert(!self.strip);
12716 return self.debugCompositeTypeAssumeCapacity(
12717 .composite_vector_type,
12718 name,
12719 file,
12720 scope,
12721 line,
12722 underlying_type,
12723 size_in_bits,
12724 align_in_bits,
12725 fields_tuple,
12726 );
12727}
12728
12729fn debugCompositeTypeAssumeCapacity(
12730 self: *Builder,
12731 tag: Metadata.Tag,
12732 name: MetadataString,
12733 file: Metadata,
12734 scope: Metadata,
12735 line: u32,
12736 underlying_type: Metadata,
12737 size_in_bits: u64,
12738 align_in_bits: u64,
12739 fields_tuple: Metadata,
12740) Metadata {
12741 assert(!self.strip);
12742 return self.metadataSimpleAssumeCapacity(tag, Metadata.CompositeType{
12743 .name = name,
12744 .file = file,
12745 .scope = scope,
12746 .line = line,
12747 .underlying_type = underlying_type,
12748 .size_in_bits_lo = @truncate(size_in_bits),
12749 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12750 .align_in_bits_lo = @truncate(align_in_bits),
12751 .align_in_bits_hi = @truncate(align_in_bits >> 32),
12752 .fields_tuple = fields_tuple,
12753 });
12754}
12755
12756fn debugPointerTypeAssumeCapacity(
12757 self: *Builder,
12758 name: MetadataString,
12759 file: Metadata,
12760 scope: Metadata,
12761 line: u32,
12762 underlying_type: Metadata,
12763 size_in_bits: u64,
12764 align_in_bits: u64,
12765 offset_in_bits: u64,
12766) Metadata {
12767 assert(!self.strip);
12768 return self.metadataSimpleAssumeCapacity(.derived_pointer_type, Metadata.DerivedType{
12769 .name = name,
12770 .file = file,
12771 .scope = scope,
12772 .line = line,
12773 .underlying_type = underlying_type,
12774 .size_in_bits_lo = @truncate(size_in_bits),
12775 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12776 .align_in_bits_lo = @truncate(align_in_bits),
12777 .align_in_bits_hi = @truncate(align_in_bits >> 32),
12778 .offset_in_bits_lo = @truncate(offset_in_bits),
12779 .offset_in_bits_hi = @truncate(offset_in_bits >> 32),
12780 });
12781}
12782
12783fn debugMemberTypeAssumeCapacity(
12784 self: *Builder,
12785 name: MetadataString,
12786 file: Metadata,
12787 scope: Metadata,
12788 line: u32,
12789 underlying_type: Metadata,
12790 size_in_bits: u64,
12791 align_in_bits: u64,
12792 offset_in_bits: u64,
12793) Metadata {
12794 assert(!self.strip);
12795 return self.metadataSimpleAssumeCapacity(.derived_member_type, Metadata.DerivedType{
12796 .name = name,
12797 .file = file,
12798 .scope = scope,
12799 .line = line,
12800 .underlying_type = underlying_type,
12801 .size_in_bits_lo = @truncate(size_in_bits),
12802 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12803 .align_in_bits_lo = @truncate(align_in_bits),
12804 .align_in_bits_hi = @truncate(align_in_bits >> 32),
12805 .offset_in_bits_lo = @truncate(offset_in_bits),
12806 .offset_in_bits_hi = @truncate(offset_in_bits >> 32),
12807 });
12808}
12809
12810fn debugSubroutineTypeAssumeCapacity(
12811 self: *Builder,
12812 types_tuple: Metadata,
12813) Metadata {
12814 assert(!self.strip);
12815 return self.metadataSimpleAssumeCapacity(.subroutine_type, Metadata.SubroutineType{
12816 .types_tuple = types_tuple,
12817 });
12818}
12819
12820fn debugEnumeratorAssumeCapacity(
12821 self: *Builder,
12822 name: MetadataString,
12823 unsigned: bool,
12824 bit_width: u32,
12825 value: std.math.big.int.Const,
12826) Metadata {
12827 assert(!self.strip);
12828 const Key = struct {
12829 tag: Metadata.Tag,
12830 name: MetadataString,
12831 bit_width: u32,
12832 value: std.math.big.int.Const,
12833 };
12834 const Adapter = struct {
12835 builder: *const Builder,
12836 pub fn hash(_: @This(), key: Key) u32 {
12837 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
12838 hasher.update(std.mem.asBytes(&key.name));
12839 hasher.update(std.mem.asBytes(&key.bit_width));
12840 hasher.update(std.mem.sliceAsBytes(key.value.limbs));
12841 return @truncate(hasher.final());
12842 }
12843
12844 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12845 if (lhs_key.tag != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12846 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12847 const rhs_extra = ctx.builder.metadataExtraData(Metadata.Enumerator, rhs_data);
12848 const limbs = ctx.builder.metadata_limbs
12849 .items[rhs_extra.limbs_index..][0..rhs_extra.limbs_len];
12850 const rhs_value = std.math.big.int.Const{
12851 .limbs = limbs,
12852 .positive = lhs_key.value.positive,
12853 };
12854 return lhs_key.name == rhs_extra.name and
12855 lhs_key.bit_width == rhs_extra.bit_width and
12856 lhs_key.value.eql(rhs_value);
12857 }
12858 };
12859
12860 const tag: Metadata.Tag = if (unsigned)
12861 .enumerator_unsigned
12862 else if (value.positive)
12863 .enumerator_signed_positive
12864 else
12865 .enumerator_signed_negative;
12866
12867 assert(!(tag == .enumerator_unsigned and !value.positive));
12868
12869 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12870 Key{
12871 .tag = tag,
12872 .name = name,
12873 .bit_width = bit_width,
12874 .value = value,
12875 },
12876 Adapter{ .builder = self },
12877 );
12878
12879 if (!gop.found_existing) {
12880 gop.key_ptr.* = {};
12881 gop.value_ptr.* = {};
12882 self.metadata_items.appendAssumeCapacity(.{
12883 .tag = tag,
12884 .data = self.addMetadataExtraAssumeCapacity(Metadata.Enumerator{
12885 .name = name,
12886 .bit_width = bit_width,
12887 .limbs_index = @intCast(self.metadata_limbs.items.len),
12888 .limbs_len = @intCast(value.limbs.len),
12889 }),
12890 });
12891 self.metadata_limbs.appendSliceAssumeCapacity(value.limbs);
12892 }
12893 return @enumFromInt(gop.index);
12894}
12895
12896fn debugSubrangeAssumeCapacity(
12897 self: *Builder,
12898 lower_bound: Metadata,
12899 count: Metadata,
12900) Metadata {
12901 assert(!self.strip);
12902 return self.metadataSimpleAssumeCapacity(.subrange, Metadata.Subrange{
12903 .lower_bound = lower_bound,
12904 .count = count,
12905 });
12906}
12907
12908fn debugExpressionAssumeCapacity(
12909 self: *Builder,
12910 elements: []const u32,
12911) Metadata {
12912 assert(!self.strip);
12913 const Key = struct {
12914 elements: []const u32,
12915 };
12916 const Adapter = struct {
12917 builder: *const Builder,
12918 pub fn hash(_: @This(), key: Key) u32 {
12919 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.expression)));
12920 hasher.update(std.mem.sliceAsBytes(key.elements));
12921 return @truncate(hasher.final());
12922 }
12923
12924 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12925 if (Metadata.Tag.expression != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12926 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12927 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.Expression, rhs_data);
12928 return std.mem.eql(
12929 u32,
12930 lhs_key.elements,
12931 rhs_extra.trail.next(rhs_extra.data.elements_len, u32, ctx.builder),
12932 );
12933 }
12934 };
12935
12936 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12937 Key{ .elements = elements },
12938 Adapter{ .builder = self },
12939 );
12940
12941 if (!gop.found_existing) {
12942 gop.key_ptr.* = {};
12943 gop.value_ptr.* = {};
12944 self.metadata_items.appendAssumeCapacity(.{
12945 .tag = .expression,
12946 .data = self.addMetadataExtraAssumeCapacity(Metadata.Expression{
12947 .elements_len = @intCast(elements.len),
12948 }),
12949 });
12950 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(elements));
12951 }
12952 return @enumFromInt(gop.index);
12953}
12954
12955fn metadataTupleAssumeCapacity(
12956 self: *Builder,
12957 elements: []const Metadata,
12958) Metadata {
12959 const Key = struct {
12960 elements: []const Metadata,
12961 };
12962 const Adapter = struct {
12963 builder: *const Builder,
12964 pub fn hash(_: @This(), key: Key) u32 {
12965 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.tuple)));
12966 hasher.update(std.mem.sliceAsBytes(key.elements));
12967 return @truncate(hasher.final());
12968 }
12969
12970 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12971 if (Metadata.Tag.tuple != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12972 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12973 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.Tuple, rhs_data);
12974 return std.mem.eql(
12975 Metadata,
12976 lhs_key.elements,
12977 rhs_extra.trail.next(rhs_extra.data.elements_len, Metadata, ctx.builder),
12978 );
12979 }
12980 };
12981
12982 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12983 Key{ .elements = elements },
12984 Adapter{ .builder = self },
12985 );
12986
12987 if (!gop.found_existing) {
12988 gop.key_ptr.* = {};
12989 gop.value_ptr.* = {};
12990 self.metadata_items.appendAssumeCapacity(.{
12991 .tag = .tuple,
12992 .data = self.addMetadataExtraAssumeCapacity(Metadata.Tuple{
12993 .elements_len = @intCast(elements.len),
12994 }),
12995 });
12996 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(elements));
12997 }
12998 return @enumFromInt(gop.index);
12999}
13000
13001fn strTupleAssumeCapacity(
13002 self: *Builder,
13003 str: MetadataString,
13004 elements: []const Metadata,
13005) Metadata {
13006 const Key = struct {
13007 str: MetadataString,
13008 elements: []const Metadata,
13009 };
13010 const Adapter = struct {
13011 builder: *const Builder,
13012 pub fn hash(_: @This(), key: Key) u32 {
13013 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.tuple)));
13014 hasher.update(std.mem.sliceAsBytes(key.elements));
13015 return @truncate(hasher.final());
13016 }
13017
13018 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
13019 if (.str_tuple != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
13020 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
13021 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.StrTuple, rhs_data);
13022 return rhs_extra.data.str == lhs_key.str and std.mem.eql(
13023 Metadata,
13024 lhs_key.elements,
13025 rhs_extra.trail.next(rhs_extra.data.elements_len, Metadata, ctx.builder),
13026 );
13027 }
13028 };
13029
13030 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
13031 Key{ .str = str, .elements = elements },
13032 Adapter{ .builder = self },
13033 );
13034
13035 if (!gop.found_existing) {
13036 gop.key_ptr.* = {};
13037 gop.value_ptr.* = {};
13038 self.metadata_items.appendAssumeCapacity(.{
13039 .tag = .str_tuple,
13040 .data = self.addMetadataExtraAssumeCapacity(Metadata.StrTuple{
13041 .str = str,
13042 .elements_len = @intCast(elements.len),
13043 }),
13044 });
13045 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(elements));
13046 }
13047 return @enumFromInt(gop.index);
13048}
13049
13050fn metadataModuleFlagAssumeCapacity(
13051 self: *Builder,
13052 behavior: Metadata,
13053 name: MetadataString,
13054 constant: Metadata,
13055) Metadata {
13056 return self.metadataSimpleAssumeCapacity(.module_flag, Metadata.ModuleFlag{
13057 .behavior = behavior,
13058 .name = name,
13059 .constant = constant,
13060 });
13061}
13062
13063fn debugLocalVarAssumeCapacity(
13064 self: *Builder,
13065 name: MetadataString,
13066 file: Metadata,
13067 scope: Metadata,
13068 line: u32,
13069 ty: Metadata,
13070) Metadata {
13071 assert(!self.strip);
13072 return self.metadataSimpleAssumeCapacity(.local_var, Metadata.LocalVar{
13073 .name = name,
13074 .file = file,
13075 .scope = scope,
13076 .line = line,
13077 .ty = ty,
13078 });
13079}
13080
13081fn debugParameterAssumeCapacity(
13082 self: *Builder,
13083 name: MetadataString,
13084 file: Metadata,
13085 scope: Metadata,
13086 line: u32,
13087 ty: Metadata,
13088 arg_no: u32,
13089) Metadata {
13090 assert(!self.strip);
13091 return self.metadataSimpleAssumeCapacity(.parameter, Metadata.Parameter{
13092 .name = name,
13093 .file = file,
13094 .scope = scope,
13095 .line = line,
13096 .ty = ty,
13097 .arg_no = arg_no,
13098 });
13099}
13100
13101fn debugGlobalVarAssumeCapacity(
13102 self: *Builder,
13103 name: MetadataString,
13104 linkage_name: MetadataString,
13105 file: Metadata,
13106 scope: Metadata,
13107 line: u32,
13108 ty: Metadata,
13109 variable: Variable.Index,
13110 options: Metadata.GlobalVar.Options,
13111) Metadata {
13112 assert(!self.strip);
13113 return self.metadataDistinctAssumeCapacity(
13114 if (options.local) .@"global_var local" else .global_var,
13115 Metadata.GlobalVar{
13116 .name = name,
13117 .linkage_name = linkage_name,
13118 .file = file,
13119 .scope = scope,
13120 .line = line,
13121 .ty = ty,
13122 .variable = variable,
13123 },
13124 );
13125}
13126
13127fn debugGlobalVarExpressionAssumeCapacity(
13128 self: *Builder,
13129 variable: Metadata,
13130 expression: Metadata,
13131) Metadata {
13132 assert(!self.strip);
13133 return self.metadataSimpleAssumeCapacity(.global_var_expression, Metadata.GlobalVarExpression{
13134 .variable = variable,
13135 .expression = expression,
13136 });
13137}
13138
13139fn metadataConstantAssumeCapacity(self: *Builder, constant: Constant) Metadata {
13140 const Adapter = struct {
13141 builder: *const Builder,
13142 pub fn hash(_: @This(), key: Constant) u32 {
13143 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.constant)));
13144 hasher.update(std.mem.asBytes(&key));
13145 return @truncate(hasher.final());
13146 }
13147
13148 pub fn eql(ctx: @This(), lhs_key: Constant, _: void, rhs_index: usize) bool {
13149 if (Metadata.Tag.constant != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
13150 const rhs_data: Constant = @enumFromInt(ctx.builder.metadata_items.items(.data)[rhs_index]);
13151 return rhs_data == lhs_key;
13152 }
13153 };
13154
13155 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
13156 constant,
13157 Adapter{ .builder = self },
13158 );
13159
13160 if (!gop.found_existing) {
13161 gop.key_ptr.* = {};
13162 gop.value_ptr.* = {};
13163 self.metadata_items.appendAssumeCapacity(.{
13164 .tag = .constant,
13165 .data = @intFromEnum(constant),
13166 });
13167 }
13168 return @enumFromInt(gop.index);
13169}
13170
13171pub const Producer = struct {
13172 name: []const u8,
13173 version: std.SemanticVersion,
13174};
13175
13176pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitcode_writer.Error![]const u32 {
13177 const BitcodeWriter = bitcode_writer.BitcodeWriter(&.{ Type, FunctionAttributes });
13178 var bitcode = BitcodeWriter.init(allocator, .{
13179 std.math.log2_int_ceil(usize, self.type_items.items.len),
13180 std.math.log2_int_ceil(usize, 1 + self.function_attributes_set.count()),
13181 });
13182 errdefer bitcode.deinit();
13183
13184 // Write LLVM IR magic
13185 try bitcode.writeBits(ir.MAGIC, 32);
13186
13187 var record: std.ArrayListUnmanaged(u64) = .empty;
13188 defer record.deinit(self.gpa);
13189
13190 // IDENTIFICATION_BLOCK
13191 {
13192 const Identification = ir.Identification;
13193 var identification_block = try bitcode.enterTopBlock(Identification);
13194
13195 const producer_str = try std.fmt.allocPrint(self.gpa, "{s} {d}.{d}.{d}", .{
13196 producer.name,
13197 producer.version.major,
13198 producer.version.minor,
13199 producer.version.patch,
13200 });
13201 defer self.gpa.free(producer_str);
13202
13203 try identification_block.writeAbbrev(Identification.Version{ .string = producer_str });
13204 try identification_block.writeAbbrev(Identification.Epoch{ .epoch = 0 });
13205
13206 try identification_block.end();
13207 }
13208
13209 // MODULE_BLOCK
13210 {
13211 const Module = ir.Module;
13212 var module_block = try bitcode.enterTopBlock(Module);
13213
13214 try module_block.writeAbbrev(Module.Version{});
13215
13216 if (self.target_triple.slice(self)) |triple| {
13217 try module_block.writeAbbrev(Module.String{
13218 .code = 2,
13219 .string = triple,
13220 });
13221 }
13222
13223 if (self.data_layout.slice(self)) |data_layout| {
13224 try module_block.writeAbbrev(Module.String{
13225 .code = 3,
13226 .string = data_layout,
13227 });
13228 }
13229
13230 if (self.source_filename.slice(self)) |source_filename| {
13231 try module_block.writeAbbrev(Module.String{
13232 .code = 16,
13233 .string = source_filename,
13234 });
13235 }
13236
13237 if (self.module_asm.items.len != 0) {
13238 try module_block.writeAbbrev(Module.String{
13239 .code = 4,
13240 .string = self.module_asm.items,
13241 });
13242 }
13243
13244 // TYPE_BLOCK
13245 {
13246 var type_block = try module_block.enterSubBlock(ir.Type, true);
13247
13248 try type_block.writeAbbrev(ir.Type.NumEntry{ .num = @intCast(self.type_items.items.len) });
13249
13250 for (self.type_items.items, 0..) |item, i| {
13251 const ty: Type = @enumFromInt(i);
13252
13253 switch (item.tag) {
13254 .simple => try type_block.writeAbbrev(ir.Type.Simple{ .code = @truncate(item.data) }),
13255 .integer => try type_block.writeAbbrev(ir.Type.Integer{ .width = item.data }),
13256 .structure,
13257 .packed_structure,
13258 => |kind| {
13259 const is_packed = switch (kind) {
13260 .structure => false,
13261 .packed_structure => true,
13262 else => unreachable,
13263 };
13264 var extra = self.typeExtraDataTrail(Type.Structure, item.data);
13265 try type_block.writeAbbrev(ir.Type.StructAnon{
13266 .is_packed = is_packed,
13267 .types = extra.trail.next(extra.data.fields_len, Type, self),
13268 });
13269 },
13270 .named_structure => {
13271 const extra = self.typeExtraData(Type.NamedStructure, item.data);
13272 try type_block.writeAbbrev(ir.Type.StructName{
13273 .string = extra.id.slice(self).?,
13274 });
13275
13276 switch (extra.body) {
13277 .none => try type_block.writeAbbrev(ir.Type.Opaque{}),
13278 else => {
13279 const real_struct = self.type_items.items[@intFromEnum(extra.body)];
13280 const is_packed: bool = switch (real_struct.tag) {
13281 .structure => false,
13282 .packed_structure => true,
13283 else => unreachable,
13284 };
13285
13286 var real_extra = self.typeExtraDataTrail(Type.Structure, real_struct.data);
13287 try type_block.writeAbbrev(ir.Type.StructNamed{
13288 .is_packed = is_packed,
13289 .types = real_extra.trail.next(real_extra.data.fields_len, Type, self),
13290 });
13291 },
13292 }
13293 },
13294 .array,
13295 .small_array,
13296 => try type_block.writeAbbrev(ir.Type.Array{
13297 .len = ty.aggregateLen(self),
13298 .child = ty.childType(self),
13299 }),
13300 .vector,
13301 .scalable_vector,
13302 => try type_block.writeAbbrev(ir.Type.Vector{
13303 .len = ty.aggregateLen(self),
13304 .child = ty.childType(self),
13305 }),
13306 .pointer => try type_block.writeAbbrev(ir.Type.Pointer{
13307 .addr_space = ty.pointerAddrSpace(self),
13308 }),
13309 .target => {
13310 var extra = self.typeExtraDataTrail(Type.Target, item.data);
13311 try type_block.writeAbbrev(ir.Type.StructName{
13312 .string = extra.data.name.slice(self).?,
13313 });
13314
13315 const types = extra.trail.next(extra.data.types_len, Type, self);
13316 const ints = extra.trail.next(extra.data.ints_len, u32, self);
13317
13318 try type_block.writeAbbrev(ir.Type.Target{
13319 .num_types = extra.data.types_len,
13320 .types = types,
13321 .ints = ints,
13322 });
13323 },
13324 .function, .vararg_function => |kind| {
13325 const is_vararg = switch (kind) {
13326 .function => false,
13327 .vararg_function => true,
13328 else => unreachable,
13329 };
13330 var extra = self.typeExtraDataTrail(Type.Function, item.data);
13331 try type_block.writeAbbrev(ir.Type.Function{
13332 .is_vararg = is_vararg,
13333 .return_type = extra.data.ret,
13334 .param_types = extra.trail.next(extra.data.params_len, Type, self),
13335 });
13336 },
13337 }
13338 }
13339
13340 try type_block.end();
13341 }
13342
13343 var attributes_set: std.AutoArrayHashMapUnmanaged(struct {
13344 attributes: Attributes,
13345 index: u32,
13346 }, void) = .{};
13347 defer attributes_set.deinit(self.gpa);
13348
13349 // PARAMATTR_GROUP_BLOCK
13350 {
13351 const ParamattrGroup = ir.ParamattrGroup;
13352
13353 var paramattr_group_block = try module_block.enterSubBlock(ParamattrGroup, true);
13354
13355 for (self.function_attributes_set.keys()) |func_attributes| {
13356 for (func_attributes.slice(self), 0..) |attributes, i| {
13357 const attributes_slice = attributes.slice(self);
13358 if (attributes_slice.len == 0) continue;
13359
13360 const attr_gop = try attributes_set.getOrPut(self.gpa, .{
13361 .attributes = attributes,
13362 .index = @intCast(i),
13363 });
13364
13365 if (attr_gop.found_existing) continue;
13366
13367 record.clearRetainingCapacity();
13368 try record.ensureUnusedCapacity(self.gpa, 2);
13369
13370 record.appendAssumeCapacity(attr_gop.index);
13371 record.appendAssumeCapacity(switch (i) {
13372 0 => 0xffffffff,
13373 else => i - 1,
13374 });
13375
13376 for (attributes_slice) |attr_index| {
13377 const kind = attr_index.getKind(self);
13378 switch (attr_index.toAttribute(self)) {
13379 .zeroext,
13380 .signext,
13381 .inreg,
13382 .@"noalias",
13383 .nocapture,
13384 .nofree,
13385 .nest,
13386 .returned,
13387 .nonnull,
13388 .swiftself,
13389 .swiftasync,
13390 .swifterror,
13391 .immarg,
13392 .noundef,
13393 .allocalign,
13394 .allocptr,
13395 .readnone,
13396 .readonly,
13397 .writeonly,
13398 .alwaysinline,
13399 .builtin,
13400 .cold,
13401 .convergent,
13402 .disable_sanitizer_information,
13403 .fn_ret_thunk_extern,
13404 .hot,
13405 .inlinehint,
13406 .jumptable,
13407 .minsize,
13408 .naked,
13409 .nobuiltin,
13410 .nocallback,
13411 .noduplicate,
13412 .noimplicitfloat,
13413 .@"noinline",
13414 .nomerge,
13415 .nonlazybind,
13416 .noprofile,
13417 .skipprofile,
13418 .noredzone,
13419 .noreturn,
13420 .norecurse,
13421 .willreturn,
13422 .nosync,
13423 .nounwind,
13424 .nosanitize_bounds,
13425 .nosanitize_coverage,
13426 .null_pointer_is_valid,
13427 .optforfuzzing,
13428 .optnone,
13429 .optsize,
13430 .returns_twice,
13431 .safestack,
13432 .sanitize_address,
13433 .sanitize_memory,
13434 .sanitize_thread,
13435 .sanitize_hwaddress,
13436 .sanitize_memtag,
13437 .speculative_load_hardening,
13438 .speculatable,
13439 .ssp,
13440 .sspstrong,
13441 .sspreq,
13442 .strictfp,
13443 .nocf_check,
13444 .shadowcallstack,
13445 .mustprogress,
13446 .no_sanitize_address,
13447 .no_sanitize_hwaddress,
13448 .sanitize_address_dyninit,
13449 => {
13450 try record.ensureUnusedCapacity(self.gpa, 2);
13451 record.appendAssumeCapacity(0);
13452 record.appendAssumeCapacity(@intFromEnum(kind));
13453 },
13454 .byval,
13455 .byref,
13456 .preallocated,
13457 .inalloca,
13458 .sret,
13459 .elementtype,
13460 => |ty| {
13461 try record.ensureUnusedCapacity(self.gpa, 3);
13462 record.appendAssumeCapacity(6);
13463 record.appendAssumeCapacity(@intFromEnum(kind));
13464 record.appendAssumeCapacity(@intFromEnum(ty));
13465 },
13466 .@"align",
13467 .alignstack,
13468 => |alignment| {
13469 try record.ensureUnusedCapacity(self.gpa, 3);
13470 record.appendAssumeCapacity(1);
13471 record.appendAssumeCapacity(@intFromEnum(kind));
13472 record.appendAssumeCapacity(alignment.toByteUnits() orelse 0);
13473 },
13474 .dereferenceable,
13475 .dereferenceable_or_null,
13476 => |size| {
13477 try record.ensureUnusedCapacity(self.gpa, 3);
13478 record.appendAssumeCapacity(1);
13479 record.appendAssumeCapacity(@intFromEnum(kind));
13480 record.appendAssumeCapacity(size);
13481 },
13482 .nofpclass => |fpclass| {
13483 try record.ensureUnusedCapacity(self.gpa, 3);
13484 record.appendAssumeCapacity(1);
13485 record.appendAssumeCapacity(@intFromEnum(kind));
13486 record.appendAssumeCapacity(@as(u32, @bitCast(fpclass)));
13487 },
13488 .allockind => |allockind| {
13489 try record.ensureUnusedCapacity(self.gpa, 3);
13490 record.appendAssumeCapacity(1);
13491 record.appendAssumeCapacity(@intFromEnum(kind));
13492 record.appendAssumeCapacity(@as(u32, @bitCast(allockind)));
13493 },
13494
13495 .allocsize => |allocsize| {
13496 try record.ensureUnusedCapacity(self.gpa, 3);
13497 record.appendAssumeCapacity(1);
13498 record.appendAssumeCapacity(@intFromEnum(kind));
13499 record.appendAssumeCapacity(@bitCast(allocsize.toLlvm()));
13500 },
13501 .memory => |memory| {
13502 try record.ensureUnusedCapacity(self.gpa, 3);
13503 record.appendAssumeCapacity(1);
13504 record.appendAssumeCapacity(@intFromEnum(kind));
13505 record.appendAssumeCapacity(@as(u32, @bitCast(memory)));
13506 },
13507 .uwtable => |uwtable| if (uwtable != .none) {
13508 try record.ensureUnusedCapacity(self.gpa, 3);
13509 record.appendAssumeCapacity(1);
13510 record.appendAssumeCapacity(@intFromEnum(kind));
13511 record.appendAssumeCapacity(@intFromEnum(uwtable));
13512 },
13513 .vscale_range => |vscale_range| {
13514 try record.ensureUnusedCapacity(self.gpa, 3);
13515 record.appendAssumeCapacity(1);
13516 record.appendAssumeCapacity(@intFromEnum(kind));
13517 record.appendAssumeCapacity(@bitCast(vscale_range.toLlvm()));
13518 },
13519 .string => |string_attr| {
13520 const string_attr_kind_slice = string_attr.kind.slice(self).?;
13521 const string_attr_value_slice = if (string_attr.value != .none)
13522 string_attr.value.slice(self).?
13523 else
13524 null;
13525
13526 try record.ensureUnusedCapacity(
13527 self.gpa,
13528 2 + string_attr_kind_slice.len + if (string_attr_value_slice) |slice| slice.len + 1 else 0,
13529 );
13530 record.appendAssumeCapacity(if (string_attr.value == .none) 3 else 4);
13531 for (string_attr.kind.slice(self).?) |c| {
13532 record.appendAssumeCapacity(c);
13533 }
13534 record.appendAssumeCapacity(0);
13535 if (string_attr_value_slice) |slice| {
13536 for (slice) |c| {
13537 record.appendAssumeCapacity(c);
13538 }
13539 record.appendAssumeCapacity(0);
13540 }
13541 },
13542 .none => unreachable,
13543 }
13544 }
13545
13546 try paramattr_group_block.writeUnabbrev(3, record.items);
13547 }
13548 }
13549
13550 try paramattr_group_block.end();
13551 }
13552
13553 // PARAMATTR_BLOCK
13554 {
13555 const Paramattr = ir.Paramattr;
13556 var paramattr_block = try module_block.enterSubBlock(Paramattr, true);
13557
13558 for (self.function_attributes_set.keys()) |func_attributes| {
13559 const func_attributes_slice = func_attributes.slice(self);
13560 record.clearRetainingCapacity();
13561 try record.ensureUnusedCapacity(self.gpa, func_attributes_slice.len);
13562 for (func_attributes_slice, 0..) |attributes, i| {
13563 const attributes_slice = attributes.slice(self);
13564 if (attributes_slice.len == 0) continue;
13565
13566 const group_index = attributes_set.getIndex(.{
13567 .attributes = attributes,
13568 .index = @intCast(i),
13569 }).?;
13570 record.appendAssumeCapacity(@intCast(group_index));
13571 }
13572
13573 try paramattr_block.writeAbbrev(Paramattr.Entry{ .group_indices = record.items });
13574 }
13575
13576 try paramattr_block.end();
13577 }
13578
13579 var globals: std.AutoArrayHashMapUnmanaged(Global.Index, void) = .empty;
13580 defer globals.deinit(self.gpa);
13581 try globals.ensureUnusedCapacity(
13582 self.gpa,
13583 self.variables.items.len +
13584 self.functions.items.len +
13585 self.aliases.items.len,
13586 );
13587
13588 for (self.variables.items) |variable| {
13589 if (variable.global.getReplacement(self) != .none) continue;
13590
13591 globals.putAssumeCapacity(variable.global, {});
13592 }
13593
13594 for (self.functions.items) |function| {
13595 if (function.global.getReplacement(self) != .none) continue;
13596
13597 globals.putAssumeCapacity(function.global, {});
13598 }
13599
13600 for (self.aliases.items) |alias| {
13601 if (alias.global.getReplacement(self) != .none) continue;
13602
13603 globals.putAssumeCapacity(alias.global, {});
13604 }
13605
13606 const ConstantAdapter = struct {
13607 const ConstantAdapter = @This();
13608 builder: *const Builder,
13609 globals: *const std.AutoArrayHashMapUnmanaged(Global.Index, void),
13610
13611 pub fn get(adapter: @This(), param: anytype, comptime field_name: []const u8) @TypeOf(param) {
13612 _ = field_name;
13613 return switch (@TypeOf(param)) {
13614 Constant => @enumFromInt(adapter.getConstantIndex(param)),
13615 else => param,
13616 };
13617 }
13618
13619 pub fn getConstantIndex(adapter: ConstantAdapter, constant: Constant) u32 {
13620 return switch (constant.unwrap()) {
13621 .constant => |c| c + adapter.numGlobals(),
13622 .global => |global| @intCast(adapter.globals.getIndex(global.unwrap(adapter.builder)).?),
13623 };
13624 }
13625
13626 pub fn numConstants(adapter: ConstantAdapter) u32 {
13627 return @intCast(adapter.globals.count() + adapter.builder.constant_items.len);
13628 }
13629
13630 pub fn numGlobals(adapter: ConstantAdapter) u32 {
13631 return @intCast(adapter.globals.count());
13632 }
13633 };
13634
13635 const constant_adapter = ConstantAdapter{
13636 .builder = self,
13637 .globals = &globals,
13638 };
13639
13640 // Globals
13641 {
13642 var section_map: std.AutoArrayHashMapUnmanaged(String, void) = .empty;
13643 defer section_map.deinit(self.gpa);
13644 try section_map.ensureUnusedCapacity(self.gpa, globals.count());
13645
13646 for (self.variables.items) |variable| {
13647 if (variable.global.getReplacement(self) != .none) continue;
13648
13649 const section = blk: {
13650 if (variable.section == .none) break :blk 0;
13651 const gop = section_map.getOrPutAssumeCapacity(variable.section);
13652 if (!gop.found_existing) {
13653 try module_block.writeAbbrev(Module.String{
13654 .code = 5,
13655 .string = variable.section.slice(self).?,
13656 });
13657 }
13658 break :blk gop.index + 1;
13659 };
13660
13661 const initid = if (variable.init == .no_init)
13662 0
13663 else
13664 (constant_adapter.getConstantIndex(variable.init) + 1);
13665
13666 const strtab = variable.global.strtab(self);
13667
13668 const global = variable.global.ptrConst(self);
13669 try module_block.writeAbbrev(Module.Variable{
13670 .strtab_offset = strtab.offset,
13671 .strtab_size = strtab.size,
13672 .type_index = global.type,
13673 .is_const = .{
13674 .is_const = switch (variable.mutability) {
13675 .global => false,
13676 .constant => true,
13677 },
13678 .addr_space = global.addr_space,
13679 },
13680 .initid = initid,
13681 .linkage = global.linkage,
13682 .alignment = variable.alignment.toLlvm(),
13683 .section = section,
13684 .visibility = global.visibility,
13685 .thread_local = variable.thread_local,
13686 .unnamed_addr = global.unnamed_addr,
13687 .externally_initialized = global.externally_initialized,
13688 .dllstorageclass = global.dll_storage_class,
13689 .preemption = global.preemption,
13690 });
13691 }
13692
13693 for (self.functions.items) |func| {
13694 if (func.global.getReplacement(self) != .none) continue;
13695
13696 const section = blk: {
13697 if (func.section == .none) break :blk 0;
13698 const gop = section_map.getOrPutAssumeCapacity(func.section);
13699 if (!gop.found_existing) {
13700 try module_block.writeAbbrev(Module.String{
13701 .code = 5,
13702 .string = func.section.slice(self).?,
13703 });
13704 }
13705 break :blk gop.index + 1;
13706 };
13707
13708 const paramattr_index = if (self.function_attributes_set.getIndex(func.attributes)) |index|
13709 index + 1
13710 else
13711 0;
13712
13713 const strtab = func.global.strtab(self);
13714
13715 const global = func.global.ptrConst(self);
13716 try module_block.writeAbbrev(Module.Function{
13717 .strtab_offset = strtab.offset,
13718 .strtab_size = strtab.size,
13719 .type_index = global.type,
13720 .call_conv = func.call_conv,
13721 .is_proto = func.instructions.len == 0,
13722 .linkage = global.linkage,
13723 .paramattr = paramattr_index,
13724 .alignment = func.alignment.toLlvm(),
13725 .section = section,
13726 .visibility = global.visibility,
13727 .unnamed_addr = global.unnamed_addr,
13728 .dllstorageclass = global.dll_storage_class,
13729 .preemption = global.preemption,
13730 .addr_space = global.addr_space,
13731 });
13732 }
13733
13734 for (self.aliases.items) |alias| {
13735 if (alias.global.getReplacement(self) != .none) continue;
13736
13737 const strtab = alias.global.strtab(self);
13738
13739 const global = alias.global.ptrConst(self);
13740 try module_block.writeAbbrev(Module.Alias{
13741 .strtab_offset = strtab.offset,
13742 .strtab_size = strtab.size,
13743 .type_index = global.type,
13744 .addr_space = global.addr_space,
13745 .aliasee = constant_adapter.getConstantIndex(alias.aliasee),
13746 .linkage = global.linkage,
13747 .visibility = global.visibility,
13748 .thread_local = alias.thread_local,
13749 .unnamed_addr = global.unnamed_addr,
13750 .dllstorageclass = global.dll_storage_class,
13751 .preemption = global.preemption,
13752 });
13753 }
13754 }
13755
13756 // CONSTANTS_BLOCK
13757 {
13758 const Constants = ir.Constants;
13759 var constants_block = try module_block.enterSubBlock(Constants, true);
13760
13761 var current_type: Type = .none;
13762 const tags = self.constant_items.items(.tag);
13763 const datas = self.constant_items.items(.data);
13764 for (0..self.constant_items.len) |index| {
13765 record.clearRetainingCapacity();
13766 const constant: Constant = @enumFromInt(index);
13767 const constant_type = constant.typeOf(self);
13768 if (constant_type != current_type) {
13769 try constants_block.writeAbbrev(Constants.SetType{ .type_id = constant_type });
13770 current_type = constant_type;
13771 }
13772 const data = datas[index];
13773 switch (tags[index]) {
13774 .null,
13775 .zeroinitializer,
13776 .none,
13777 => try constants_block.writeAbbrev(Constants.Null{}),
13778 .undef => try constants_block.writeAbbrev(Constants.Undef{}),
13779 .poison => try constants_block.writeAbbrev(Constants.Poison{}),
13780 .positive_integer,
13781 .negative_integer,
13782 => |tag| {
13783 const extra: *align(@alignOf(std.math.big.Limb)) Constant.Integer =
13784 @ptrCast(self.constant_limbs.items[data..][0..Constant.Integer.limbs]);
13785 const bigint: std.math.big.int.Const = .{
13786 .limbs = self.constant_limbs
13787 .items[data + Constant.Integer.limbs ..][0..extra.limbs_len],
13788 .positive = switch (tag) {
13789 .positive_integer => true,
13790 .negative_integer => false,
13791 else => unreachable,
13792 },
13793 };
13794 const bit_count = extra.type.scalarBits(self);
13795 const val: i64 = if (bit_count <= 64)
13796 bigint.toInt(i64) catch unreachable
13797 else if (bigint.toInt(u64)) |val|
13798 @bitCast(val)
13799 else |_| {
13800 const limbs = try record.addManyAsSlice(
13801 self.gpa,
13802 std.math.divCeil(u24, bit_count, 64) catch unreachable,
13803 );
13804 bigint.writeTwosComplement(std.mem.sliceAsBytes(limbs), .little);
13805 for (limbs) |*limb| {
13806 const val = std.mem.littleToNative(i64, @bitCast(limb.*));
13807 limb.* = @bitCast(if (val >= 0)
13808 val << 1 | 0
13809 else
13810 -%val << 1 | 1);
13811 }
13812 try constants_block.writeUnabbrev(5, record.items);
13813 continue;
13814 };
13815 try constants_block.writeAbbrev(Constants.Integer{
13816 .value = @bitCast(if (val >= 0)
13817 val << 1 | 0
13818 else
13819 -%val << 1 | 1),
13820 });
13821 },
13822 .half,
13823 .bfloat,
13824 => try constants_block.writeAbbrev(Constants.Half{ .value = @truncate(data) }),
13825 .float => try constants_block.writeAbbrev(Constants.Float{ .value = data }),
13826 .double => {
13827 const extra = self.constantExtraData(Constant.Double, data);
13828 try constants_block.writeAbbrev(Constants.Double{
13829 .value = (@as(u64, extra.hi) << 32) | extra.lo,
13830 });
13831 },
13832 .x86_fp80 => {
13833 const extra = self.constantExtraData(Constant.Fp80, data);
13834 try constants_block.writeAbbrev(Constants.Fp80{
13835 .hi = @as(u64, extra.hi) << 48 | @as(u64, extra.lo_hi) << 16 |
13836 extra.lo_lo >> 16,
13837 .lo = @truncate(extra.lo_lo),
13838 });
13839 },
13840 .fp128,
13841 .ppc_fp128,
13842 => {
13843 const extra = self.constantExtraData(Constant.Fp128, data);
13844 try constants_block.writeAbbrev(Constants.Fp128{
13845 .lo = @as(u64, extra.lo_hi) << 32 | @as(u64, extra.lo_lo),
13846 .hi = @as(u64, extra.hi_hi) << 32 | @as(u64, extra.hi_lo),
13847 });
13848 },
13849 .array,
13850 .vector,
13851 .structure,
13852 .packed_structure,
13853 => {
13854 var extra = self.constantExtraDataTrail(Constant.Aggregate, data);
13855 const len: u32 = @intCast(extra.data.type.aggregateLen(self));
13856 const values = extra.trail.next(len, Constant, self);
13857
13858 try constants_block.writeAbbrevAdapted(
13859 Constants.Aggregate{ .values = values },
13860 constant_adapter,
13861 );
13862 },
13863 .splat => {
13864 const ConstantsWriter = @TypeOf(constants_block);
13865 const extra = self.constantExtraData(Constant.Splat, data);
13866 const vector_len = extra.type.vectorLen(self);
13867 const c = constant_adapter.getConstantIndex(extra.value);
13868
13869 try bitcode.writeBits(
13870 ConstantsWriter.abbrevId(Constants.Aggregate),
13871 ConstantsWriter.abbrev_len,
13872 );
13873 try bitcode.writeVBR(vector_len, 6);
13874 for (0..vector_len) |_| {
13875 try bitcode.writeBits(c, Constants.Aggregate.ops[1].array_fixed);
13876 }
13877 },
13878 .string => {
13879 const str: String = @enumFromInt(data);
13880 if (str == .none) {
13881 try constants_block.writeAbbrev(Constants.Null{});
13882 } else {
13883 const slice = str.slice(self).?;
13884 if (slice.len > 0 and slice[slice.len - 1] == 0)
13885 try constants_block.writeAbbrev(Constants.CString{ .string = slice[0 .. slice.len - 1] })
13886 else
13887 try constants_block.writeAbbrev(Constants.String{ .string = slice });
13888 }
13889 },
13890 .bitcast,
13891 .inttoptr,
13892 .ptrtoint,
13893 .addrspacecast,
13894 .trunc,
13895 => |tag| {
13896 const extra = self.constantExtraData(Constant.Cast, data);
13897 try constants_block.writeAbbrevAdapted(Constants.Cast{
13898 .type_index = extra.type,
13899 .val = extra.val,
13900 .opcode = tag.toCastOpcode(),
13901 }, constant_adapter);
13902 },
13903 .add,
13904 .@"add nsw",
13905 .@"add nuw",
13906 .sub,
13907 .@"sub nsw",
13908 .@"sub nuw",
13909 .shl,
13910 .xor,
13911 => |tag| {
13912 const extra = self.constantExtraData(Constant.Binary, data);
13913 try constants_block.writeAbbrevAdapted(Constants.Binary{
13914 .opcode = tag.toBinaryOpcode(),
13915 .lhs = extra.lhs,
13916 .rhs = extra.rhs,
13917 }, constant_adapter);
13918 },
13919 .getelementptr,
13920 .@"getelementptr inbounds",
13921 => |tag| {
13922 var extra = self.constantExtraDataTrail(Constant.GetElementPtr, data);
13923 const indices = extra.trail.next(extra.data.info.indices_len, Constant, self);
13924 try record.ensureUnusedCapacity(self.gpa, 1 + 2 + 2 * indices.len);
13925
13926 record.appendAssumeCapacity(@intFromEnum(extra.data.type));
13927
13928 record.appendAssumeCapacity(@intFromEnum(extra.data.base.typeOf(self)));
13929 record.appendAssumeCapacity(constant_adapter.getConstantIndex(extra.data.base));
13930
13931 for (indices) |i| {
13932 record.appendAssumeCapacity(@intFromEnum(i.typeOf(self)));
13933 record.appendAssumeCapacity(constant_adapter.getConstantIndex(i));
13934 }
13935
13936 try constants_block.writeUnabbrev(switch (tag) {
13937 .getelementptr => 12,
13938 .@"getelementptr inbounds" => 20,
13939 else => unreachable,
13940 }, record.items);
13941 },
13942 .@"asm",
13943 .@"asm sideeffect",
13944 .@"asm alignstack",
13945 .@"asm sideeffect alignstack",
13946 .@"asm inteldialect",
13947 .@"asm sideeffect inteldialect",
13948 .@"asm alignstack inteldialect",
13949 .@"asm sideeffect alignstack inteldialect",
13950 .@"asm unwind",
13951 .@"asm sideeffect unwind",
13952 .@"asm alignstack unwind",
13953 .@"asm sideeffect alignstack unwind",
13954 .@"asm inteldialect unwind",
13955 .@"asm sideeffect inteldialect unwind",
13956 .@"asm alignstack inteldialect unwind",
13957 .@"asm sideeffect alignstack inteldialect unwind",
13958 => |tag| {
13959 const extra = self.constantExtraData(Constant.Assembly, data);
13960
13961 const assembly_slice = extra.assembly.slice(self).?;
13962 const constraints_slice = extra.constraints.slice(self).?;
13963
13964 try record.ensureUnusedCapacity(self.gpa, 4 + assembly_slice.len + constraints_slice.len);
13965
13966 record.appendAssumeCapacity(@intFromEnum(extra.type));
13967 record.appendAssumeCapacity(switch (tag) {
13968 .@"asm" => 0,
13969 .@"asm sideeffect" => 0b0001,
13970 .@"asm sideeffect alignstack" => 0b0011,
13971 .@"asm sideeffect inteldialect" => 0b0101,
13972 .@"asm sideeffect alignstack inteldialect" => 0b0111,
13973 .@"asm sideeffect unwind" => 0b1001,
13974 .@"asm sideeffect alignstack unwind" => 0b1011,
13975 .@"asm sideeffect inteldialect unwind" => 0b1101,
13976 .@"asm sideeffect alignstack inteldialect unwind" => 0b1111,
13977 .@"asm alignstack" => 0b0010,
13978 .@"asm inteldialect" => 0b0100,
13979 .@"asm alignstack inteldialect" => 0b0110,
13980 .@"asm unwind" => 0b1000,
13981 .@"asm alignstack unwind" => 0b1010,
13982 .@"asm inteldialect unwind" => 0b1100,
13983 .@"asm alignstack inteldialect unwind" => 0b1110,
13984 else => unreachable,
13985 });
13986
13987 record.appendAssumeCapacity(assembly_slice.len);
13988 for (assembly_slice) |c| record.appendAssumeCapacity(c);
13989
13990 record.appendAssumeCapacity(constraints_slice.len);
13991 for (constraints_slice) |c| record.appendAssumeCapacity(c);
13992
13993 try constants_block.writeUnabbrev(30, record.items);
13994 },
13995 .blockaddress => {
13996 const extra = self.constantExtraData(Constant.BlockAddress, data);
13997 try constants_block.writeAbbrev(Constants.BlockAddress{
13998 .type_id = extra.function.typeOf(self),
13999 .function = constant_adapter.getConstantIndex(extra.function.toConst(self)),
14000 .block = @intFromEnum(extra.block),
14001 });
14002 },
14003 .dso_local_equivalent,
14004 .no_cfi,
14005 => |tag| {
14006 const function: Function.Index = @enumFromInt(data);
14007 try constants_block.writeAbbrev(Constants.DsoLocalEquivalentOrNoCfi{
14008 .code = switch (tag) {
14009 .dso_local_equivalent => 27,
14010 .no_cfi => 29,
14011 else => unreachable,
14012 },
14013 .type_id = function.typeOf(self),
14014 .function = constant_adapter.getConstantIndex(function.toConst(self)),
14015 });
14016 },
14017 }
14018 }
14019
14020 try constants_block.end();
14021 }
14022
14023 // METADATA_KIND_BLOCK
14024 {
14025 const MetadataKindBlock = ir.MetadataKindBlock;
14026 var metadata_kind_block = try module_block.enterSubBlock(MetadataKindBlock, true);
14027
14028 inline for (@typeInfo(ir.FixedMetadataKind).@"enum".fields) |field| {
14029 // don't include `dbg` in stripped functions
14030 if (!(self.strip and std.mem.eql(u8, field.name, "dbg"))) {
14031 try metadata_kind_block.writeAbbrev(MetadataKindBlock.Kind{
14032 .id = field.value,
14033 .name = field.name,
14034 });
14035 }
14036 }
14037
14038 try metadata_kind_block.end();
14039 }
14040
14041 const MetadataAdapter = struct {
14042 builder: *const Builder,
14043 constant_adapter: ConstantAdapter,
14044
14045 pub fn init(
14046 builder: *const Builder,
14047 const_adapter: ConstantAdapter,
14048 ) @This() {
14049 return .{
14050 .builder = builder,
14051 .constant_adapter = const_adapter,
14052 };
14053 }
14054
14055 pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) {
14056 _ = field_name;
14057 const Ty = @TypeOf(value);
14058 return switch (Ty) {
14059 Metadata => @enumFromInt(adapter.getMetadataIndex(value)),
14060 MetadataString => @enumFromInt(adapter.getMetadataStringIndex(value)),
14061 Constant => @enumFromInt(adapter.constant_adapter.getConstantIndex(value)),
14062 else => value,
14063 };
14064 }
14065
14066 pub fn getMetadataIndex(adapter: @This(), metadata: Metadata) u32 {
14067 if (metadata == .none) return 0;
14068 return @intCast(adapter.builder.metadata_string_map.count() +
14069 @intFromEnum(metadata.unwrap(adapter.builder)) - 1);
14070 }
14071
14072 pub fn getMetadataStringIndex(_: @This(), metadata_string: MetadataString) u32 {
14073 return @intFromEnum(metadata_string);
14074 }
14075 };
14076
14077 const metadata_adapter = MetadataAdapter.init(self, constant_adapter);
14078
14079 // METADATA_BLOCK
14080 {
14081 const MetadataBlock = ir.MetadataBlock;
14082 var metadata_block = try module_block.enterSubBlock(MetadataBlock, true);
14083
14084 const MetadataBlockWriter = @TypeOf(metadata_block);
14085
14086 // Emit all MetadataStrings
14087 if (self.metadata_string_map.count() > 1) {
14088 const strings_offset, const strings_size = blk: {
14089 var strings_offset: u32 = 0;
14090 var strings_size: u32 = 0;
14091 for (1..self.metadata_string_map.count()) |metadata_string_index| {
14092 const metadata_string: MetadataString = @enumFromInt(metadata_string_index);
14093 const slice = metadata_string.slice(self);
14094 strings_offset += bitcode.bitsVBR(@as(u32, @intCast(slice.len)), 6);
14095 strings_size += @intCast(slice.len * 8);
14096 }
14097 break :blk .{
14098 std.mem.alignForward(u32, strings_offset, 32) / 8,
14099 std.mem.alignForward(u32, strings_size, 32) / 8,
14100 };
14101 };
14102
14103 try bitcode.writeBits(
14104 comptime MetadataBlockWriter.abbrevId(MetadataBlock.Strings),
14105 MetadataBlockWriter.abbrev_len,
14106 );
14107
14108 try bitcode.writeVBR(@as(u32, @intCast(self.metadata_string_map.count() - 1)), 6);
14109 try bitcode.writeVBR(strings_offset, 6);
14110
14111 try bitcode.writeVBR(strings_size + strings_offset, 6);
14112
14113 try bitcode.alignTo32();
14114
14115 for (1..self.metadata_string_map.count()) |metadata_string_index| {
14116 const metadata_string: MetadataString = @enumFromInt(metadata_string_index);
14117 const slice = metadata_string.slice(self);
14118 try bitcode.writeVBR(@as(u32, @intCast(slice.len)), 6);
14119 }
14120
14121 try bitcode.writeBlob(self.metadata_string_bytes.items);
14122 }
14123
14124 for (
14125 self.metadata_items.items(.tag)[1..],
14126 self.metadata_items.items(.data)[1..],
14127 ) |tag, data| {
14128 record.clearRetainingCapacity();
14129 switch (tag) {
14130 .none => unreachable,
14131 .file => {
14132 const extra = self.metadataExtraData(Metadata.File, data);
14133
14134 try metadata_block.writeAbbrevAdapted(MetadataBlock.File{
14135 .filename = extra.filename,
14136 .directory = extra.directory,
14137 }, metadata_adapter);
14138 },
14139 .compile_unit,
14140 .@"compile_unit optimized",
14141 => |kind| {
14142 const extra = self.metadataExtraData(Metadata.CompileUnit, data);
14143 try metadata_block.writeAbbrevAdapted(MetadataBlock.CompileUnit{
14144 .file = extra.file,
14145 .producer = extra.producer,
14146 .is_optimized = switch (kind) {
14147 .compile_unit => false,
14148 .@"compile_unit optimized" => true,
14149 else => unreachable,
14150 },
14151 .enums = extra.enums,
14152 .globals = extra.globals,
14153 }, metadata_adapter);
14154 },
14155 .subprogram,
14156 .@"subprogram local",
14157 .@"subprogram definition",
14158 .@"subprogram local definition",
14159 .@"subprogram optimized",
14160 .@"subprogram optimized local",
14161 .@"subprogram optimized definition",
14162 .@"subprogram optimized local definition",
14163 => |kind| {
14164 const extra = self.metadataExtraData(Metadata.Subprogram, data);
14165
14166 try metadata_block.writeAbbrevAdapted(MetadataBlock.Subprogram{
14167 .scope = extra.file,
14168 .name = extra.name,
14169 .linkage_name = extra.linkage_name,
14170 .file = extra.file,
14171 .line = extra.line,
14172 .ty = extra.ty,
14173 .scope_line = extra.scope_line,
14174 .sp_flags = @bitCast(@as(u32, @as(u3, @intCast(
14175 @intFromEnum(kind) - @intFromEnum(Metadata.Tag.subprogram),
14176 ))) << 2),
14177 .flags = extra.di_flags,
14178 .compile_unit = extra.compile_unit,
14179 }, metadata_adapter);
14180 },
14181 .lexical_block => {
14182 const extra = self.metadataExtraData(Metadata.LexicalBlock, data);
14183 try metadata_block.writeAbbrevAdapted(MetadataBlock.LexicalBlock{
14184 .scope = extra.scope,
14185 .file = extra.file,
14186 .line = extra.line,
14187 .column = extra.column,
14188 }, metadata_adapter);
14189 },
14190 .location => {
14191 const extra = self.metadataExtraData(Metadata.Location, data);
14192 assert(extra.scope != .none);
14193 try metadata_block.writeAbbrev(MetadataBlock.Location{
14194 .line = extra.line,
14195 .column = extra.column,
14196 .scope = metadata_adapter.getMetadataIndex(extra.scope) - 1,
14197 .inlined_at = @enumFromInt(metadata_adapter.getMetadataIndex(extra.inlined_at)),
14198 });
14199 },
14200 .basic_bool_type,
14201 .basic_unsigned_type,
14202 .basic_signed_type,
14203 .basic_float_type,
14204 => |kind| {
14205 const extra = self.metadataExtraData(Metadata.BasicType, data);
14206 try metadata_block.writeAbbrevAdapted(MetadataBlock.BasicType{
14207 .name = extra.name,
14208 .size_in_bits = extra.bitSize(),
14209 .encoding = switch (kind) {
14210 .basic_bool_type => DW.ATE.boolean,
14211 .basic_unsigned_type => DW.ATE.unsigned,
14212 .basic_signed_type => DW.ATE.signed,
14213 .basic_float_type => DW.ATE.float,
14214 else => unreachable,
14215 },
14216 }, metadata_adapter);
14217 },
14218 .composite_struct_type,
14219 .composite_union_type,
14220 .composite_enumeration_type,
14221 .composite_array_type,
14222 .composite_vector_type,
14223 => |kind| {
14224 const extra = self.metadataExtraData(Metadata.CompositeType, data);
14225
14226 try metadata_block.writeAbbrevAdapted(MetadataBlock.CompositeType{
14227 .tag = switch (kind) {
14228 .composite_struct_type => DW.TAG.structure_type,
14229 .composite_union_type => DW.TAG.union_type,
14230 .composite_enumeration_type => DW.TAG.enumeration_type,
14231 .composite_array_type, .composite_vector_type => DW.TAG.array_type,
14232 else => unreachable,
14233 },
14234 .name = extra.name,
14235 .file = extra.file,
14236 .line = extra.line,
14237 .scope = extra.scope,
14238 .underlying_type = extra.underlying_type,
14239 .size_in_bits = extra.bitSize(),
14240 .align_in_bits = extra.bitAlign(),
14241 .flags = if (kind == .composite_vector_type) .{ .Vector = true } else .{},
14242 .elements = extra.fields_tuple,
14243 }, metadata_adapter);
14244 },
14245 .derived_pointer_type,
14246 .derived_member_type,
14247 => |kind| {
14248 const extra = self.metadataExtraData(Metadata.DerivedType, data);
14249 try metadata_block.writeAbbrevAdapted(MetadataBlock.DerivedType{
14250 .tag = switch (kind) {
14251 .derived_pointer_type => DW.TAG.pointer_type,
14252 .derived_member_type => DW.TAG.member,
14253 else => unreachable,
14254 },
14255 .name = extra.name,
14256 .file = extra.file,
14257 .line = extra.line,
14258 .scope = extra.scope,
14259 .underlying_type = extra.underlying_type,
14260 .size_in_bits = extra.bitSize(),
14261 .align_in_bits = extra.bitAlign(),
14262 .offset_in_bits = extra.bitOffset(),
14263 }, metadata_adapter);
14264 },
14265 .subroutine_type => {
14266 const extra = self.metadataExtraData(Metadata.SubroutineType, data);
14267
14268 try metadata_block.writeAbbrevAdapted(MetadataBlock.SubroutineType{
14269 .types = extra.types_tuple,
14270 }, metadata_adapter);
14271 },
14272 .enumerator_unsigned,
14273 .enumerator_signed_positive,
14274 .enumerator_signed_negative,
14275 => |kind| {
14276 const extra = self.metadataExtraData(Metadata.Enumerator, data);
14277 const bigint: std.math.big.int.Const = .{
14278 .limbs = self.metadata_limbs.items[extra.limbs_index..][0..extra.limbs_len],
14279 .positive = switch (kind) {
14280 .enumerator_unsigned,
14281 .enumerator_signed_positive,
14282 => true,
14283 .enumerator_signed_negative => false,
14284 else => unreachable,
14285 },
14286 };
14287 const flags: MetadataBlock.Enumerator.Flags = .{
14288 .unsigned = switch (kind) {
14289 .enumerator_unsigned => true,
14290 .enumerator_signed_positive,
14291 .enumerator_signed_negative,
14292 => false,
14293 else => unreachable,
14294 },
14295 };
14296 const val: i64 = if (bigint.toInt(i64)) |val|
14297 val
14298 else |_| if (bigint.toInt(u64)) |val|
14299 @bitCast(val)
14300 else |_| {
14301 const limbs_len = std.math.divCeil(u32, extra.bit_width, 64) catch unreachable;
14302 try record.ensureTotalCapacity(self.gpa, 3 + limbs_len);
14303 record.appendAssumeCapacity(@as(
14304 @typeInfo(MetadataBlock.Enumerator.Flags).@"struct".backing_integer.?,
14305 @bitCast(flags),
14306 ));
14307 record.appendAssumeCapacity(extra.bit_width);
14308 record.appendAssumeCapacity(metadata_adapter.getMetadataStringIndex(extra.name));
14309 const limbs = record.addManyAsSliceAssumeCapacity(limbs_len);
14310 bigint.writeTwosComplement(std.mem.sliceAsBytes(limbs), .little);
14311 for (limbs) |*limb| {
14312 const val = std.mem.littleToNative(i64, @bitCast(limb.*));
14313 limb.* = @bitCast(if (val >= 0)
14314 val << 1 | 0
14315 else
14316 -%val << 1 | 1);
14317 }
14318 try metadata_block.writeUnabbrev(@intFromEnum(MetadataBlock.Enumerator.id), record.items);
14319 continue;
14320 };
14321 try metadata_block.writeAbbrevAdapted(MetadataBlock.Enumerator{
14322 .flags = flags,
14323 .bit_width = extra.bit_width,
14324 .name = extra.name,
14325 .value = @bitCast(if (val >= 0)
14326 val << 1 | 0
14327 else
14328 -%val << 1 | 1),
14329 }, metadata_adapter);
14330 },
14331 .subrange => {
14332 const extra = self.metadataExtraData(Metadata.Subrange, data);
14333
14334 try metadata_block.writeAbbrevAdapted(MetadataBlock.Subrange{
14335 .count = extra.count,
14336 .lower_bound = extra.lower_bound,
14337 }, metadata_adapter);
14338 },
14339 .expression => {
14340 var extra = self.metadataExtraDataTrail(Metadata.Expression, data);
14341
14342 const elements = extra.trail.next(extra.data.elements_len, u32, self);
14343
14344 try metadata_block.writeAbbrevAdapted(MetadataBlock.Expression{
14345 .elements = elements,
14346 }, metadata_adapter);
14347 },
14348 .tuple => {
14349 var extra = self.metadataExtraDataTrail(Metadata.Tuple, data);
14350
14351 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
14352
14353 try metadata_block.writeAbbrevAdapted(MetadataBlock.Node{
14354 .elements = elements,
14355 }, metadata_adapter);
14356 },
14357 .str_tuple => {
14358 var extra = self.metadataExtraDataTrail(Metadata.StrTuple, data);
14359
14360 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
14361
14362 const all_elems = try self.gpa.alloc(Metadata, elements.len + 1);
14363 defer self.gpa.free(all_elems);
14364 all_elems[0] = @enumFromInt(metadata_adapter.getMetadataStringIndex(extra.data.str));
14365 for (elements, all_elems[1..]) |elem, *out_elem| {
14366 out_elem.* = @enumFromInt(metadata_adapter.getMetadataIndex(elem));
14367 }
14368
14369 try metadata_block.writeAbbrev(MetadataBlock.Node{
14370 .elements = all_elems,
14371 });
14372 },
14373 .module_flag => {
14374 const extra = self.metadataExtraData(Metadata.ModuleFlag, data);
14375 try metadata_block.writeAbbrev(MetadataBlock.Node{
14376 .elements = &.{
14377 @enumFromInt(metadata_adapter.getMetadataIndex(extra.behavior)),
14378 @enumFromInt(metadata_adapter.getMetadataStringIndex(extra.name)),
14379 @enumFromInt(metadata_adapter.getMetadataIndex(extra.constant)),
14380 },
14381 });
14382 },
14383 .local_var => {
14384 const extra = self.metadataExtraData(Metadata.LocalVar, data);
14385 try metadata_block.writeAbbrevAdapted(MetadataBlock.LocalVar{
14386 .scope = extra.scope,
14387 .name = extra.name,
14388 .file = extra.file,
14389 .line = extra.line,
14390 .ty = extra.ty,
14391 }, metadata_adapter);
14392 },
14393 .parameter => {
14394 const extra = self.metadataExtraData(Metadata.Parameter, data);
14395 try metadata_block.writeAbbrevAdapted(MetadataBlock.Parameter{
14396 .scope = extra.scope,
14397 .name = extra.name,
14398 .file = extra.file,
14399 .line = extra.line,
14400 .ty = extra.ty,
14401 .arg = extra.arg_no,
14402 }, metadata_adapter);
14403 },
14404 .global_var,
14405 .@"global_var local",
14406 => |kind| {
14407 const extra = self.metadataExtraData(Metadata.GlobalVar, data);
14408 try metadata_block.writeAbbrevAdapted(MetadataBlock.GlobalVar{
14409 .scope = extra.scope,
14410 .name = extra.name,
14411 .linkage_name = extra.linkage_name,
14412 .file = extra.file,
14413 .line = extra.line,
14414 .ty = extra.ty,
14415 .local = kind == .@"global_var local",
14416 }, metadata_adapter);
14417 },
14418 .global_var_expression => {
14419 const extra = self.metadataExtraData(Metadata.GlobalVarExpression, data);
14420 try metadata_block.writeAbbrevAdapted(MetadataBlock.GlobalVarExpression{
14421 .variable = extra.variable,
14422 .expression = extra.expression,
14423 }, metadata_adapter);
14424 },
14425 .constant => {
14426 const constant: Constant = @enumFromInt(data);
14427 try metadata_block.writeAbbrevAdapted(MetadataBlock.Constant{
14428 .ty = constant.typeOf(self),
14429 .constant = constant,
14430 }, metadata_adapter);
14431 },
14432 }
14433 }
14434
14435 // Write named metadata
14436 for (self.metadata_named.keys(), self.metadata_named.values()) |name, operands| {
14437 const slice = name.slice(self);
14438 try metadata_block.writeAbbrev(MetadataBlock.Name{
14439 .name = slice,
14440 });
14441
14442 const elements = self.metadata_extra.items[operands.index..][0..operands.len];
14443 for (elements) |*e| {
14444 e.* = metadata_adapter.getMetadataIndex(@enumFromInt(e.*)) - 1;
14445 }
14446
14447 try metadata_block.writeAbbrev(MetadataBlock.NamedNode{
14448 .elements = @ptrCast(elements),
14449 });
14450 }
14451
14452 // Write global attached metadata
14453 {
14454 for (globals.keys()) |global| {
14455 const global_ptr = global.ptrConst(self);
14456 if (global_ptr.dbg == .none) continue;
14457
14458 switch (global_ptr.kind) {
14459 .function => |f| if (f.ptrConst(self).instructions.len != 0) continue,
14460 else => {},
14461 }
14462
14463 try metadata_block.writeAbbrev(MetadataBlock.GlobalDeclAttachment{
14464 .value = @enumFromInt(constant_adapter.getConstantIndex(global.toConst())),
14465 .kind = .dbg,
14466 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(global_ptr.dbg) - 1),
14467 });
14468 }
14469 }
14470
14471 try metadata_block.end();
14472 }
14473
14474 // OPERAND_BUNDLE_TAGS_BLOCK
14475 {
14476 const OperandBundleTags = ir.OperandBundleTags;
14477 var operand_bundle_tags_block = try module_block.enterSubBlock(OperandBundleTags, true);
14478
14479 try operand_bundle_tags_block.writeAbbrev(OperandBundleTags.OperandBundleTag{
14480 .tag = "cold",
14481 });
14482
14483 try operand_bundle_tags_block.end();
14484 }
14485
14486 // Block info
14487 {
14488 const BlockInfo = ir.BlockInfo;
14489 var block_info_block = try module_block.enterSubBlock(BlockInfo, true);
14490
14491 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.FunctionBlock.id});
14492 inline for (ir.FunctionBlock.abbrevs) |abbrev| {
14493 try block_info_block.defineAbbrev(&abbrev.ops);
14494 }
14495
14496 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.FunctionValueSymbolTable.id});
14497 inline for (ir.FunctionValueSymbolTable.abbrevs) |abbrev| {
14498 try block_info_block.defineAbbrev(&abbrev.ops);
14499 }
14500
14501 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.FunctionMetadataBlock.id});
14502 inline for (ir.FunctionMetadataBlock.abbrevs) |abbrev| {
14503 try block_info_block.defineAbbrev(&abbrev.ops);
14504 }
14505
14506 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.MetadataAttachmentBlock.id});
14507 inline for (ir.MetadataAttachmentBlock.abbrevs) |abbrev| {
14508 try block_info_block.defineAbbrev(&abbrev.ops);
14509 }
14510
14511 try block_info_block.end();
14512 }
14513
14514 // FUNCTION_BLOCKS
14515 {
14516 const FunctionAdapter = struct {
14517 constant_adapter: ConstantAdapter,
14518 metadata_adapter: MetadataAdapter,
14519 func: *const Function,
14520 instruction_index: Function.Instruction.Index,
14521
14522 pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) {
14523 _ = field_name;
14524 const Ty = @TypeOf(value);
14525 return switch (Ty) {
14526 Value => @enumFromInt(adapter.getOffsetValueIndex(value)),
14527 Constant => @enumFromInt(adapter.getOffsetConstantIndex(value)),
14528 FunctionAttributes => @enumFromInt(switch (value) {
14529 .none => 0,
14530 else => 1 + adapter.constant_adapter.builder.function_attributes_set.getIndex(value).?,
14531 }),
14532 else => value,
14533 };
14534 }
14535
14536 pub fn getValueIndex(adapter: @This(), value: Value) u32 {
14537 return @intCast(switch (value.unwrap()) {
14538 .instruction => |instruction| instruction.valueIndex(adapter.func) + adapter.firstInstr(),
14539 .constant => |constant| adapter.constant_adapter.getConstantIndex(constant),
14540 .metadata => |metadata| {
14541 const real_metadata = metadata.unwrap(adapter.metadata_adapter.builder);
14542 if (@intFromEnum(real_metadata) < Metadata.first_local_metadata)
14543 return adapter.metadata_adapter.getMetadataIndex(real_metadata) - 1;
14544
14545 return @intCast(@intFromEnum(metadata) -
14546 Metadata.first_local_metadata +
14547 adapter.metadata_adapter.builder.metadata_string_map.count() - 1 +
14548 adapter.metadata_adapter.builder.metadata_map.count() - 1);
14549 },
14550 });
14551 }
14552
14553 pub fn getOffsetValueIndex(adapter: @This(), value: Value) u32 {
14554 return adapter.offset() -% adapter.getValueIndex(value);
14555 }
14556
14557 pub fn getOffsetValueSignedIndex(adapter: @This(), value: Value) i32 {
14558 const signed_offset: i32 = @intCast(adapter.offset());
14559 const signed_value: i32 = @intCast(adapter.getValueIndex(value));
14560 return signed_offset - signed_value;
14561 }
14562
14563 pub fn getOffsetConstantIndex(adapter: @This(), constant: Constant) u32 {
14564 return adapter.offset() - adapter.constant_adapter.getConstantIndex(constant);
14565 }
14566
14567 pub fn offset(adapter: @This()) u32 {
14568 return adapter.instruction_index.valueIndex(adapter.func) + adapter.firstInstr();
14569 }
14570
14571 fn firstInstr(adapter: @This()) u32 {
14572 return adapter.constant_adapter.numConstants();
14573 }
14574 };
14575
14576 for (self.functions.items, 0..) |func, func_index| {
14577 const FunctionBlock = ir.FunctionBlock;
14578 if (func.global.getReplacement(self) != .none) continue;
14579
14580 if (func.instructions.len == 0) continue;
14581
14582 var function_block = try module_block.enterSubBlock(FunctionBlock, false);
14583
14584 try function_block.writeAbbrev(FunctionBlock.DeclareBlocks{ .num_blocks = func.blocks.len });
14585
14586 var adapter: FunctionAdapter = .{
14587 .constant_adapter = constant_adapter,
14588 .metadata_adapter = metadata_adapter,
14589 .func = &func,
14590 .instruction_index = @enumFromInt(0),
14591 };
14592
14593 // Emit function level metadata block
14594 if (!func.strip and func.debug_values.len > 0) {
14595 const MetadataBlock = ir.FunctionMetadataBlock;
14596 var metadata_block = try function_block.enterSubBlock(MetadataBlock, false);
14597
14598 for (func.debug_values) |value| {
14599 try metadata_block.writeAbbrev(MetadataBlock.Value{
14600 .ty = value.typeOf(@enumFromInt(func_index), self),
14601 .value = @enumFromInt(adapter.getValueIndex(value.toValue())),
14602 });
14603 }
14604
14605 try metadata_block.end();
14606 }
14607
14608 const tags = func.instructions.items(.tag);
14609 const datas = func.instructions.items(.data);
14610
14611 var has_location = false;
14612
14613 var block_incoming_len: u32 = undefined;
14614 for (tags, datas, 0..) |tag, data, instr_index| {
14615 adapter.instruction_index = @enumFromInt(instr_index);
14616 record.clearRetainingCapacity();
14617
14618 switch (tag) {
14619 .arg => continue,
14620 .block => {
14621 block_incoming_len = data;
14622 continue;
14623 },
14624 .@"unreachable" => try function_block.writeAbbrev(FunctionBlock.Unreachable{}),
14625 .call,
14626 .@"musttail call",
14627 .@"notail call",
14628 .@"tail call",
14629 => |kind| {
14630 var extra = func.extraDataTrail(Function.Instruction.Call, data);
14631
14632 if (extra.data.info.has_op_bundle_cold) {
14633 try function_block.writeAbbrev(FunctionBlock.ColdOperandBundle{});
14634 }
14635
14636 const call_conv = extra.data.info.call_conv;
14637 const args = extra.trail.next(extra.data.args_len, Value, &func);
14638 try function_block.writeAbbrevAdapted(FunctionBlock.Call{
14639 .attributes = extra.data.attributes,
14640 .call_type = switch (kind) {
14641 .call => .{ .call_conv = call_conv },
14642 .@"tail call" => .{ .tail = true, .call_conv = call_conv },
14643 .@"musttail call" => .{ .must_tail = true, .call_conv = call_conv },
14644 .@"notail call" => .{ .no_tail = true, .call_conv = call_conv },
14645 else => unreachable,
14646 },
14647 .type_id = extra.data.ty,
14648 .callee = extra.data.callee,
14649 .args = args,
14650 }, adapter);
14651 },
14652 .@"call fast",
14653 .@"musttail call fast",
14654 .@"notail call fast",
14655 .@"tail call fast",
14656 => |kind| {
14657 var extra = func.extraDataTrail(Function.Instruction.Call, data);
14658
14659 if (extra.data.info.has_op_bundle_cold) {
14660 try function_block.writeAbbrev(FunctionBlock.ColdOperandBundle{});
14661 }
14662
14663 const call_conv = extra.data.info.call_conv;
14664 const args = extra.trail.next(extra.data.args_len, Value, &func);
14665 try function_block.writeAbbrevAdapted(FunctionBlock.CallFast{
14666 .attributes = extra.data.attributes,
14667 .call_type = switch (kind) {
14668 .@"call fast" => .{ .call_conv = call_conv },
14669 .@"tail call fast" => .{ .tail = true, .call_conv = call_conv },
14670 .@"musttail call fast" => .{ .must_tail = true, .call_conv = call_conv },
14671 .@"notail call fast" => .{ .no_tail = true, .call_conv = call_conv },
14672 else => unreachable,
14673 },
14674 .fast_math = FastMath.fast,
14675 .type_id = extra.data.ty,
14676 .callee = extra.data.callee,
14677 .args = args,
14678 }, adapter);
14679 },
14680 .add,
14681 .@"and",
14682 .fadd,
14683 .fdiv,
14684 .fmul,
14685 .mul,
14686 .frem,
14687 .fsub,
14688 .sdiv,
14689 .sub,
14690 .udiv,
14691 .xor,
14692 .shl,
14693 .lshr,
14694 .@"or",
14695 .urem,
14696 .srem,
14697 .ashr,
14698 => |kind| {
14699 const extra = func.extraData(Function.Instruction.Binary, data);
14700 try function_block.writeAbbrev(FunctionBlock.Binary{
14701 .opcode = kind.toBinaryOpcode(),
14702 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14703 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14704 });
14705 },
14706 .@"sdiv exact",
14707 .@"udiv exact",
14708 .@"lshr exact",
14709 .@"ashr exact",
14710 => |kind| {
14711 const extra = func.extraData(Function.Instruction.Binary, data);
14712 try function_block.writeAbbrev(FunctionBlock.BinaryExact{
14713 .opcode = kind.toBinaryOpcode(),
14714 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14715 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14716 });
14717 },
14718 .@"add nsw",
14719 .@"add nuw",
14720 .@"add nuw nsw",
14721 .@"mul nsw",
14722 .@"mul nuw",
14723 .@"mul nuw nsw",
14724 .@"sub nsw",
14725 .@"sub nuw",
14726 .@"sub nuw nsw",
14727 .@"shl nsw",
14728 .@"shl nuw",
14729 .@"shl nuw nsw",
14730 => |kind| {
14731 const extra = func.extraData(Function.Instruction.Binary, data);
14732 try function_block.writeAbbrev(FunctionBlock.BinaryNoWrap{
14733 .opcode = kind.toBinaryOpcode(),
14734 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14735 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14736 .flags = switch (kind) {
14737 .@"add nsw",
14738 .@"mul nsw",
14739 .@"sub nsw",
14740 .@"shl nsw",
14741 => .{ .no_unsigned_wrap = false, .no_signed_wrap = true },
14742 .@"add nuw",
14743 .@"mul nuw",
14744 .@"sub nuw",
14745 .@"shl nuw",
14746 => .{ .no_unsigned_wrap = true, .no_signed_wrap = false },
14747 .@"add nuw nsw",
14748 .@"mul nuw nsw",
14749 .@"sub nuw nsw",
14750 .@"shl nuw nsw",
14751 => .{ .no_unsigned_wrap = true, .no_signed_wrap = true },
14752 else => unreachable,
14753 },
14754 });
14755 },
14756 .@"fadd fast",
14757 .@"fdiv fast",
14758 .@"fmul fast",
14759 .@"frem fast",
14760 .@"fsub fast",
14761 => |kind| {
14762 const extra = func.extraData(Function.Instruction.Binary, data);
14763 try function_block.writeAbbrev(FunctionBlock.BinaryFast{
14764 .opcode = kind.toBinaryOpcode(),
14765 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14766 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14767 .fast_math = FastMath.fast,
14768 });
14769 },
14770 .alloca,
14771 .@"alloca inalloca",
14772 => |kind| {
14773 const extra = func.extraData(Function.Instruction.Alloca, data);
14774 const alignment = extra.info.alignment.toLlvm();
14775 try function_block.writeAbbrev(FunctionBlock.Alloca{
14776 .inst_type = extra.type,
14777 .len_type = extra.len.typeOf(@enumFromInt(func_index), self),
14778 .len_value = adapter.getValueIndex(extra.len),
14779 .flags = .{
14780 .align_lower = @truncate(alignment),
14781 .inalloca = kind == .@"alloca inalloca",
14782 .explicit_type = true,
14783 .swift_error = false,
14784 .align_upper = @truncate(alignment << 5),
14785 },
14786 });
14787 },
14788 .bitcast,
14789 .inttoptr,
14790 .ptrtoint,
14791 .fptosi,
14792 .fptoui,
14793 .sitofp,
14794 .uitofp,
14795 .addrspacecast,
14796 .fptrunc,
14797 .trunc,
14798 .fpext,
14799 .sext,
14800 .zext,
14801 => |kind| {
14802 const extra = func.extraData(Function.Instruction.Cast, data);
14803 try function_block.writeAbbrev(FunctionBlock.Cast{
14804 .val = adapter.getOffsetValueIndex(extra.val),
14805 .type_index = extra.type,
14806 .opcode = kind.toCastOpcode(),
14807 });
14808 },
14809 .@"fcmp false",
14810 .@"fcmp oeq",
14811 .@"fcmp oge",
14812 .@"fcmp ogt",
14813 .@"fcmp ole",
14814 .@"fcmp olt",
14815 .@"fcmp one",
14816 .@"fcmp ord",
14817 .@"fcmp true",
14818 .@"fcmp ueq",
14819 .@"fcmp uge",
14820 .@"fcmp ugt",
14821 .@"fcmp ule",
14822 .@"fcmp ult",
14823 .@"fcmp une",
14824 .@"fcmp uno",
14825 .@"icmp eq",
14826 .@"icmp ne",
14827 .@"icmp sge",
14828 .@"icmp sgt",
14829 .@"icmp sle",
14830 .@"icmp slt",
14831 .@"icmp uge",
14832 .@"icmp ugt",
14833 .@"icmp ule",
14834 .@"icmp ult",
14835 => |kind| {
14836 const extra = func.extraData(Function.Instruction.Binary, data);
14837 try function_block.writeAbbrev(FunctionBlock.Cmp{
14838 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14839 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14840 .pred = kind.toCmpPredicate(),
14841 });
14842 },
14843 .@"fcmp fast false",
14844 .@"fcmp fast oeq",
14845 .@"fcmp fast oge",
14846 .@"fcmp fast ogt",
14847 .@"fcmp fast ole",
14848 .@"fcmp fast olt",
14849 .@"fcmp fast one",
14850 .@"fcmp fast ord",
14851 .@"fcmp fast true",
14852 .@"fcmp fast ueq",
14853 .@"fcmp fast uge",
14854 .@"fcmp fast ugt",
14855 .@"fcmp fast ule",
14856 .@"fcmp fast ult",
14857 .@"fcmp fast une",
14858 .@"fcmp fast uno",
14859 => |kind| {
14860 const extra = func.extraData(Function.Instruction.Binary, data);
14861 try function_block.writeAbbrev(FunctionBlock.CmpFast{
14862 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14863 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14864 .pred = kind.toCmpPredicate(),
14865 .fast_math = FastMath.fast,
14866 });
14867 },
14868 .fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{
14869 .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
14870 }),
14871 .@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{
14872 .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
14873 .fast_math = FastMath.fast,
14874 }),
14875 .extractvalue => {
14876 var extra = func.extraDataTrail(Function.Instruction.ExtractValue, data);
14877 const indices = extra.trail.next(extra.data.indices_len, u32, &func);
14878 try function_block.writeAbbrev(FunctionBlock.ExtractValue{
14879 .val = adapter.getOffsetValueIndex(extra.data.val),
14880 .indices = indices,
14881 });
14882 },
14883 .extractelement => {
14884 const extra = func.extraData(Function.Instruction.ExtractElement, data);
14885 try function_block.writeAbbrev(FunctionBlock.ExtractElement{
14886 .val = adapter.getOffsetValueIndex(extra.val),
14887 .index = adapter.getOffsetValueIndex(extra.index),
14888 });
14889 },
14890 .indirectbr => {
14891 var extra =
14892 func.extraDataTrail(Function.Instruction.IndirectBr, datas[instr_index]);
14893 const targets =
14894 extra.trail.next(extra.data.targets_len, Function.Block.Index, &func);
14895 try function_block.writeAbbrevAdapted(
14896 FunctionBlock.IndirectBr{
14897 .ty = extra.data.addr.typeOf(@enumFromInt(func_index), self),
14898 .addr = extra.data.addr,
14899 .targets = targets,
14900 },
14901 adapter,
14902 );
14903 },
14904 .insertelement => {
14905 const extra = func.extraData(Function.Instruction.InsertElement, data);
14906 try function_block.writeAbbrev(FunctionBlock.InsertElement{
14907 .val = adapter.getOffsetValueIndex(extra.val),
14908 .elem = adapter.getOffsetValueIndex(extra.elem),
14909 .index = adapter.getOffsetValueIndex(extra.index),
14910 });
14911 },
14912 .insertvalue => {
14913 var extra = func.extraDataTrail(Function.Instruction.InsertValue, datas[instr_index]);
14914 const indices = extra.trail.next(extra.data.indices_len, u32, &func);
14915 try function_block.writeAbbrev(FunctionBlock.InsertValue{
14916 .val = adapter.getOffsetValueIndex(extra.data.val),
14917 .elem = adapter.getOffsetValueIndex(extra.data.elem),
14918 .indices = indices,
14919 });
14920 },
14921 .select => {
14922 const extra = func.extraData(Function.Instruction.Select, data);
14923 try function_block.writeAbbrev(FunctionBlock.Select{
14924 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14925 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14926 .cond = adapter.getOffsetValueIndex(extra.cond),
14927 });
14928 },
14929 .@"select fast" => {
14930 const extra = func.extraData(Function.Instruction.Select, data);
14931 try function_block.writeAbbrev(FunctionBlock.SelectFast{
14932 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14933 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14934 .cond = adapter.getOffsetValueIndex(extra.cond),
14935 .fast_math = FastMath.fast,
14936 });
14937 },
14938 .shufflevector => {
14939 const extra = func.extraData(Function.Instruction.ShuffleVector, data);
14940 try function_block.writeAbbrev(FunctionBlock.ShuffleVector{
14941 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14942 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14943 .mask = adapter.getOffsetValueIndex(extra.mask),
14944 });
14945 },
14946 .getelementptr,
14947 .@"getelementptr inbounds",
14948 => |kind| {
14949 var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, data);
14950 const indices = extra.trail.next(extra.data.indices_len, Value, &func);
14951 try function_block.writeAbbrevAdapted(
14952 FunctionBlock.GetElementPtr{
14953 .is_inbounds = kind == .@"getelementptr inbounds",
14954 .type_index = extra.data.type,
14955 .base = extra.data.base,
14956 .indices = indices,
14957 },
14958 adapter,
14959 );
14960 },
14961 .load => {
14962 const extra = func.extraData(Function.Instruction.Load, data);
14963 try function_block.writeAbbrev(FunctionBlock.Load{
14964 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14965 .ty = extra.type,
14966 .alignment = extra.info.alignment.toLlvm(),
14967 .is_volatile = extra.info.access_kind == .@"volatile",
14968 });
14969 },
14970 .@"load atomic" => {
14971 const extra = func.extraData(Function.Instruction.Load, data);
14972 try function_block.writeAbbrev(FunctionBlock.LoadAtomic{
14973 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14974 .ty = extra.type,
14975 .alignment = extra.info.alignment.toLlvm(),
14976 .is_volatile = extra.info.access_kind == .@"volatile",
14977 .success_ordering = extra.info.success_ordering,
14978 .sync_scope = extra.info.sync_scope,
14979 });
14980 },
14981 .store => {
14982 const extra = func.extraData(Function.Instruction.Store, data);
14983 try function_block.writeAbbrev(FunctionBlock.Store{
14984 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14985 .val = adapter.getOffsetValueIndex(extra.val),
14986 .alignment = extra.info.alignment.toLlvm(),
14987 .is_volatile = extra.info.access_kind == .@"volatile",
14988 });
14989 },
14990 .@"store atomic" => {
14991 const extra = func.extraData(Function.Instruction.Store, data);
14992 try function_block.writeAbbrev(FunctionBlock.StoreAtomic{
14993 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14994 .val = adapter.getOffsetValueIndex(extra.val),
14995 .alignment = extra.info.alignment.toLlvm(),
14996 .is_volatile = extra.info.access_kind == .@"volatile",
14997 .success_ordering = extra.info.success_ordering,
14998 .sync_scope = extra.info.sync_scope,
14999 });
15000 },
15001 .br => {
15002 try function_block.writeAbbrev(FunctionBlock.BrUnconditional{
15003 .block = data,
15004 });
15005 },
15006 .br_cond => {
15007 const extra = func.extraData(Function.Instruction.BrCond, data);
15008 try function_block.writeAbbrev(FunctionBlock.BrConditional{
15009 .then_block = @intFromEnum(extra.then),
15010 .else_block = @intFromEnum(extra.@"else"),
15011 .condition = adapter.getOffsetValueIndex(extra.cond),
15012 });
15013 },
15014 .@"switch" => {
15015 var extra = func.extraDataTrail(Function.Instruction.Switch, data);
15016
15017 try record.ensureUnusedCapacity(self.gpa, 3 + extra.data.cases_len * 2);
15018
15019 // Conditional type
15020 record.appendAssumeCapacity(@intFromEnum(extra.data.val.typeOf(@enumFromInt(func_index), self)));
15021
15022 // Conditional
15023 record.appendAssumeCapacity(adapter.getOffsetValueIndex(extra.data.val));
15024
15025 // Default block
15026 record.appendAssumeCapacity(@intFromEnum(extra.data.default));
15027
15028 const vals = extra.trail.next(extra.data.cases_len, Constant, &func);
15029 const blocks = extra.trail.next(extra.data.cases_len, Function.Block.Index, &func);
15030 for (vals, blocks) |val, block| {
15031 record.appendAssumeCapacity(adapter.constant_adapter.getConstantIndex(val));
15032 record.appendAssumeCapacity(@intFromEnum(block));
15033 }
15034
15035 try function_block.writeUnabbrev(12, record.items);
15036 },
15037 .va_arg => {
15038 const extra = func.extraData(Function.Instruction.VaArg, data);
15039 try function_block.writeAbbrev(FunctionBlock.VaArg{
15040 .list_type = extra.list.typeOf(@enumFromInt(func_index), self),
15041 .list = adapter.getOffsetValueIndex(extra.list),
15042 .type = extra.type,
15043 });
15044 },
15045 .phi,
15046 .@"phi fast",
15047 => |kind| {
15048 var extra = func.extraDataTrail(Function.Instruction.Phi, data);
15049 const vals = extra.trail.next(block_incoming_len, Value, &func);
15050 const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &func);
15051
15052 try record.ensureUnusedCapacity(
15053 self.gpa,
15054 1 + block_incoming_len * 2 + @intFromBool(kind == .@"phi fast"),
15055 );
15056
15057 record.appendAssumeCapacity(@intFromEnum(extra.data.type));
15058
15059 for (vals, blocks) |val, block| {
15060 const offset_value = adapter.getOffsetValueSignedIndex(val);
15061 const abs_value: u32 = @intCast(@abs(offset_value));
15062 const signed_vbr = if (offset_value > 0) abs_value << 1 else ((abs_value << 1) | 1);
15063 record.appendAssumeCapacity(signed_vbr);
15064 record.appendAssumeCapacity(@intFromEnum(block));
15065 }
15066
15067 if (kind == .@"phi fast") record.appendAssumeCapacity(@as(u8, @bitCast(FastMath{})));
15068
15069 try function_block.writeUnabbrev(16, record.items);
15070 },
15071 .ret => try function_block.writeAbbrev(FunctionBlock.Ret{
15072 .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
15073 }),
15074 .@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}),
15075 .atomicrmw => {
15076 const extra = func.extraData(Function.Instruction.AtomicRmw, data);
15077 try function_block.writeAbbrev(FunctionBlock.AtomicRmw{
15078 .ptr = adapter.getOffsetValueIndex(extra.ptr),
15079 .val = adapter.getOffsetValueIndex(extra.val),
15080 .operation = extra.info.atomic_rmw_operation,
15081 .is_volatile = extra.info.access_kind == .@"volatile",
15082 .success_ordering = extra.info.success_ordering,
15083 .sync_scope = extra.info.sync_scope,
15084 .alignment = extra.info.alignment.toLlvm(),
15085 });
15086 },
15087 .cmpxchg,
15088 .@"cmpxchg weak",
15089 => |kind| {
15090 const extra = func.extraData(Function.Instruction.CmpXchg, data);
15091
15092 try function_block.writeAbbrev(FunctionBlock.CmpXchg{
15093 .ptr = adapter.getOffsetValueIndex(extra.ptr),
15094 .cmp = adapter.getOffsetValueIndex(extra.cmp),
15095 .new = adapter.getOffsetValueIndex(extra.new),
15096 .is_volatile = extra.info.access_kind == .@"volatile",
15097 .success_ordering = extra.info.success_ordering,
15098 .sync_scope = extra.info.sync_scope,
15099 .failure_ordering = extra.info.failure_ordering,
15100 .is_weak = kind == .@"cmpxchg weak",
15101 .alignment = extra.info.alignment.toLlvm(),
15102 });
15103 },
15104 .fence => {
15105 const info: MemoryAccessInfo = @bitCast(data);
15106 try function_block.writeAbbrev(FunctionBlock.Fence{
15107 .ordering = info.success_ordering,
15108 .sync_scope = info.sync_scope,
15109 });
15110 },
15111 }
15112
15113 if (!func.strip) {
15114 if (func.debug_locations.get(adapter.instruction_index)) |debug_location| {
15115 switch (debug_location) {
15116 .no_location => has_location = false,
15117 .location => |location| {
15118 try function_block.writeAbbrev(FunctionBlock.DebugLoc{
15119 .line = location.line,
15120 .column = location.column,
15121 .scope = @enumFromInt(metadata_adapter.getMetadataIndex(location.scope)),
15122 .inlined_at = @enumFromInt(metadata_adapter.getMetadataIndex(location.inlined_at)),
15123 });
15124 has_location = true;
15125 },
15126 }
15127 } else if (has_location) {
15128 try function_block.writeAbbrev(FunctionBlock.DebugLocAgain{});
15129 }
15130 }
15131 }
15132
15133 // VALUE_SYMTAB
15134 if (!func.strip) {
15135 const ValueSymbolTable = ir.FunctionValueSymbolTable;
15136
15137 var value_symtab_block = try function_block.enterSubBlock(ValueSymbolTable, false);
15138
15139 for (func.blocks, 0..) |block, block_index| {
15140 const name = block.instruction.name(&func);
15141
15142 if (name == .none or name == .empty) continue;
15143
15144 try value_symtab_block.writeAbbrev(ValueSymbolTable.BlockEntry{
15145 .value_id = @intCast(block_index),
15146 .string = name.slice(self).?,
15147 });
15148 }
15149
15150 // TODO: Emit non block entries if the builder ever starts assigning names to non blocks
15151
15152 try value_symtab_block.end();
15153 }
15154
15155 // METADATA_ATTACHMENT_BLOCK
15156 {
15157 const MetadataAttachmentBlock = ir.MetadataAttachmentBlock;
15158 var metadata_attach_block = try function_block.enterSubBlock(MetadataAttachmentBlock, false);
15159
15160 dbg: {
15161 if (func.strip) break :dbg;
15162 const dbg = func.global.ptrConst(self).dbg;
15163 if (dbg == .none) break :dbg;
15164 try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentGlobalSingle{
15165 .kind = .dbg,
15166 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(dbg) - 1),
15167 });
15168 }
15169
15170 var instr_index: u32 = 0;
15171 for (func.instructions.items(.tag), func.instructions.items(.data)) |instr_tag, data| switch (instr_tag) {
15172 .arg, .block => {}, // not an actual instruction
15173 else => {
15174 instr_index += 1;
15175 },
15176 .br_cond, .@"switch" => {
15177 const weights = switch (instr_tag) {
15178 .br_cond => func.extraData(Function.Instruction.BrCond, data).weights,
15179 .@"switch" => func.extraData(Function.Instruction.Switch, data).weights,
15180 else => unreachable,
15181 };
15182 switch (weights) {
15183 .none => {},
15184 .unpredictable => try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentInstructionSingle{
15185 .inst = instr_index,
15186 .kind = .unpredictable,
15187 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(.empty_tuple) - 1),
15188 }),
15189 _ => try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentInstructionSingle{
15190 .inst = instr_index,
15191 .kind = .prof,
15192 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(@enumFromInt(@intFromEnum(weights))) - 1),
15193 }),
15194 }
15195 instr_index += 1;
15196 },
15197 };
15198
15199 try metadata_attach_block.end();
15200 }
15201
15202 try function_block.end();
15203 }
15204 }
15205
15206 try module_block.end();
15207 }
15208
15209 // STRTAB_BLOCK
15210 {
15211 const Strtab = ir.Strtab;
15212 var strtab_block = try bitcode.enterTopBlock(Strtab);
15213
15214 try strtab_block.writeAbbrev(Strtab.Blob{ .blob = self.strtab_string_bytes.items });
15215
15216 try strtab_block.end();
15217 }
15218
15219 return bitcode.toOwnedSlice();
15220}
15221
15222const Allocator = std.mem.Allocator;
15223const assert = std.debug.assert;
15224const bitcode_writer = @import("bitcode_writer.zig");
15225const Builder = @This();
15226const builtin = @import("builtin");
15227const DW = std.dwarf;
15228const ir = @import("ir.zig");
15229const log = std.log.scoped(.llvm);
15230const std = @import("../../std.zig");
lib/std/zig/llvm/bitcode_writer.zig created+433
......@@ -0,0 +1,433 @@
1const std = @import("../../std.zig");
2
3pub const AbbrevOp = union(enum) {
4 literal: u32, // 0
5 fixed: u16, // 1
6 fixed_runtime: type, // 1
7 vbr: u16, // 2
8 char6: void, // 4
9 blob: void, // 5
10 array_fixed: u16, // 3, 1
11 array_fixed_runtime: type, // 3, 1
12 array_vbr: u16, // 3, 2
13 array_char6: void, // 3, 4
14};
15
16pub const Error = error{OutOfMemory};
17
18pub fn BitcodeWriter(comptime types: []const type) type {
19 return struct {
20 const BcWriter = @This();
21
22 buffer: std.ArrayList(u32),
23 bit_buffer: u32 = 0,
24 bit_count: u5 = 0,
25
26 widths: [types.len]u16,
27
28 pub fn getTypeWidth(self: BcWriter, comptime Type: type) u16 {
29 return self.widths[comptime std.mem.indexOfScalar(type, types, Type).?];
30 }
31
32 pub fn init(allocator: std.mem.Allocator, widths: [types.len]u16) BcWriter {
33 return .{
34 .buffer = std.ArrayList(u32).init(allocator),
35 .widths = widths,
36 };
37 }
38
39 pub fn deinit(self: BcWriter) void {
40 self.buffer.deinit();
41 }
42
43 pub fn toOwnedSlice(self: *BcWriter) Error![]const u32 {
44 std.debug.assert(self.bit_count == 0);
45 return self.buffer.toOwnedSlice();
46 }
47
48 pub fn length(self: BcWriter) usize {
49 std.debug.assert(self.bit_count == 0);
50 return self.buffer.items.len;
51 }
52
53 pub fn writeBits(self: *BcWriter, value: anytype, bits: u16) Error!void {
54 if (bits == 0) return;
55
56 var in_buffer = bufValue(value, 32);
57 var in_bits = bits;
58
59 // Store input bits in buffer if they fit otherwise store as many as possible and flush
60 if (self.bit_count > 0) {
61 const bits_remaining = 31 - self.bit_count + 1;
62 const n: u5 = @intCast(@min(bits_remaining, in_bits));
63 const v = @as(u32, @truncate(in_buffer)) << self.bit_count;
64 self.bit_buffer |= v;
65 in_buffer >>= n;
66
67 self.bit_count +%= n;
68 in_bits -= n;
69
70 if (self.bit_count != 0) return;
71 try self.buffer.append(self.bit_buffer);
72 self.bit_buffer = 0;
73 }
74
75 // Write 32-bit chunks of input bits
76 while (in_bits >= 32) {
77 try self.buffer.append(@truncate(in_buffer));
78
79 in_buffer >>= 31;
80 in_buffer >>= 1;
81 in_bits -= 32;
82 }
83
84 // Store remaining input bits in buffer
85 if (in_bits > 0) {
86 self.bit_count = @intCast(in_bits);
87 self.bit_buffer = @truncate(in_buffer);
88 }
89 }
90
91 pub fn writeVBR(self: *BcWriter, value: anytype, comptime vbr_bits: usize) Error!void {
92 comptime {
93 std.debug.assert(vbr_bits > 1);
94 if (@bitSizeOf(@TypeOf(value)) > 64) @compileError("Unsupported VBR block type: " ++ @typeName(@TypeOf(value)));
95 }
96
97 var in_buffer = bufValue(value, vbr_bits);
98
99 const continue_bit = @as(@TypeOf(in_buffer), 1) << @intCast(vbr_bits - 1);
100 const mask = continue_bit - 1;
101
102 // If input is larger than one VBR block can store
103 // then store vbr_bits - 1 bits and a continue bit
104 while (in_buffer > mask) {
105 try self.writeBits(in_buffer & mask | continue_bit, vbr_bits);
106 in_buffer >>= @intCast(vbr_bits - 1);
107 }
108
109 // Store remaining bits
110 try self.writeBits(in_buffer, vbr_bits);
111 }
112
113 pub fn bitsVBR(_: *const BcWriter, value: anytype, comptime vbr_bits: usize) u16 {
114 comptime {
115 std.debug.assert(vbr_bits > 1);
116 if (@bitSizeOf(@TypeOf(value)) > 64) @compileError("Unsupported VBR block type: " ++ @typeName(@TypeOf(value)));
117 }
118
119 var bits: u16 = 0;
120
121 var in_buffer = bufValue(value, vbr_bits);
122
123 const continue_bit = @as(@TypeOf(in_buffer), 1) << @intCast(vbr_bits - 1);
124 const mask = continue_bit - 1;
125
126 // If input is larger than one VBR block can store
127 // then store vbr_bits - 1 bits and a continue bit
128 while (in_buffer > mask) {
129 bits += @intCast(vbr_bits);
130 in_buffer >>= @intCast(vbr_bits - 1);
131 }
132
133 // Store remaining bits
134 bits += @intCast(vbr_bits);
135 return bits;
136 }
137
138 pub fn write6BitChar(self: *BcWriter, c: u8) Error!void {
139 try self.writeBits(charTo6Bit(c), 6);
140 }
141
142 pub fn writeBlob(self: *BcWriter, blob: []const u8) Error!void {
143 const blob_word_size = std.mem.alignForward(usize, blob.len, 4);
144 try self.buffer.ensureUnusedCapacity(blob_word_size + 1);
145 self.alignTo32() catch unreachable;
146
147 const slice = self.buffer.addManyAsSliceAssumeCapacity(blob_word_size / 4);
148 const slice_bytes = std.mem.sliceAsBytes(slice);
149 @memcpy(slice_bytes[0..blob.len], blob);
150 @memset(slice_bytes[blob.len..], 0);
151 }
152
153 pub fn alignTo32(self: *BcWriter) Error!void {
154 if (self.bit_count == 0) return;
155
156 try self.buffer.append(self.bit_buffer);
157 self.bit_buffer = 0;
158 self.bit_count = 0;
159 }
160
161 pub fn enterTopBlock(self: *BcWriter, comptime SubBlock: type) Error!BlockWriter(SubBlock) {
162 return BlockWriter(SubBlock).init(self, 2, true);
163 }
164
165 fn BlockWriter(comptime Block: type) type {
166 return struct {
167 const Self = @This();
168
169 // The minimum abbrev id length based on the number of abbrevs present in the block
170 pub const abbrev_len = std.math.log2_int_ceil(
171 u6,
172 4 + (if (@hasDecl(Block, "abbrevs")) Block.abbrevs.len else 0),
173 );
174
175 start: usize,
176 bitcode: *BcWriter,
177
178 pub fn init(bitcode: *BcWriter, comptime parent_abbrev_len: u6, comptime define_abbrevs: bool) Error!Self {
179 try bitcode.writeBits(1, parent_abbrev_len);
180 try bitcode.writeVBR(Block.id, 8);
181 try bitcode.writeVBR(abbrev_len, 4);
182 try bitcode.alignTo32();
183
184 // We store the index of the block size and store a dummy value as the number of words in the block
185 const start = bitcode.length();
186 try bitcode.writeBits(0, 32);
187
188 var self = Self{
189 .start = start,
190 .bitcode = bitcode,
191 };
192
193 // Predefine all block abbrevs
194 if (define_abbrevs) {
195 inline for (Block.abbrevs) |Abbrev| {
196 try self.defineAbbrev(&Abbrev.ops);
197 }
198 }
199
200 return self;
201 }
202
203 pub fn enterSubBlock(self: Self, comptime SubBlock: type, comptime define_abbrevs: bool) Error!BlockWriter(SubBlock) {
204 return BlockWriter(SubBlock).init(self.bitcode, abbrev_len, define_abbrevs);
205 }
206
207 pub fn end(self: *Self) Error!void {
208 try self.bitcode.writeBits(0, abbrev_len);
209 try self.bitcode.alignTo32();
210
211 // Set the number of words in the block at the start of the block
212 self.bitcode.buffer.items[self.start] = @truncate(self.bitcode.length() - self.start - 1);
213 }
214
215 pub fn writeUnabbrev(self: *Self, code: u32, values: []const u64) Error!void {
216 try self.bitcode.writeBits(3, abbrev_len);
217 try self.bitcode.writeVBR(code, 6);
218 try self.bitcode.writeVBR(values.len, 6);
219 for (values) |val| {
220 try self.bitcode.writeVBR(val, 6);
221 }
222 }
223
224 pub fn writeAbbrev(self: *Self, params: anytype) Error!void {
225 return self.writeAbbrevAdapted(params, struct {
226 pub fn get(_: @This(), param: anytype, comptime _: []const u8) @TypeOf(param) {
227 return param;
228 }
229 }{});
230 }
231
232 pub fn abbrevId(comptime Abbrev: type) u32 {
233 inline for (Block.abbrevs, 0..) |abbrev, i| {
234 if (Abbrev == abbrev) return i + 4;
235 }
236
237 @compileError("Unknown abbrev: " ++ @typeName(Abbrev));
238 }
239
240 pub fn writeAbbrevAdapted(
241 self: *Self,
242 params: anytype,
243 adapter: anytype,
244 ) Error!void {
245 const Abbrev = @TypeOf(params);
246
247 try self.bitcode.writeBits(comptime abbrevId(Abbrev), abbrev_len);
248
249 const fields = std.meta.fields(Abbrev);
250
251 // This abbreviation might only contain literals
252 if (fields.len == 0) return;
253
254 comptime var field_index: usize = 0;
255 inline for (Abbrev.ops) |ty| {
256 const field_name = fields[field_index].name;
257 const param = @field(params, field_name);
258
259 switch (ty) {
260 .literal => continue,
261 .fixed => |len| try self.bitcode.writeBits(adapter.get(param, field_name), len),
262 .fixed_runtime => |width_ty| try self.bitcode.writeBits(
263 adapter.get(param, field_name),
264 self.bitcode.getTypeWidth(width_ty),
265 ),
266 .vbr => |len| try self.bitcode.writeVBR(adapter.get(param, field_name), len),
267 .char6 => try self.bitcode.write6BitChar(adapter.get(param, field_name)),
268 .blob => {
269 try self.bitcode.writeVBR(param.len, 6);
270 try self.bitcode.writeBlob(param);
271 },
272 .array_fixed => |len| {
273 try self.bitcode.writeVBR(param.len, 6);
274 for (param) |x| {
275 try self.bitcode.writeBits(adapter.get(x, field_name), len);
276 }
277 },
278 .array_fixed_runtime => |width_ty| {
279 try self.bitcode.writeVBR(param.len, 6);
280 for (param) |x| {
281 try self.bitcode.writeBits(
282 adapter.get(x, field_name),
283 self.bitcode.getTypeWidth(width_ty),
284 );
285 }
286 },
287 .array_vbr => |len| {
288 try self.bitcode.writeVBR(param.len, 6);
289 for (param) |x| {
290 try self.bitcode.writeVBR(adapter.get(x, field_name), len);
291 }
292 },
293 .array_char6 => {
294 try self.bitcode.writeVBR(param.len, 6);
295 for (param) |x| {
296 try self.bitcode.write6BitChar(adapter.get(x, field_name));
297 }
298 },
299 }
300 field_index += 1;
301 if (field_index == fields.len) break;
302 }
303 }
304
305 pub fn defineAbbrev(self: *Self, comptime ops: []const AbbrevOp) Error!void {
306 const bitcode = self.bitcode;
307 try bitcode.writeBits(2, abbrev_len);
308
309 // ops.len is not accurate because arrays are actually two ops
310 try bitcode.writeVBR(blk: {
311 var count: usize = 0;
312 inline for (ops) |op| {
313 count += switch (op) {
314 .literal, .fixed, .fixed_runtime, .vbr, .char6, .blob => 1,
315 .array_fixed, .array_fixed_runtime, .array_vbr, .array_char6 => 2,
316 };
317 }
318 break :blk count;
319 }, 5);
320
321 inline for (ops) |op| {
322 switch (op) {
323 .literal => |value| {
324 try bitcode.writeBits(1, 1);
325 try bitcode.writeVBR(value, 8);
326 },
327 .fixed => |width| {
328 try bitcode.writeBits(0, 1);
329 try bitcode.writeBits(1, 3);
330 try bitcode.writeVBR(width, 5);
331 },
332 .fixed_runtime => |width_ty| {
333 try bitcode.writeBits(0, 1);
334 try bitcode.writeBits(1, 3);
335 try bitcode.writeVBR(bitcode.getTypeWidth(width_ty), 5);
336 },
337 .vbr => |width| {
338 try bitcode.writeBits(0, 1);
339 try bitcode.writeBits(2, 3);
340 try bitcode.writeVBR(width, 5);
341 },
342 .char6 => {
343 try bitcode.writeBits(0, 1);
344 try bitcode.writeBits(4, 3);
345 },
346 .blob => {
347 try bitcode.writeBits(0, 1);
348 try bitcode.writeBits(5, 3);
349 },
350 .array_fixed => |width| {
351 // Array op
352 try bitcode.writeBits(0, 1);
353 try bitcode.writeBits(3, 3);
354
355 // Fixed or VBR op
356 try bitcode.writeBits(0, 1);
357 try bitcode.writeBits(1, 3);
358 try bitcode.writeVBR(width, 5);
359 },
360 .array_fixed_runtime => |width_ty| {
361 // Array op
362 try bitcode.writeBits(0, 1);
363 try bitcode.writeBits(3, 3);
364
365 // Fixed or VBR op
366 try bitcode.writeBits(0, 1);
367 try bitcode.writeBits(1, 3);
368 try bitcode.writeVBR(bitcode.getTypeWidth(width_ty), 5);
369 },
370 .array_vbr => |width| {
371 // Array op
372 try bitcode.writeBits(0, 1);
373 try bitcode.writeBits(3, 3);
374
375 // Fixed or VBR op
376 try bitcode.writeBits(0, 1);
377 try bitcode.writeBits(2, 3);
378 try bitcode.writeVBR(width, 5);
379 },
380 .array_char6 => {
381 // Array op
382 try bitcode.writeBits(0, 1);
383 try bitcode.writeBits(3, 3);
384
385 // Char6 op
386 try bitcode.writeBits(0, 1);
387 try bitcode.writeBits(4, 3);
388 },
389 }
390 }
391 }
392 };
393 }
394 };
395}
396
397fn charTo6Bit(c: u8) u8 {
398 return switch (c) {
399 'a'...'z' => c - 'a',
400 'A'...'Z' => c - 'A' + 26,
401 '0'...'9' => c - '0' + 52,
402 '.' => 62,
403 '_' => 63,
404 else => @panic("Failed to encode byte as 6-bit char"),
405 };
406}
407
408fn BufType(comptime T: type, comptime min_len: usize) type {
409 return std.meta.Int(.unsigned, @max(min_len, @bitSizeOf(switch (@typeInfo(T)) {
410 .comptime_int => u32,
411 .int => |info| if (info.signedness == .unsigned)
412 T
413 else
414 @compileError("Unsupported type: " ++ @typeName(T)),
415 .@"enum" => |info| info.tag_type,
416 .bool => u1,
417 .@"struct" => |info| switch (info.layout) {
418 .auto, .@"extern" => @compileError("Unsupported type: " ++ @typeName(T)),
419 .@"packed" => std.meta.Int(.unsigned, @bitSizeOf(T)),
420 },
421 else => @compileError("Unsupported type: " ++ @typeName(T)),
422 })));
423}
424
425fn bufValue(value: anytype, comptime min_len: usize) BufType(@TypeOf(value), min_len) {
426 return switch (@typeInfo(@TypeOf(value))) {
427 .comptime_int, .int => @intCast(value),
428 .@"enum" => @intFromEnum(value),
429 .bool => @intFromBool(value),
430 .@"struct" => @intCast(@as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(value))), @bitCast(value))),
431 else => unreachable,
432 };
433}
lib/std/zig/llvm/ir.zig created+1862
......@@ -0,0 +1,1862 @@
1const std = @import("../../std.zig");
2const Builder = @import("Builder.zig");
3const bitcode_writer = @import("bitcode_writer.zig");
4
5const AbbrevOp = bitcode_writer.AbbrevOp;
6
7pub const MAGIC: u32 = 0xdec04342;
8
9const ValueAbbrev = AbbrevOp{ .vbr = 6 };
10const ValueArrayAbbrev = AbbrevOp{ .array_vbr = 6 };
11
12const ConstantAbbrev = AbbrevOp{ .vbr = 6 };
13const ConstantArrayAbbrev = AbbrevOp{ .array_vbr = 6 };
14
15const MetadataAbbrev = AbbrevOp{ .vbr = 16 };
16const MetadataArrayAbbrev = AbbrevOp{ .array_vbr = 16 };
17
18const LineAbbrev = AbbrevOp{ .vbr = 8 };
19const ColumnAbbrev = AbbrevOp{ .vbr = 8 };
20
21const BlockAbbrev = AbbrevOp{ .vbr = 6 };
22const BlockArrayAbbrev = AbbrevOp{ .array_vbr = 6 };
23
24/// Unused tags are commented out so that they are omitted in the generated
25/// bitcode, which scans over this enum using reflection.
26pub const FixedMetadataKind = enum(u8) {
27 dbg = 0,
28 //tbaa = 1,
29 prof = 2,
30 //fpmath = 3,
31 //range = 4,
32 //@"tbaa.struct" = 5,
33 //@"invariant.load" = 6,
34 //@"alias.scope" = 7,
35 //@"noalias" = 8,
36 //nontemporal = 9,
37 //@"llvm.mem.parallel_loop_access" = 10,
38 //nonnull = 11,
39 //dereferenceable = 12,
40 //dereferenceable_or_null = 13,
41 //@"make.implicit" = 14,
42 unpredictable = 15,
43 //@"invariant.group" = 16,
44 //@"align" = 17,
45 //@"llvm.loop" = 18,
46 //type = 19,
47 //section_prefix = 20,
48 //absolute_symbol = 21,
49 //associated = 22,
50 //callees = 23,
51 //irr_loop = 24,
52 //@"llvm.access.group" = 25,
53 //callback = 26,
54 //@"llvm.preserve.access.index" = 27,
55 //vcall_visibility = 28,
56 //noundef = 29,
57 //annotation = 30,
58 //nosanitize = 31,
59 //func_sanitize = 32,
60 //exclude = 33,
61 //memprof = 34,
62 //callsite = 35,
63 //kcfi_type = 36,
64 //pcsections = 37,
65 //DIAssignID = 38,
66 //@"coro.outside.frame" = 39,
67};
68
69pub const MetadataCode = enum(u8) {
70 /// MDSTRING: [values]
71 STRING_OLD = 1,
72 /// VALUE: [type num, value num]
73 VALUE = 2,
74 /// NODE: [n x md num]
75 NODE = 3,
76 /// STRING: [values]
77 NAME = 4,
78 /// DISTINCT_NODE: [n x md num]
79 DISTINCT_NODE = 5,
80 /// [n x [id, name]]
81 KIND = 6,
82 /// [distinct, line, col, scope, inlined-at?]
83 LOCATION = 7,
84 /// OLD_NODE: [n x (type num, value num)]
85 OLD_NODE = 8,
86 /// OLD_FN_NODE: [n x (type num, value num)]
87 OLD_FN_NODE = 9,
88 /// NAMED_NODE: [n x mdnodes]
89 NAMED_NODE = 10,
90 /// [m x [value, [n x [id, mdnode]]]
91 ATTACHMENT = 11,
92 /// [distinct, tag, vers, header, n x md num]
93 GENERIC_DEBUG = 12,
94 /// [distinct, count, lo]
95 SUBRANGE = 13,
96 /// [isUnsigned|distinct, value, name]
97 ENUMERATOR = 14,
98 /// [distinct, tag, name, size, align, enc]
99 BASIC_TYPE = 15,
100 /// [distinct, filename, directory, checksumkind, checksum]
101 FILE = 16,
102 /// [distinct, ...]
103 DERIVED_TYPE = 17,
104 /// [distinct, ...]
105 COMPOSITE_TYPE = 18,
106 /// [distinct, flags, types, cc]
107 SUBROUTINE_TYPE = 19,
108 /// [distinct, ...]
109 COMPILE_UNIT = 20,
110 /// [distinct, ...]
111 SUBPROGRAM = 21,
112 /// [distinct, scope, file, line, column]
113 LEXICAL_BLOCK = 22,
114 ///[distinct, scope, file, discriminator]
115 LEXICAL_BLOCK_FILE = 23,
116 /// [distinct, scope, file, name, line, exportSymbols]
117 NAMESPACE = 24,
118 /// [distinct, scope, name, type, ...]
119 TEMPLATE_TYPE = 25,
120 /// [distinct, scope, name, type, value, ...]
121 TEMPLATE_VALUE = 26,
122 /// [distinct, ...]
123 GLOBAL_VAR = 27,
124 /// [distinct, ...]
125 LOCAL_VAR = 28,
126 /// [distinct, n x element]
127 EXPRESSION = 29,
128 /// [distinct, name, file, line, ...]
129 OBJC_PROPERTY = 30,
130 /// [distinct, tag, scope, entity, line, name]
131 IMPORTED_ENTITY = 31,
132 /// [distinct, scope, name, ...]
133 MODULE = 32,
134 /// [distinct, macinfo, line, name, value]
135 MACRO = 33,
136 /// [distinct, macinfo, line, file, ...]
137 MACRO_FILE = 34,
138 /// [count, offset] blob([lengths][chars])
139 STRINGS = 35,
140 /// [valueid, n x [id, mdnode]]
141 GLOBAL_DECL_ATTACHMENT = 36,
142 /// [distinct, var, expr]
143 GLOBAL_VAR_EXPR = 37,
144 /// [offset]
145 INDEX_OFFSET = 38,
146 /// [bitpos]
147 INDEX = 39,
148 /// [distinct, scope, name, file, line]
149 LABEL = 40,
150 /// [distinct, name, size, align,...]
151 STRING_TYPE = 41,
152 /// [distinct, scope, name, variable,...]
153 COMMON_BLOCK = 44,
154 /// [distinct, count, lo, up, stride]
155 GENERIC_SUBRANGE = 45,
156 /// [n x [type num, value num]]
157 ARG_LIST = 46,
158 /// [distinct, ...]
159 ASSIGN_ID = 47,
160};
161
162pub const Identification = struct {
163 pub const id = 13;
164
165 pub const abbrevs = [_]type{
166 Version,
167 Epoch,
168 };
169
170 pub const Version = struct {
171 pub const ops = [_]AbbrevOp{
172 .{ .literal = 1 },
173 .{ .array_fixed = 8 },
174 };
175 string: []const u8,
176 };
177
178 pub const Epoch = struct {
179 pub const ops = [_]AbbrevOp{
180 .{ .literal = 2 },
181 .{ .vbr = 6 },
182 };
183 epoch: u32,
184 };
185};
186
187pub const Module = struct {
188 pub const id = 8;
189
190 pub const abbrevs = [_]type{
191 Version,
192 String,
193 Variable,
194 Function,
195 Alias,
196 };
197
198 pub const Version = struct {
199 pub const ops = [_]AbbrevOp{
200 .{ .literal = 1 },
201 .{ .literal = 2 },
202 };
203 };
204
205 pub const String = struct {
206 pub const ops = [_]AbbrevOp{
207 .{ .vbr = 4 },
208 .{ .array_fixed = 8 },
209 };
210 code: u16,
211 string: []const u8,
212 };
213
214 pub const Variable = struct {
215 const AddrSpaceAndIsConst = packed struct {
216 is_const: bool,
217 one: u1 = 1,
218 addr_space: Builder.AddrSpace,
219 };
220
221 pub const ops = [_]AbbrevOp{
222 .{ .literal = 7 }, // Code
223 .{ .vbr = 16 }, // strtab_offset
224 .{ .vbr = 16 }, // strtab_size
225 .{ .fixed_runtime = Builder.Type },
226 .{ .fixed = @bitSizeOf(AddrSpaceAndIsConst) }, // isconst
227 ConstantAbbrev, // initid
228 .{ .fixed = @bitSizeOf(Builder.Linkage) },
229 .{ .fixed = @bitSizeOf(Builder.Alignment) },
230 .{ .vbr = 16 }, // section
231 .{ .fixed = @bitSizeOf(Builder.Visibility) },
232 .{ .fixed = @bitSizeOf(Builder.ThreadLocal) }, // threadlocal
233 .{ .fixed = @bitSizeOf(Builder.UnnamedAddr) },
234 .{ .fixed = @bitSizeOf(Builder.ExternallyInitialized) },
235 .{ .fixed = @bitSizeOf(Builder.DllStorageClass) },
236 .{ .literal = 0 }, // comdat
237 .{ .literal = 0 }, // attributes
238 .{ .fixed = @bitSizeOf(Builder.Preemption) },
239 };
240 strtab_offset: usize,
241 strtab_size: usize,
242 type_index: Builder.Type,
243 is_const: AddrSpaceAndIsConst,
244 initid: u32,
245 linkage: Builder.Linkage,
246 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
247 section: usize,
248 visibility: Builder.Visibility,
249 thread_local: Builder.ThreadLocal,
250 unnamed_addr: Builder.UnnamedAddr,
251 externally_initialized: Builder.ExternallyInitialized,
252 dllstorageclass: Builder.DllStorageClass,
253 preemption: Builder.Preemption,
254 };
255
256 pub const Function = struct {
257 pub const ops = [_]AbbrevOp{
258 .{ .literal = 8 }, // Code
259 .{ .vbr = 16 }, // strtab_offset
260 .{ .vbr = 16 }, // strtab_size
261 .{ .fixed_runtime = Builder.Type },
262 .{ .fixed = @bitSizeOf(Builder.CallConv) },
263 .{ .fixed = 1 }, // isproto
264 .{ .fixed = @bitSizeOf(Builder.Linkage) },
265 .{ .vbr = 16 }, // paramattr
266 .{ .fixed = @bitSizeOf(Builder.Alignment) },
267 .{ .vbr = 16 }, // section
268 .{ .fixed = @bitSizeOf(Builder.Visibility) },
269 .{ .literal = 0 }, // gc
270 .{ .fixed = @bitSizeOf(Builder.UnnamedAddr) },
271 .{ .literal = 0 }, // prologuedata
272 .{ .fixed = @bitSizeOf(Builder.DllStorageClass) },
273 .{ .literal = 0 }, // comdat
274 .{ .literal = 0 }, // prefixdata
275 .{ .literal = 0 }, // personalityfn
276 .{ .fixed = @bitSizeOf(Builder.Preemption) },
277 .{ .fixed = @bitSizeOf(Builder.AddrSpace) },
278 };
279 strtab_offset: usize,
280 strtab_size: usize,
281 type_index: Builder.Type,
282 call_conv: Builder.CallConv,
283 is_proto: bool,
284 linkage: Builder.Linkage,
285 paramattr: usize,
286 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
287 section: usize,
288 visibility: Builder.Visibility,
289 unnamed_addr: Builder.UnnamedAddr,
290 dllstorageclass: Builder.DllStorageClass,
291 preemption: Builder.Preemption,
292 addr_space: Builder.AddrSpace,
293 };
294
295 pub const Alias = struct {
296 pub const ops = [_]AbbrevOp{
297 .{ .literal = 14 }, // Code
298 .{ .vbr = 16 }, // strtab_offset
299 .{ .vbr = 16 }, // strtab_size
300 .{ .fixed_runtime = Builder.Type },
301 .{ .fixed = @bitSizeOf(Builder.AddrSpace) },
302 ConstantAbbrev, // aliasee val
303 .{ .fixed = @bitSizeOf(Builder.Linkage) },
304 .{ .fixed = @bitSizeOf(Builder.Visibility) },
305 .{ .fixed = @bitSizeOf(Builder.DllStorageClass) },
306 .{ .fixed = @bitSizeOf(Builder.ThreadLocal) },
307 .{ .fixed = @bitSizeOf(Builder.UnnamedAddr) },
308 .{ .fixed = @bitSizeOf(Builder.Preemption) },
309 };
310 strtab_offset: usize,
311 strtab_size: usize,
312 type_index: Builder.Type,
313 addr_space: Builder.AddrSpace,
314 aliasee: u32,
315 linkage: Builder.Linkage,
316 visibility: Builder.Visibility,
317 dllstorageclass: Builder.DllStorageClass,
318 thread_local: Builder.ThreadLocal,
319 unnamed_addr: Builder.UnnamedAddr,
320 preemption: Builder.Preemption,
321 };
322};
323
324pub const BlockInfo = struct {
325 pub const id = 0;
326
327 pub const set_block_id = 1;
328
329 pub const abbrevs = [_]type{};
330};
331
332pub const Type = struct {
333 pub const id = 17;
334
335 pub const abbrevs = [_]type{
336 NumEntry,
337 Simple,
338 Opaque,
339 Integer,
340 StructAnon,
341 StructNamed,
342 StructName,
343 Array,
344 Vector,
345 Pointer,
346 Target,
347 Function,
348 };
349
350 pub const NumEntry = struct {
351 pub const ops = [_]AbbrevOp{
352 .{ .literal = 1 },
353 .{ .fixed = 32 },
354 };
355 num: u32,
356 };
357
358 pub const Simple = struct {
359 pub const ops = [_]AbbrevOp{
360 .{ .vbr = 4 },
361 };
362 code: u5,
363 };
364
365 pub const Opaque = struct {
366 pub const ops = [_]AbbrevOp{
367 .{ .literal = 6 },
368 .{ .literal = 0 },
369 };
370 };
371
372 pub const Integer = struct {
373 pub const ops = [_]AbbrevOp{
374 .{ .literal = 7 },
375 .{ .fixed = 28 },
376 };
377 width: u28,
378 };
379
380 pub const StructAnon = struct {
381 pub const ops = [_]AbbrevOp{
382 .{ .literal = 18 },
383 .{ .fixed = 1 },
384 .{ .array_fixed_runtime = Builder.Type },
385 };
386 is_packed: bool,
387 types: []const Builder.Type,
388 };
389
390 pub const StructNamed = struct {
391 pub const ops = [_]AbbrevOp{
392 .{ .literal = 20 },
393 .{ .fixed = 1 },
394 .{ .array_fixed_runtime = Builder.Type },
395 };
396 is_packed: bool,
397 types: []const Builder.Type,
398 };
399
400 pub const StructName = struct {
401 pub const ops = [_]AbbrevOp{
402 .{ .literal = 19 },
403 .{ .array_fixed = 8 },
404 };
405 string: []const u8,
406 };
407
408 pub const Array = struct {
409 pub const ops = [_]AbbrevOp{
410 .{ .literal = 11 },
411 .{ .vbr = 16 },
412 .{ .fixed_runtime = Builder.Type },
413 };
414 len: u64,
415 child: Builder.Type,
416 };
417
418 pub const Vector = struct {
419 pub const ops = [_]AbbrevOp{
420 .{ .literal = 12 },
421 .{ .vbr = 16 },
422 .{ .fixed_runtime = Builder.Type },
423 };
424 len: u64,
425 child: Builder.Type,
426 };
427
428 pub const Pointer = struct {
429 pub const ops = [_]AbbrevOp{
430 .{ .literal = 25 },
431 .{ .vbr = 4 },
432 };
433 addr_space: Builder.AddrSpace,
434 };
435
436 pub const Target = struct {
437 pub const ops = [_]AbbrevOp{
438 .{ .literal = 26 },
439 .{ .vbr = 4 },
440 .{ .array_fixed_runtime = Builder.Type },
441 .{ .array_fixed = 32 },
442 };
443 num_types: u32,
444 types: []const Builder.Type,
445 ints: []const u32,
446 };
447
448 pub const Function = struct {
449 pub const ops = [_]AbbrevOp{
450 .{ .literal = 21 },
451 .{ .fixed = 1 },
452 .{ .fixed_runtime = Builder.Type },
453 .{ .array_fixed_runtime = Builder.Type },
454 };
455 is_vararg: bool,
456 return_type: Builder.Type,
457 param_types: []const Builder.Type,
458 };
459};
460
461pub const Paramattr = struct {
462 pub const id = 9;
463
464 pub const abbrevs = [_]type{
465 Entry,
466 };
467
468 pub const Entry = struct {
469 pub const ops = [_]AbbrevOp{
470 .{ .literal = 2 },
471 .{ .array_vbr = 8 },
472 };
473 group_indices: []const u64,
474 };
475};
476
477pub const ParamattrGroup = struct {
478 pub const id = 10;
479
480 pub const abbrevs = [_]type{};
481};
482
483pub const Constants = struct {
484 pub const id = 11;
485
486 pub const abbrevs = [_]type{
487 SetType,
488 Null,
489 Undef,
490 Poison,
491 Integer,
492 Half,
493 Float,
494 Double,
495 Fp80,
496 Fp128,
497 Aggregate,
498 String,
499 CString,
500 Cast,
501 Binary,
502 Cmp,
503 ExtractElement,
504 InsertElement,
505 ShuffleVector,
506 ShuffleVectorEx,
507 BlockAddress,
508 DsoLocalEquivalentOrNoCfi,
509 };
510
511 pub const SetType = struct {
512 pub const ops = [_]AbbrevOp{
513 .{ .literal = 1 },
514 .{ .fixed_runtime = Builder.Type },
515 };
516 type_id: Builder.Type,
517 };
518
519 pub const Null = struct {
520 pub const ops = [_]AbbrevOp{
521 .{ .literal = 2 },
522 };
523 };
524
525 pub const Undef = struct {
526 pub const ops = [_]AbbrevOp{
527 .{ .literal = 3 },
528 };
529 };
530
531 pub const Poison = struct {
532 pub const ops = [_]AbbrevOp{
533 .{ .literal = 26 },
534 };
535 };
536
537 pub const Integer = struct {
538 pub const ops = [_]AbbrevOp{
539 .{ .literal = 4 },
540 .{ .vbr = 16 },
541 };
542 value: u64,
543 };
544
545 pub const Half = struct {
546 pub const ops = [_]AbbrevOp{
547 .{ .literal = 6 },
548 .{ .fixed = 16 },
549 };
550 value: u16,
551 };
552
553 pub const Float = struct {
554 pub const ops = [_]AbbrevOp{
555 .{ .literal = 6 },
556 .{ .fixed = 32 },
557 };
558 value: u32,
559 };
560
561 pub const Double = struct {
562 pub const ops = [_]AbbrevOp{
563 .{ .literal = 6 },
564 .{ .vbr = 6 },
565 };
566 value: u64,
567 };
568
569 pub const Fp80 = struct {
570 pub const ops = [_]AbbrevOp{
571 .{ .literal = 6 },
572 .{ .vbr = 6 },
573 .{ .vbr = 6 },
574 };
575 hi: u64,
576 lo: u16,
577 };
578
579 pub const Fp128 = struct {
580 pub const ops = [_]AbbrevOp{
581 .{ .literal = 6 },
582 .{ .vbr = 6 },
583 .{ .vbr = 6 },
584 };
585 lo: u64,
586 hi: u64,
587 };
588
589 pub const Aggregate = struct {
590 pub const ops = [_]AbbrevOp{
591 .{ .literal = 7 },
592 .{ .array_fixed = 32 },
593 };
594 values: []const Builder.Constant,
595 };
596
597 pub const String = struct {
598 pub const ops = [_]AbbrevOp{
599 .{ .literal = 8 },
600 .{ .array_fixed = 8 },
601 };
602 string: []const u8,
603 };
604
605 pub const CString = struct {
606 pub const ops = [_]AbbrevOp{
607 .{ .literal = 9 },
608 .{ .array_fixed = 8 },
609 };
610 string: []const u8,
611 };
612
613 pub const Cast = struct {
614 const CastOpcode = Builder.CastOpcode;
615 pub const ops = [_]AbbrevOp{
616 .{ .literal = 11 },
617 .{ .fixed = @bitSizeOf(CastOpcode) },
618 .{ .fixed_runtime = Builder.Type },
619 ConstantAbbrev,
620 };
621
622 opcode: CastOpcode,
623 type_index: Builder.Type,
624 val: Builder.Constant,
625 };
626
627 pub const Binary = struct {
628 const BinaryOpcode = Builder.BinaryOpcode;
629 pub const ops = [_]AbbrevOp{
630 .{ .literal = 10 },
631 .{ .fixed = @bitSizeOf(BinaryOpcode) },
632 ConstantAbbrev,
633 ConstantAbbrev,
634 };
635
636 opcode: BinaryOpcode,
637 lhs: Builder.Constant,
638 rhs: Builder.Constant,
639 };
640
641 pub const Cmp = struct {
642 pub const ops = [_]AbbrevOp{
643 .{ .literal = 17 },
644 .{ .fixed_runtime = Builder.Type },
645 ConstantAbbrev,
646 ConstantAbbrev,
647 .{ .vbr = 6 },
648 };
649
650 ty: Builder.Type,
651 lhs: Builder.Constant,
652 rhs: Builder.Constant,
653 pred: u32,
654 };
655
656 pub const ExtractElement = struct {
657 pub const ops = [_]AbbrevOp{
658 .{ .literal = 14 },
659 .{ .fixed_runtime = Builder.Type },
660 ConstantAbbrev,
661 .{ .fixed_runtime = Builder.Type },
662 ConstantAbbrev,
663 };
664
665 val_type: Builder.Type,
666 val: Builder.Constant,
667 index_type: Builder.Type,
668 index: Builder.Constant,
669 };
670
671 pub const InsertElement = struct {
672 pub const ops = [_]AbbrevOp{
673 .{ .literal = 15 },
674 ConstantAbbrev,
675 ConstantAbbrev,
676 .{ .fixed_runtime = Builder.Type },
677 ConstantAbbrev,
678 };
679
680 val: Builder.Constant,
681 elem: Builder.Constant,
682 index_type: Builder.Type,
683 index: Builder.Constant,
684 };
685
686 pub const ShuffleVector = struct {
687 pub const ops = [_]AbbrevOp{
688 .{ .literal = 16 },
689 ValueAbbrev,
690 ValueAbbrev,
691 ValueAbbrev,
692 };
693
694 lhs: Builder.Constant,
695 rhs: Builder.Constant,
696 mask: Builder.Constant,
697 };
698
699 pub const ShuffleVectorEx = struct {
700 pub const ops = [_]AbbrevOp{
701 .{ .literal = 19 },
702 .{ .fixed_runtime = Builder.Type },
703 ValueAbbrev,
704 ValueAbbrev,
705 ValueAbbrev,
706 };
707
708 ty: Builder.Type,
709 lhs: Builder.Constant,
710 rhs: Builder.Constant,
711 mask: Builder.Constant,
712 };
713
714 pub const BlockAddress = struct {
715 pub const ops = [_]AbbrevOp{
716 .{ .literal = 21 },
717 .{ .fixed_runtime = Builder.Type },
718 ConstantAbbrev,
719 BlockAbbrev,
720 };
721 type_id: Builder.Type,
722 function: u32,
723 block: u32,
724 };
725
726 pub const DsoLocalEquivalentOrNoCfi = struct {
727 pub const ops = [_]AbbrevOp{
728 .{ .fixed = 5 },
729 .{ .fixed_runtime = Builder.Type },
730 ConstantAbbrev,
731 };
732 code: u5,
733 type_id: Builder.Type,
734 function: u32,
735 };
736};
737
738pub const MetadataKindBlock = struct {
739 pub const id = 22;
740
741 pub const abbrevs = [_]type{
742 Kind,
743 };
744
745 pub const Kind = struct {
746 pub const ops = [_]AbbrevOp{
747 .{ .literal = 6 },
748 .{ .vbr = 4 },
749 .{ .array_fixed = 8 },
750 };
751 id: u32,
752 name: []const u8,
753 };
754};
755
756pub const MetadataAttachmentBlock = struct {
757 pub const id = 16;
758
759 pub const abbrevs = [_]type{
760 AttachmentGlobalSingle,
761 AttachmentInstructionSingle,
762 };
763
764 pub const AttachmentGlobalSingle = struct {
765 pub const ops = [_]AbbrevOp{
766 .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
767 .{ .fixed = 1 },
768 MetadataAbbrev,
769 };
770 kind: FixedMetadataKind,
771 metadata: Builder.Metadata,
772 };
773
774 pub const AttachmentInstructionSingle = struct {
775 pub const ops = [_]AbbrevOp{
776 .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
777 ValueAbbrev,
778 .{ .fixed = 5 },
779 MetadataAbbrev,
780 };
781 inst: u32,
782 kind: FixedMetadataKind,
783 metadata: Builder.Metadata,
784 };
785};
786
787pub const MetadataBlock = struct {
788 pub const id = 15;
789
790 pub const abbrevs = [_]type{
791 Strings,
792 File,
793 CompileUnit,
794 Subprogram,
795 LexicalBlock,
796 Location,
797 BasicType,
798 CompositeType,
799 DerivedType,
800 SubroutineType,
801 Enumerator,
802 Subrange,
803 Expression,
804 Node,
805 LocalVar,
806 Parameter,
807 GlobalVar,
808 GlobalVarExpression,
809 Constant,
810 Name,
811 NamedNode,
812 GlobalDeclAttachment,
813 };
814
815 pub const Strings = struct {
816 pub const ops = [_]AbbrevOp{
817 .{ .literal = @intFromEnum(MetadataCode.STRINGS) },
818 .{ .vbr = 6 },
819 .{ .vbr = 6 },
820 .blob,
821 };
822 num_strings: u32,
823 strings_offset: u32,
824 blob: []const u8,
825 };
826
827 pub const File = struct {
828 pub const ops = [_]AbbrevOp{
829 .{ .literal = @intFromEnum(MetadataCode.FILE) },
830 .{ .literal = 0 }, // is distinct
831 MetadataAbbrev, // filename
832 MetadataAbbrev, // directory
833 .{ .literal = 0 }, // checksum
834 .{ .literal = 0 }, // checksum
835 };
836
837 filename: Builder.MetadataString,
838 directory: Builder.MetadataString,
839 };
840
841 pub const CompileUnit = struct {
842 pub const ops = [_]AbbrevOp{
843 .{ .literal = @intFromEnum(MetadataCode.COMPILE_UNIT) },
844 .{ .literal = 1 }, // is distinct
845 .{ .literal = std.dwarf.LANG.C99 }, // source language
846 MetadataAbbrev, // file
847 MetadataAbbrev, // producer
848 .{ .fixed = 1 }, // isOptimized
849 .{ .literal = 0 }, // raw flags
850 .{ .literal = 0 }, // runtime version
851 .{ .literal = 0 }, // split debug file name
852 .{ .literal = 1 }, // emission kind
853 MetadataAbbrev, // enums
854 .{ .literal = 0 }, // retained types
855 .{ .literal = 0 }, // subprograms
856 MetadataAbbrev, // globals
857 .{ .literal = 0 }, // imported entities
858 .{ .literal = 0 }, // DWO ID
859 .{ .literal = 0 }, // macros
860 .{ .literal = 0 }, // split debug inlining
861 .{ .literal = 0 }, // debug info profiling
862 .{ .literal = 0 }, // name table kind
863 .{ .literal = 0 }, // ranges base address
864 .{ .literal = 0 }, // raw sysroot
865 .{ .literal = 0 }, // raw SDK
866 };
867
868 file: Builder.Metadata,
869 producer: Builder.MetadataString,
870 is_optimized: bool,
871 enums: Builder.Metadata,
872 globals: Builder.Metadata,
873 };
874
875 pub const Subprogram = struct {
876 pub const ops = [_]AbbrevOp{
877 .{ .literal = @intFromEnum(MetadataCode.SUBPROGRAM) },
878 .{ .literal = 0b111 }, // is distinct | has sp flags | has flags
879 MetadataAbbrev, // scope
880 MetadataAbbrev, // name
881 MetadataAbbrev, // linkage name
882 MetadataAbbrev, // file
883 LineAbbrev, // line
884 MetadataAbbrev, // type
885 LineAbbrev, // scope line
886 .{ .literal = 0 }, // containing type
887 .{ .fixed = 32 }, // sp flags
888 .{ .literal = 0 }, // virtual index
889 .{ .fixed = 32 }, // flags
890 MetadataAbbrev, // compile unit
891 .{ .literal = 0 }, // template params
892 .{ .literal = 0 }, // declaration
893 .{ .literal = 0 }, // retained nodes
894 .{ .literal = 0 }, // this adjustment
895 .{ .literal = 0 }, // thrown types
896 .{ .literal = 0 }, // annotations
897 .{ .literal = 0 }, // target function name
898 };
899
900 scope: Builder.Metadata,
901 name: Builder.MetadataString,
902 linkage_name: Builder.MetadataString,
903 file: Builder.Metadata,
904 line: u32,
905 ty: Builder.Metadata,
906 scope_line: u32,
907 sp_flags: Builder.Metadata.Subprogram.DISPFlags,
908 flags: Builder.Metadata.DIFlags,
909 compile_unit: Builder.Metadata,
910 };
911
912 pub const LexicalBlock = struct {
913 pub const ops = [_]AbbrevOp{
914 .{ .literal = @intFromEnum(MetadataCode.LEXICAL_BLOCK) },
915 .{ .literal = 0 }, // is distinct
916 MetadataAbbrev, // scope
917 MetadataAbbrev, // file
918 LineAbbrev, // line
919 ColumnAbbrev, // column
920 };
921
922 scope: Builder.Metadata,
923 file: Builder.Metadata,
924 line: u32,
925 column: u32,
926 };
927
928 pub const Location = struct {
929 pub const ops = [_]AbbrevOp{
930 .{ .literal = @intFromEnum(MetadataCode.LOCATION) },
931 .{ .literal = 0 }, // is distinct
932 LineAbbrev, // line
933 ColumnAbbrev, // column
934 MetadataAbbrev, // scope
935 MetadataAbbrev, // inlined at
936 .{ .literal = 0 }, // is implicit code
937 };
938
939 line: u32,
940 column: u32,
941 scope: u32,
942 inlined_at: Builder.Metadata,
943 };
944
945 pub const BasicType = struct {
946 pub const ops = [_]AbbrevOp{
947 .{ .literal = @intFromEnum(MetadataCode.BASIC_TYPE) },
948 .{ .literal = 0 }, // is distinct
949 .{ .literal = std.dwarf.TAG.base_type }, // tag
950 MetadataAbbrev, // name
951 .{ .vbr = 6 }, // size in bits
952 .{ .literal = 0 }, // align in bits
953 .{ .vbr = 8 }, // encoding
954 .{ .literal = 0 }, // flags
955 };
956
957 name: Builder.MetadataString,
958 size_in_bits: u64,
959 encoding: u32,
960 };
961
962 pub const CompositeType = struct {
963 pub const ops = [_]AbbrevOp{
964 .{ .literal = @intFromEnum(MetadataCode.COMPOSITE_TYPE) },
965 .{ .literal = 0 | 0x2 }, // is distinct | is not used in old type ref
966 .{ .fixed = 32 }, // tag
967 MetadataAbbrev, // name
968 MetadataAbbrev, // file
969 LineAbbrev, // line
970 MetadataAbbrev, // scope
971 MetadataAbbrev, // underlying type
972 .{ .vbr = 6 }, // size in bits
973 .{ .vbr = 6 }, // align in bits
974 .{ .literal = 0 }, // offset in bits
975 .{ .fixed = 32 }, // flags
976 MetadataAbbrev, // elements
977 .{ .literal = 0 }, // runtime lang
978 .{ .literal = 0 }, // vtable holder
979 .{ .literal = 0 }, // template params
980 .{ .literal = 0 }, // raw id
981 .{ .literal = 0 }, // discriminator
982 .{ .literal = 0 }, // data location
983 .{ .literal = 0 }, // associated
984 .{ .literal = 0 }, // allocated
985 .{ .literal = 0 }, // rank
986 .{ .literal = 0 }, // annotations
987 };
988
989 tag: u32,
990 name: Builder.MetadataString,
991 file: Builder.Metadata,
992 line: u32,
993 scope: Builder.Metadata,
994 underlying_type: Builder.Metadata,
995 size_in_bits: u64,
996 align_in_bits: u64,
997 flags: Builder.Metadata.DIFlags,
998 elements: Builder.Metadata,
999 };
1000
1001 pub const DerivedType = struct {
1002 pub const ops = [_]AbbrevOp{
1003 .{ .literal = @intFromEnum(MetadataCode.DERIVED_TYPE) },
1004 .{ .literal = 0 }, // is distinct
1005 .{ .fixed = 32 }, // tag
1006 MetadataAbbrev, // name
1007 MetadataAbbrev, // file
1008 LineAbbrev, // line
1009 MetadataAbbrev, // scope
1010 MetadataAbbrev, // underlying type
1011 .{ .vbr = 6 }, // size in bits
1012 .{ .vbr = 6 }, // align in bits
1013 .{ .vbr = 6 }, // offset in bits
1014 .{ .literal = 0 }, // flags
1015 .{ .literal = 0 }, // extra data
1016 };
1017
1018 tag: u32,
1019 name: Builder.MetadataString,
1020 file: Builder.Metadata,
1021 line: u32,
1022 scope: Builder.Metadata,
1023 underlying_type: Builder.Metadata,
1024 size_in_bits: u64,
1025 align_in_bits: u64,
1026 offset_in_bits: u64,
1027 };
1028
1029 pub const SubroutineType = struct {
1030 pub const ops = [_]AbbrevOp{
1031 .{ .literal = @intFromEnum(MetadataCode.SUBROUTINE_TYPE) },
1032 .{ .literal = 0 | 0x2 }, // is distinct | has no old type refs
1033 .{ .literal = 0 }, // flags
1034 MetadataAbbrev, // types
1035 .{ .literal = 0 }, // cc
1036 };
1037
1038 types: Builder.Metadata,
1039 };
1040
1041 pub const Enumerator = struct {
1042 pub const id: MetadataCode = .ENUMERATOR;
1043
1044 pub const Flags = packed struct(u3) {
1045 distinct: bool = false,
1046 unsigned: bool,
1047 bigint: bool = true,
1048 };
1049
1050 pub const ops = [_]AbbrevOp{
1051 .{ .literal = @intFromEnum(Enumerator.id) },
1052 .{ .fixed = @bitSizeOf(Flags) }, // flags
1053 .{ .vbr = 6 }, // bit width
1054 MetadataAbbrev, // name
1055 .{ .vbr = 16 }, // integer value
1056 };
1057
1058 flags: Flags,
1059 bit_width: u32,
1060 name: Builder.MetadataString,
1061 value: u64,
1062 };
1063
1064 pub const Subrange = struct {
1065 pub const ops = [_]AbbrevOp{
1066 .{ .literal = @intFromEnum(MetadataCode.SUBRANGE) },
1067 .{ .literal = 0b10 }, // is distinct | version
1068 MetadataAbbrev, // count
1069 MetadataAbbrev, // lower bound
1070 .{ .literal = 0 }, // upper bound
1071 .{ .literal = 0 }, // stride
1072 };
1073
1074 count: Builder.Metadata,
1075 lower_bound: Builder.Metadata,
1076 };
1077
1078 pub const Expression = struct {
1079 pub const ops = [_]AbbrevOp{
1080 .{ .literal = @intFromEnum(MetadataCode.EXPRESSION) },
1081 .{ .literal = 0 | (3 << 1) }, // is distinct | version
1082 MetadataArrayAbbrev, // elements
1083 };
1084
1085 elements: []const u32,
1086 };
1087
1088 pub const Node = struct {
1089 pub const ops = [_]AbbrevOp{
1090 .{ .literal = @intFromEnum(MetadataCode.NODE) },
1091 MetadataArrayAbbrev, // elements
1092 };
1093
1094 elements: []const Builder.Metadata,
1095 };
1096
1097 pub const LocalVar = struct {
1098 pub const ops = [_]AbbrevOp{
1099 .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
1100 .{ .literal = 0b10 }, // is distinct | has alignment
1101 MetadataAbbrev, // scope
1102 MetadataAbbrev, // name
1103 MetadataAbbrev, // file
1104 LineAbbrev, // line
1105 MetadataAbbrev, // type
1106 .{ .literal = 0 }, // arg
1107 .{ .literal = 0 }, // flags
1108 .{ .literal = 0 }, // align bits
1109 .{ .literal = 0 }, // annotations
1110 };
1111
1112 scope: Builder.Metadata,
1113 name: Builder.MetadataString,
1114 file: Builder.Metadata,
1115 line: u32,
1116 ty: Builder.Metadata,
1117 };
1118
1119 pub const Parameter = struct {
1120 pub const ops = [_]AbbrevOp{
1121 .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
1122 .{ .literal = 0b10 }, // is distinct | has alignment
1123 MetadataAbbrev, // scope
1124 MetadataAbbrev, // name
1125 MetadataAbbrev, // file
1126 LineAbbrev, // line
1127 MetadataAbbrev, // type
1128 .{ .vbr = 4 }, // arg
1129 .{ .literal = 0 }, // flags
1130 .{ .literal = 0 }, // align bits
1131 .{ .literal = 0 }, // annotations
1132 };
1133
1134 scope: Builder.Metadata,
1135 name: Builder.MetadataString,
1136 file: Builder.Metadata,
1137 line: u32,
1138 ty: Builder.Metadata,
1139 arg: u32,
1140 };
1141
1142 pub const GlobalVar = struct {
1143 pub const ops = [_]AbbrevOp{
1144 .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR) },
1145 .{ .literal = 0b101 }, // is distinct | version
1146 MetadataAbbrev, // scope
1147 MetadataAbbrev, // name
1148 MetadataAbbrev, // linkage name
1149 MetadataAbbrev, // file
1150 LineAbbrev, // line
1151 MetadataAbbrev, // type
1152 .{ .fixed = 1 }, // local
1153 .{ .literal = 1 }, // defined
1154 .{ .literal = 0 }, // static data members declaration
1155 .{ .literal = 0 }, // template params
1156 .{ .literal = 0 }, // align in bits
1157 .{ .literal = 0 }, // annotations
1158 };
1159
1160 scope: Builder.Metadata,
1161 name: Builder.MetadataString,
1162 linkage_name: Builder.MetadataString,
1163 file: Builder.Metadata,
1164 line: u32,
1165 ty: Builder.Metadata,
1166 local: bool,
1167 };
1168
1169 pub const GlobalVarExpression = struct {
1170 pub const ops = [_]AbbrevOp{
1171 .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR_EXPR) },
1172 .{ .literal = 0 }, // is distinct
1173 MetadataAbbrev, // variable
1174 MetadataAbbrev, // expression
1175 };
1176
1177 variable: Builder.Metadata,
1178 expression: Builder.Metadata,
1179 };
1180
1181 pub const Constant = struct {
1182 pub const ops = [_]AbbrevOp{
1183 .{ .literal = @intFromEnum(MetadataCode.VALUE) },
1184 MetadataAbbrev, // type
1185 MetadataAbbrev, // value
1186 };
1187
1188 ty: Builder.Type,
1189 constant: Builder.Constant,
1190 };
1191
1192 pub const Name = struct {
1193 pub const ops = [_]AbbrevOp{
1194 .{ .literal = @intFromEnum(MetadataCode.NAME) },
1195 .{ .array_fixed = 8 }, // name
1196 };
1197
1198 name: []const u8,
1199 };
1200
1201 pub const NamedNode = struct {
1202 pub const ops = [_]AbbrevOp{
1203 .{ .literal = @intFromEnum(MetadataCode.NAMED_NODE) },
1204 MetadataArrayAbbrev, // elements
1205 };
1206
1207 elements: []const Builder.Metadata,
1208 };
1209
1210 pub const GlobalDeclAttachment = struct {
1211 pub const ops = [_]AbbrevOp{
1212 .{ .literal = @intFromEnum(MetadataCode.GLOBAL_DECL_ATTACHMENT) },
1213 ValueAbbrev, // value id
1214 .{ .fixed = 1 }, // kind
1215 MetadataAbbrev, // elements
1216 };
1217
1218 value: Builder.Constant,
1219 kind: FixedMetadataKind,
1220 metadata: Builder.Metadata,
1221 };
1222};
1223
1224pub const OperandBundleTags = struct {
1225 pub const id = 21;
1226
1227 pub const abbrevs = [_]type{OperandBundleTag};
1228
1229 pub const OperandBundleTag = struct {
1230 pub const ops = [_]AbbrevOp{
1231 .{ .literal = 1 },
1232 .array_char6,
1233 };
1234 tag: []const u8,
1235 };
1236};
1237
1238pub const FunctionMetadataBlock = struct {
1239 pub const id = 15;
1240
1241 pub const abbrevs = [_]type{
1242 Value,
1243 };
1244
1245 pub const Value = struct {
1246 pub const ops = [_]AbbrevOp{
1247 .{ .literal = 2 },
1248 .{ .fixed = 32 }, // variable
1249 .{ .fixed = 32 }, // expression
1250 };
1251
1252 ty: Builder.Type,
1253 value: Builder.Value,
1254 };
1255};
1256
1257pub const FunctionBlock = struct {
1258 pub const id = 12;
1259
1260 pub const abbrevs = [_]type{
1261 DeclareBlocks,
1262 Call,
1263 CallFast,
1264 FNeg,
1265 FNegFast,
1266 Binary,
1267 BinaryNoWrap,
1268 BinaryExact,
1269 BinaryFast,
1270 Cmp,
1271 CmpFast,
1272 Select,
1273 SelectFast,
1274 Cast,
1275 Alloca,
1276 GetElementPtr,
1277 ExtractValue,
1278 InsertValue,
1279 ExtractElement,
1280 InsertElement,
1281 ShuffleVector,
1282 RetVoid,
1283 Ret,
1284 Unreachable,
1285 Load,
1286 LoadAtomic,
1287 Store,
1288 StoreAtomic,
1289 BrUnconditional,
1290 BrConditional,
1291 VaArg,
1292 AtomicRmw,
1293 CmpXchg,
1294 Fence,
1295 DebugLoc,
1296 DebugLocAgain,
1297 ColdOperandBundle,
1298 IndirectBr,
1299 };
1300
1301 pub const DeclareBlocks = struct {
1302 pub const ops = [_]AbbrevOp{
1303 .{ .literal = 1 },
1304 .{ .vbr = 8 },
1305 };
1306 num_blocks: usize,
1307 };
1308
1309 pub const Call = struct {
1310 pub const CallType = packed struct(u17) {
1311 tail: bool = false,
1312 call_conv: Builder.CallConv,
1313 reserved: u3 = 0,
1314 must_tail: bool = false,
1315 // We always use the explicit type version as that is what LLVM does
1316 explicit_type: bool = true,
1317 no_tail: bool = false,
1318 };
1319 pub const ops = [_]AbbrevOp{
1320 .{ .literal = 34 },
1321 .{ .fixed_runtime = Builder.FunctionAttributes },
1322 .{ .fixed = @bitSizeOf(CallType) },
1323 .{ .fixed_runtime = Builder.Type },
1324 ValueAbbrev, // Callee
1325 ValueArrayAbbrev, // Args
1326 };
1327
1328 attributes: Builder.FunctionAttributes,
1329 call_type: CallType,
1330 type_id: Builder.Type,
1331 callee: Builder.Value,
1332 args: []const Builder.Value,
1333 };
1334
1335 pub const CallFast = struct {
1336 const CallType = packed struct(u18) {
1337 tail: bool = false,
1338 call_conv: Builder.CallConv,
1339 reserved: u3 = 0,
1340 must_tail: bool = false,
1341 // We always use the explicit type version as that is what LLVM does
1342 explicit_type: bool = true,
1343 no_tail: bool = false,
1344 fast: bool = true,
1345 };
1346
1347 pub const ops = [_]AbbrevOp{
1348 .{ .literal = 34 },
1349 .{ .fixed_runtime = Builder.FunctionAttributes },
1350 .{ .fixed = @bitSizeOf(CallType) },
1351 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1352 .{ .fixed_runtime = Builder.Type },
1353 ValueAbbrev, // Callee
1354 ValueArrayAbbrev, // Args
1355 };
1356
1357 attributes: Builder.FunctionAttributes,
1358 call_type: CallType,
1359 fast_math: Builder.FastMath,
1360 type_id: Builder.Type,
1361 callee: Builder.Value,
1362 args: []const Builder.Value,
1363 };
1364
1365 pub const FNeg = struct {
1366 pub const ops = [_]AbbrevOp{
1367 .{ .literal = 56 },
1368 ValueAbbrev,
1369 .{ .literal = 0 },
1370 };
1371
1372 val: u32,
1373 };
1374
1375 pub const FNegFast = struct {
1376 pub const ops = [_]AbbrevOp{
1377 .{ .literal = 56 },
1378 ValueAbbrev,
1379 .{ .literal = 0 },
1380 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1381 };
1382
1383 val: u32,
1384 fast_math: Builder.FastMath,
1385 };
1386
1387 pub const Binary = struct {
1388 const BinaryOpcode = Builder.BinaryOpcode;
1389 pub const ops = [_]AbbrevOp{
1390 .{ .literal = 2 },
1391 ValueAbbrev,
1392 ValueAbbrev,
1393 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1394 };
1395
1396 lhs: u32,
1397 rhs: u32,
1398 opcode: BinaryOpcode,
1399 };
1400
1401 pub const BinaryNoWrap = struct {
1402 const BinaryOpcode = Builder.BinaryOpcode;
1403 pub const ops = [_]AbbrevOp{
1404 .{ .literal = 2 },
1405 ValueAbbrev,
1406 ValueAbbrev,
1407 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1408 .{ .fixed = 2 },
1409 };
1410
1411 lhs: u32,
1412 rhs: u32,
1413 opcode: BinaryOpcode,
1414 flags: packed struct(u2) {
1415 no_unsigned_wrap: bool,
1416 no_signed_wrap: bool,
1417 },
1418 };
1419
1420 pub const BinaryExact = struct {
1421 const BinaryOpcode = Builder.BinaryOpcode;
1422 pub const ops = [_]AbbrevOp{
1423 .{ .literal = 2 },
1424 ValueAbbrev,
1425 ValueAbbrev,
1426 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1427 .{ .literal = 1 },
1428 };
1429
1430 lhs: u32,
1431 rhs: u32,
1432 opcode: BinaryOpcode,
1433 };
1434
1435 pub const BinaryFast = struct {
1436 const BinaryOpcode = Builder.BinaryOpcode;
1437 pub const ops = [_]AbbrevOp{
1438 .{ .literal = 2 },
1439 ValueAbbrev,
1440 ValueAbbrev,
1441 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1442 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1443 };
1444
1445 lhs: u32,
1446 rhs: u32,
1447 opcode: BinaryOpcode,
1448 fast_math: Builder.FastMath,
1449 };
1450
1451 pub const Cmp = struct {
1452 const CmpPredicate = Builder.CmpPredicate;
1453 pub const ops = [_]AbbrevOp{
1454 .{ .literal = 28 },
1455 ValueAbbrev,
1456 ValueAbbrev,
1457 .{ .fixed = @bitSizeOf(CmpPredicate) },
1458 };
1459
1460 lhs: u32,
1461 rhs: u32,
1462 pred: CmpPredicate,
1463 };
1464
1465 pub const CmpFast = struct {
1466 const CmpPredicate = Builder.CmpPredicate;
1467 pub const ops = [_]AbbrevOp{
1468 .{ .literal = 28 },
1469 ValueAbbrev,
1470 ValueAbbrev,
1471 .{ .fixed = @bitSizeOf(CmpPredicate) },
1472 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1473 };
1474
1475 lhs: u32,
1476 rhs: u32,
1477 pred: CmpPredicate,
1478 fast_math: Builder.FastMath,
1479 };
1480
1481 pub const Select = struct {
1482 pub const ops = [_]AbbrevOp{
1483 .{ .literal = 29 },
1484 ValueAbbrev,
1485 ValueAbbrev,
1486 ValueAbbrev,
1487 };
1488
1489 lhs: u32,
1490 rhs: u32,
1491 cond: u32,
1492 };
1493
1494 pub const SelectFast = struct {
1495 pub const ops = [_]AbbrevOp{
1496 .{ .literal = 29 },
1497 ValueAbbrev,
1498 ValueAbbrev,
1499 ValueAbbrev,
1500 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1501 };
1502
1503 lhs: u32,
1504 rhs: u32,
1505 cond: u32,
1506 fast_math: Builder.FastMath,
1507 };
1508
1509 pub const Cast = struct {
1510 const CastOpcode = Builder.CastOpcode;
1511 pub const ops = [_]AbbrevOp{
1512 .{ .literal = 3 },
1513 ValueAbbrev,
1514 .{ .fixed_runtime = Builder.Type },
1515 .{ .fixed = @bitSizeOf(CastOpcode) },
1516 };
1517
1518 val: u32,
1519 type_index: Builder.Type,
1520 opcode: CastOpcode,
1521 };
1522
1523 pub const Alloca = struct {
1524 pub const Flags = packed struct(u11) {
1525 align_lower: u5,
1526 inalloca: bool,
1527 explicit_type: bool,
1528 swift_error: bool,
1529 align_upper: u3,
1530 };
1531 pub const ops = [_]AbbrevOp{
1532 .{ .literal = 19 },
1533 .{ .fixed_runtime = Builder.Type },
1534 .{ .fixed_runtime = Builder.Type },
1535 ValueAbbrev,
1536 .{ .fixed = @bitSizeOf(Flags) },
1537 };
1538
1539 inst_type: Builder.Type,
1540 len_type: Builder.Type,
1541 len_value: u32,
1542 flags: Flags,
1543 };
1544
1545 pub const RetVoid = struct {
1546 pub const ops = [_]AbbrevOp{
1547 .{ .literal = 10 },
1548 };
1549 };
1550
1551 pub const Ret = struct {
1552 pub const ops = [_]AbbrevOp{
1553 .{ .literal = 10 },
1554 ValueAbbrev,
1555 };
1556 val: u32,
1557 };
1558
1559 pub const GetElementPtr = struct {
1560 pub const ops = [_]AbbrevOp{
1561 .{ .literal = 43 },
1562 .{ .fixed = 1 },
1563 .{ .fixed_runtime = Builder.Type },
1564 ValueAbbrev,
1565 ValueArrayAbbrev,
1566 };
1567
1568 is_inbounds: bool,
1569 type_index: Builder.Type,
1570 base: Builder.Value,
1571 indices: []const Builder.Value,
1572 };
1573
1574 pub const ExtractValue = struct {
1575 pub const ops = [_]AbbrevOp{
1576 .{ .literal = 26 },
1577 ValueAbbrev,
1578 ValueArrayAbbrev,
1579 };
1580
1581 val: u32,
1582 indices: []const u32,
1583 };
1584
1585 pub const InsertValue = struct {
1586 pub const ops = [_]AbbrevOp{
1587 .{ .literal = 27 },
1588 ValueAbbrev,
1589 ValueAbbrev,
1590 ValueArrayAbbrev,
1591 };
1592
1593 val: u32,
1594 elem: u32,
1595 indices: []const u32,
1596 };
1597
1598 pub const ExtractElement = struct {
1599 pub const ops = [_]AbbrevOp{
1600 .{ .literal = 6 },
1601 ValueAbbrev,
1602 ValueAbbrev,
1603 };
1604
1605 val: u32,
1606 index: u32,
1607 };
1608
1609 pub const InsertElement = struct {
1610 pub const ops = [_]AbbrevOp{
1611 .{ .literal = 7 },
1612 ValueAbbrev,
1613 ValueAbbrev,
1614 ValueAbbrev,
1615 };
1616
1617 val: u32,
1618 elem: u32,
1619 index: u32,
1620 };
1621
1622 pub const ShuffleVector = struct {
1623 pub const ops = [_]AbbrevOp{
1624 .{ .literal = 8 },
1625 ValueAbbrev,
1626 ValueAbbrev,
1627 ValueAbbrev,
1628 };
1629
1630 lhs: u32,
1631 rhs: u32,
1632 mask: u32,
1633 };
1634
1635 pub const Unreachable = struct {
1636 pub const ops = [_]AbbrevOp{
1637 .{ .literal = 15 },
1638 };
1639 };
1640
1641 pub const Load = struct {
1642 pub const ops = [_]AbbrevOp{
1643 .{ .literal = 20 },
1644 ValueAbbrev,
1645 .{ .fixed_runtime = Builder.Type },
1646 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1647 .{ .fixed = 1 },
1648 };
1649 ptr: u32,
1650 ty: Builder.Type,
1651 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1652 is_volatile: bool,
1653 };
1654
1655 pub const LoadAtomic = struct {
1656 pub const ops = [_]AbbrevOp{
1657 .{ .literal = 41 },
1658 ValueAbbrev,
1659 .{ .fixed_runtime = Builder.Type },
1660 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1661 .{ .fixed = 1 },
1662 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1663 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1664 };
1665 ptr: u32,
1666 ty: Builder.Type,
1667 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1668 is_volatile: bool,
1669 success_ordering: Builder.AtomicOrdering,
1670 sync_scope: Builder.SyncScope,
1671 };
1672
1673 pub const Store = struct {
1674 pub const ops = [_]AbbrevOp{
1675 .{ .literal = 44 },
1676 ValueAbbrev,
1677 ValueAbbrev,
1678 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1679 .{ .fixed = 1 },
1680 };
1681 ptr: u32,
1682 val: u32,
1683 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1684 is_volatile: bool,
1685 };
1686
1687 pub const StoreAtomic = struct {
1688 pub const ops = [_]AbbrevOp{
1689 .{ .literal = 45 },
1690 ValueAbbrev,
1691 ValueAbbrev,
1692 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1693 .{ .fixed = 1 },
1694 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1695 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1696 };
1697 ptr: u32,
1698 val: u32,
1699 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1700 is_volatile: bool,
1701 success_ordering: Builder.AtomicOrdering,
1702 sync_scope: Builder.SyncScope,
1703 };
1704
1705 pub const BrUnconditional = struct {
1706 pub const ops = [_]AbbrevOp{
1707 .{ .literal = 11 },
1708 BlockAbbrev,
1709 };
1710 block: u32,
1711 };
1712
1713 pub const BrConditional = struct {
1714 pub const ops = [_]AbbrevOp{
1715 .{ .literal = 11 },
1716 BlockAbbrev,
1717 BlockAbbrev,
1718 BlockAbbrev,
1719 };
1720 then_block: u32,
1721 else_block: u32,
1722 condition: u32,
1723 };
1724
1725 pub const VaArg = struct {
1726 pub const ops = [_]AbbrevOp{
1727 .{ .literal = 23 },
1728 .{ .fixed_runtime = Builder.Type },
1729 ValueAbbrev,
1730 .{ .fixed_runtime = Builder.Type },
1731 };
1732 list_type: Builder.Type,
1733 list: u32,
1734 type: Builder.Type,
1735 };
1736
1737 pub const AtomicRmw = struct {
1738 pub const ops = [_]AbbrevOp{
1739 .{ .literal = 59 },
1740 ValueAbbrev,
1741 ValueAbbrev,
1742 .{ .fixed = @bitSizeOf(Builder.Function.Instruction.AtomicRmw.Operation) },
1743 .{ .fixed = 1 },
1744 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1745 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1746 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1747 };
1748 ptr: u32,
1749 val: u32,
1750 operation: Builder.Function.Instruction.AtomicRmw.Operation,
1751 is_volatile: bool,
1752 success_ordering: Builder.AtomicOrdering,
1753 sync_scope: Builder.SyncScope,
1754 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1755 };
1756
1757 pub const CmpXchg = struct {
1758 pub const ops = [_]AbbrevOp{
1759 .{ .literal = 46 },
1760 ValueAbbrev,
1761 ValueAbbrev,
1762 ValueAbbrev,
1763 .{ .fixed = 1 },
1764 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1765 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1766 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1767 .{ .fixed = 1 },
1768 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1769 };
1770 ptr: u32,
1771 cmp: u32,
1772 new: u32,
1773 is_volatile: bool,
1774 success_ordering: Builder.AtomicOrdering,
1775 sync_scope: Builder.SyncScope,
1776 failure_ordering: Builder.AtomicOrdering,
1777 is_weak: bool,
1778 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1779 };
1780
1781 pub const Fence = struct {
1782 pub const ops = [_]AbbrevOp{
1783 .{ .literal = 36 },
1784 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1785 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1786 };
1787 ordering: Builder.AtomicOrdering,
1788 sync_scope: Builder.SyncScope,
1789 };
1790
1791 pub const DebugLoc = struct {
1792 pub const ops = [_]AbbrevOp{
1793 .{ .literal = 35 },
1794 LineAbbrev,
1795 ColumnAbbrev,
1796 MetadataAbbrev,
1797 MetadataAbbrev,
1798 .{ .literal = 0 },
1799 };
1800 line: u32,
1801 column: u32,
1802 scope: Builder.Metadata,
1803 inlined_at: Builder.Metadata,
1804 };
1805
1806 pub const DebugLocAgain = struct {
1807 pub const ops = [_]AbbrevOp{
1808 .{ .literal = 33 },
1809 };
1810 };
1811
1812 pub const ColdOperandBundle = struct {
1813 pub const ops = [_]AbbrevOp{
1814 .{ .literal = 55 },
1815 .{ .literal = 0 },
1816 };
1817 };
1818
1819 pub const IndirectBr = struct {
1820 pub const ops = [_]AbbrevOp{
1821 .{ .literal = 31 },
1822 .{ .fixed_runtime = Builder.Type },
1823 ValueAbbrev,
1824 BlockArrayAbbrev,
1825 };
1826 ty: Builder.Type,
1827 addr: Builder.Value,
1828 targets: []const Builder.Function.Block.Index,
1829 };
1830};
1831
1832pub const FunctionValueSymbolTable = struct {
1833 pub const id = 14;
1834
1835 pub const abbrevs = [_]type{
1836 BlockEntry,
1837 };
1838
1839 pub const BlockEntry = struct {
1840 pub const ops = [_]AbbrevOp{
1841 .{ .literal = 2 },
1842 ValueAbbrev,
1843 .{ .array_fixed = 8 },
1844 };
1845 value_id: u32,
1846 string: []const u8,
1847 };
1848};
1849
1850pub const Strtab = struct {
1851 pub const id = 23;
1852
1853 pub const abbrevs = [_]type{Blob};
1854
1855 pub const Blob = struct {
1856 pub const ops = [_]AbbrevOp{
1857 .{ .literal = 1 },
1858 .blob,
1859 };
1860 blob: []const u8,
1861 };
1862};
src/Compilation.zig+1-2
......@@ -551,7 +551,6 @@ pub const CObject = struct {
551551 }
552552
553553 pub fn parse(gpa: Allocator, path: []const u8) !*Bundle {
554 const BitcodeReader = @import("codegen/llvm/BitcodeReader.zig");
555554 const BlockId = enum(u32) {
556555 Meta = 8,
557556 Diag,
......@@ -588,7 +587,7 @@ pub const CObject = struct {
588587 defer file.close();
589588 var br = std.io.bufferedReader(file.reader());
590589 const reader = br.reader();
591 var bc = BitcodeReader.init(gpa, .{ .reader = reader.any() });
590 var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = reader.any() });
592591 defer bc.deinit();
593592
594593 var file_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .empty;
src/InternPool.zig+1-1
......@@ -6261,7 +6261,7 @@ pub const Alignment = enum(u6) {
62616261 return n + 1;
62626262 }
62636263
6264 const LlvmBuilderAlignment = @import("codegen/llvm/Builder.zig").Alignment;
6264 const LlvmBuilderAlignment = std.zig.llvm.Builder.Alignment;
62656265
62666266 pub fn toLlvm(this: @This()) LlvmBuilderAlignment {
62676267 return @enumFromInt(@intFromEnum(this));
src/codegen/llvm.zig+5-2
......@@ -6,7 +6,7 @@ const log = std.log.scoped(.codegen);
66const math = std.math;
77const DW = std.dwarf;
88
9const Builder = @import("llvm/Builder.zig");
9const Builder = std.zig.llvm.Builder;
1010const llvm = if (build_options.have_llvm)
1111 @import("llvm/bindings.zig")
1212else
......@@ -1216,7 +1216,10 @@ pub const Object = struct {
12161216 }
12171217 }
12181218
1219 const bitcode = try o.builder.toBitcode(o.gpa);
1219 const bitcode = try o.builder.toBitcode(o.gpa, .{
1220 .name = "zig",
1221 .version = build_options.semver,
1222 });
12201223 defer o.gpa.free(bitcode);
12211224 o.builder.clearAndFree();
12221225
src/codegen/llvm/BitcodeReader.zig deleted-515
......@@ -1,515 +0,0 @@
1allocator: std.mem.Allocator,
2record_arena: std.heap.ArenaAllocator.State,
3reader: std.io.AnyReader,
4keep_names: bool,
5bit_buffer: u32,
6bit_offset: u5,
7stack: std.ArrayListUnmanaged(State),
8block_info: std.AutoHashMapUnmanaged(u32, Block.Info),
9
10pub const Item = union(enum) {
11 start_block: Block,
12 record: Record,
13 end_block: Block,
14};
15
16pub const Block = struct {
17 name: []const u8,
18 id: u32,
19 len: u32,
20
21 const block_info: u32 = 0;
22 const first_reserved: u32 = 1;
23 const last_standard: u32 = 7;
24
25 const Info = struct {
26 block_name: []const u8,
27 record_names: std.AutoHashMapUnmanaged(u32, []const u8),
28 abbrevs: Abbrev.Store,
29
30 const default: Info = .{
31 .block_name = &.{},
32 .record_names = .{},
33 .abbrevs = .{ .abbrevs = .{} },
34 };
35
36 const set_bid_id: u32 = 1;
37 const block_name_id: u32 = 2;
38 const set_record_name_id: u32 = 3;
39
40 fn deinit(info: *Info, allocator: std.mem.Allocator) void {
41 allocator.free(info.block_name);
42 var record_names_it = info.record_names.valueIterator();
43 while (record_names_it.next()) |record_name| allocator.free(record_name.*);
44 info.record_names.deinit(allocator);
45 info.abbrevs.deinit(allocator);
46 info.* = undefined;
47 }
48 };
49};
50
51pub const Record = struct {
52 name: []const u8,
53 id: u32,
54 operands: []const u64,
55 blob: []const u8,
56
57 fn toOwnedAbbrev(record: Record, allocator: std.mem.Allocator) !Abbrev {
58 var operands = std.ArrayList(Abbrev.Operand).init(allocator);
59 defer operands.deinit();
60
61 assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId());
62 var i: usize = 0;
63 while (i < record.operands.len) switch (record.operands[i]) {
64 Abbrev.Operand.literal_id => {
65 try operands.append(.{ .literal = record.operands[i + 1] });
66 i += 2;
67 },
68 @intFromEnum(Abbrev.Operand.Encoding.fixed) => {
69 try operands.append(.{ .encoding = .{ .fixed = @intCast(record.operands[i + 1]) } });
70 i += 2;
71 },
72 @intFromEnum(Abbrev.Operand.Encoding.vbr) => {
73 try operands.append(.{ .encoding = .{ .vbr = @intCast(record.operands[i + 1]) } });
74 i += 2;
75 },
76 @intFromEnum(Abbrev.Operand.Encoding.array) => {
77 try operands.append(.{ .encoding = .{ .array = 6 } });
78 i += 1;
79 },
80 @intFromEnum(Abbrev.Operand.Encoding.char6) => {
81 try operands.append(.{ .encoding = .char6 });
82 i += 1;
83 },
84 @intFromEnum(Abbrev.Operand.Encoding.blob) => {
85 try operands.append(.{ .encoding = .{ .blob = 6 } });
86 i += 1;
87 },
88 else => unreachable,
89 };
90
91 return .{ .operands = try operands.toOwnedSlice() };
92 }
93};
94
95pub const InitOptions = struct {
96 reader: std.io.AnyReader,
97 keep_names: bool = false,
98};
99pub fn init(allocator: std.mem.Allocator, options: InitOptions) BitcodeReader {
100 return .{
101 .allocator = allocator,
102 .record_arena = .{},
103 .reader = options.reader,
104 .keep_names = options.keep_names,
105 .bit_buffer = 0,
106 .bit_offset = 0,
107 .stack = .{},
108 .block_info = .{},
109 };
110}
111
112pub fn deinit(bc: *BitcodeReader) void {
113 var block_info_it = bc.block_info.valueIterator();
114 while (block_info_it.next()) |block_info| block_info.deinit(bc.allocator);
115 bc.block_info.deinit(bc.allocator);
116 for (bc.stack.items) |*state| state.deinit(bc.allocator);
117 bc.stack.deinit(bc.allocator);
118 bc.record_arena.promote(bc.allocator).deinit();
119 bc.* = undefined;
120}
121
122pub fn checkMagic(bc: *BitcodeReader, magic: *const [4]u8) !void {
123 var buffer: [4]u8 = undefined;
124 try bc.readBytes(&buffer);
125 if (!std.mem.eql(u8, &buffer, magic)) return error.InvalidMagic;
126
127 try bc.startBlock(null, 2);
128 try bc.block_info.put(bc.allocator, Block.block_info, Block.Info.default);
129}
130
131pub fn next(bc: *BitcodeReader) !?Item {
132 while (true) {
133 const record = (try bc.nextRecord()) orelse
134 return if (bc.stack.items.len > 1) error.EndOfStream else null;
135 switch (record.id) {
136 else => return .{ .record = record },
137 Abbrev.Builtin.end_block.toRecordId() => {
138 const block_id = bc.stack.items[bc.stack.items.len - 1].block_id.?;
139 try bc.endBlock();
140 return .{ .end_block = .{
141 .name = if (bc.block_info.get(block_id)) |block_info|
142 block_info.block_name
143 else
144 &.{},
145 .id = block_id,
146 .len = 0,
147 } };
148 },
149 Abbrev.Builtin.enter_subblock.toRecordId() => {
150 const block_id: u32 = @intCast(record.operands[0]);
151 switch (block_id) {
152 Block.block_info => try bc.parseBlockInfoBlock(),
153 Block.first_reserved...Block.last_standard => return error.UnsupportedBlockId,
154 else => {
155 try bc.startBlock(block_id, @intCast(record.operands[1]));
156 return .{ .start_block = .{
157 .name = if (bc.block_info.get(block_id)) |block_info|
158 block_info.block_name
159 else
160 &.{},
161 .id = block_id,
162 .len = @intCast(record.operands[2]),
163 } };
164 },
165 }
166 },
167 Abbrev.Builtin.define_abbrev.toRecordId() => try bc.stack.items[bc.stack.items.len - 1]
168 .abbrevs.addOwnedAbbrev(bc.allocator, try record.toOwnedAbbrev(bc.allocator)),
169 }
170 }
171}
172
173pub fn skipBlock(bc: *BitcodeReader, block: Block) !void {
174 assert(bc.bit_offset == 0);
175 try bc.reader.skipBytes(@as(u34, block.len) * 4, .{});
176 try bc.endBlock();
177}
178
179fn nextRecord(bc: *BitcodeReader) !?Record {
180 const state = &bc.stack.items[bc.stack.items.len - 1];
181 const abbrev_id = bc.readFixed(u32, state.abbrev_id_width) catch |err| switch (err) {
182 error.EndOfStream => return null,
183 else => |e| return e,
184 };
185 if (abbrev_id >= state.abbrevs.abbrevs.items.len) return error.InvalidAbbrevId;
186 const abbrev = state.abbrevs.abbrevs.items[abbrev_id];
187
188 var record_arena = bc.record_arena.promote(bc.allocator);
189 defer bc.record_arena = record_arena.state;
190 _ = record_arena.reset(.retain_capacity);
191
192 var operands = try std.ArrayList(u64).initCapacity(record_arena.allocator(), abbrev.operands.len);
193 var blob = std.ArrayList(u8).init(record_arena.allocator());
194 for (abbrev.operands, 0..) |abbrev_operand, abbrev_operand_i| switch (abbrev_operand) {
195 .literal => |value| operands.appendAssumeCapacity(value),
196 .encoding => |abbrev_encoding| switch (abbrev_encoding) {
197 .fixed => |width| operands.appendAssumeCapacity(try bc.readFixed(u64, width)),
198 .vbr => |width| operands.appendAssumeCapacity(try bc.readVbr(u64, width)),
199 .array => |len_width| {
200 assert(abbrev_operand_i + 2 == abbrev.operands.len);
201 const len: usize = @intCast(try bc.readVbr(u32, len_width));
202 try operands.ensureUnusedCapacity(len);
203 for (0..len) |_| switch (abbrev.operands[abbrev.operands.len - 1]) {
204 .literal => |elem_value| operands.appendAssumeCapacity(elem_value),
205 .encoding => |elem_encoding| switch (elem_encoding) {
206 .fixed => |elem_width| operands.appendAssumeCapacity(try bc.readFixed(u64, elem_width)),
207 .vbr => |elem_width| operands.appendAssumeCapacity(try bc.readVbr(u64, elem_width)),
208 .array, .blob => return error.InvalidArrayElement,
209 .char6 => operands.appendAssumeCapacity(try bc.readChar6()),
210 },
211 .align_32_bits, .block_len => return error.UnsupportedArrayElement,
212 .abbrev_op => switch (try bc.readFixed(u1, 1)) {
213 1 => try operands.appendSlice(&.{
214 Abbrev.Operand.literal_id,
215 try bc.readVbr(u64, 8),
216 }),
217 0 => {
218 const encoding: Abbrev.Operand.Encoding =
219 @enumFromInt(try bc.readFixed(u3, 3));
220 try operands.append(@intFromEnum(encoding));
221 switch (encoding) {
222 .fixed, .vbr => try operands.append(try bc.readVbr(u7, 5)),
223 .array, .char6, .blob => {},
224 _ => return error.UnsuportedAbbrevEncoding,
225 }
226 },
227 },
228 };
229 break;
230 },
231 .char6 => operands.appendAssumeCapacity(try bc.readChar6()),
232 .blob => |len_width| {
233 assert(abbrev_operand_i + 1 == abbrev.operands.len);
234 const len = std.math.cast(usize, try bc.readVbr(u32, len_width)) orelse
235 return error.Overflow;
236 bc.align32Bits();
237 try bc.readBytes(try blob.addManyAsSlice(len));
238 bc.align32Bits();
239 },
240 },
241 .align_32_bits => bc.align32Bits(),
242 .block_len => operands.appendAssumeCapacity(try bc.read32Bits()),
243 .abbrev_op => unreachable,
244 };
245 return .{
246 .name = name: {
247 if (operands.items.len < 1) break :name &.{};
248 const record_id = std.math.cast(u32, operands.items[0]) orelse break :name &.{};
249 if (state.block_id) |block_id| {
250 if (bc.block_info.get(block_id)) |block_info| {
251 break :name block_info.record_names.get(record_id) orelse break :name &.{};
252 }
253 }
254 break :name &.{};
255 },
256 .id = std.math.cast(u32, operands.items[0]) orelse return error.InvalidRecordId,
257 .operands = operands.items[1..],
258 .blob = blob.items,
259 };
260}
261
262fn startBlock(bc: *BitcodeReader, block_id: ?u32, new_abbrev_len: u6) !void {
263 const abbrevs = if (block_id) |id|
264 if (bc.block_info.get(id)) |block_info| block_info.abbrevs.abbrevs.items else &.{}
265 else
266 &.{};
267
268 const state = try bc.stack.addOne(bc.allocator);
269 state.* = .{
270 .block_id = block_id,
271 .abbrev_id_width = new_abbrev_len,
272 .abbrevs = .{ .abbrevs = .{} },
273 };
274 try state.abbrevs.abbrevs.ensureTotalCapacity(
275 bc.allocator,
276 @typeInfo(Abbrev.Builtin).@"enum".fields.len + abbrevs.len,
277 );
278
279 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.end_block));
280 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
281 .operands = &.{
282 .{ .literal = Abbrev.Builtin.end_block.toRecordId() },
283 .align_32_bits,
284 },
285 });
286 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.enter_subblock));
287 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
288 .operands = &.{
289 .{ .literal = Abbrev.Builtin.enter_subblock.toRecordId() },
290 .{ .encoding = .{ .vbr = 8 } }, // blockid
291 .{ .encoding = .{ .vbr = 4 } }, // newabbrevlen
292 .align_32_bits,
293 .block_len,
294 },
295 });
296 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.define_abbrev));
297 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
298 .operands = &.{
299 .{ .literal = Abbrev.Builtin.define_abbrev.toRecordId() },
300 .{ .encoding = .{ .array = 5 } }, // numabbrevops
301 .abbrev_op,
302 },
303 });
304 assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.unabbrev_record));
305 try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{
306 .operands = &.{
307 .{ .encoding = .{ .vbr = 6 } }, // code
308 .{ .encoding = .{ .array = 6 } }, // numops
309 .{ .encoding = .{ .vbr = 6 } }, // ops
310 },
311 });
312 assert(state.abbrevs.abbrevs.items.len == @typeInfo(Abbrev.Builtin).@"enum".fields.len);
313 for (abbrevs) |abbrev| try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, abbrev);
314}
315
316fn endBlock(bc: *BitcodeReader) !void {
317 if (bc.stack.items.len == 0) return error.InvalidEndBlock;
318 bc.stack.items[bc.stack.items.len - 1].deinit(bc.allocator);
319 bc.stack.items.len -= 1;
320}
321
322fn parseBlockInfoBlock(bc: *BitcodeReader) !void {
323 var block_id: ?u32 = null;
324 while (true) {
325 const record = (try bc.nextRecord()) orelse return error.EndOfStream;
326 switch (record.id) {
327 Abbrev.Builtin.end_block.toRecordId() => break,
328 Abbrev.Builtin.define_abbrev.toRecordId() => {
329 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
330 return error.UnspecifiedBlockId);
331 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
332 try gop.value_ptr.abbrevs.addOwnedAbbrev(
333 bc.allocator,
334 try record.toOwnedAbbrev(bc.allocator),
335 );
336 },
337 Block.Info.set_bid_id => block_id = std.math.cast(u32, record.operands[0]) orelse
338 return error.Overflow,
339 Block.Info.block_name_id => if (bc.keep_names) {
340 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
341 return error.UnspecifiedBlockId);
342 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
343 const name = try bc.allocator.alloc(u8, record.operands.len);
344 errdefer bc.allocator.free(name);
345 for (name, record.operands) |*byte, operand|
346 byte.* = std.math.cast(u8, operand) orelse return error.InvalidName;
347 gop.value_ptr.block_name = name;
348 },
349 Block.Info.set_record_name_id => if (bc.keep_names) {
350 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
351 return error.UnspecifiedBlockId);
352 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
353 const name = try bc.allocator.alloc(u8, record.operands.len - 1);
354 errdefer bc.allocator.free(name);
355 for (name, record.operands[1..]) |*byte, operand|
356 byte.* = std.math.cast(u8, operand) orelse return error.InvalidName;
357 try gop.value_ptr.record_names.put(
358 bc.allocator,
359 std.math.cast(u32, record.operands[0]) orelse return error.Overflow,
360 name,
361 );
362 },
363 else => return error.UnsupportedBlockInfoRecord,
364 }
365 }
366}
367
368fn align32Bits(bc: *BitcodeReader) void {
369 bc.bit_offset = 0;
370}
371
372fn read32Bits(bc: *BitcodeReader) !u32 {
373 assert(bc.bit_offset == 0);
374 return bc.reader.readInt(u32, .little);
375}
376
377fn readBytes(bc: *BitcodeReader, bytes: []u8) !void {
378 assert(bc.bit_offset == 0);
379 try bc.reader.readNoEof(bytes);
380
381 const trailing_bytes = bytes.len % 4;
382 if (trailing_bytes > 0) {
383 var bit_buffer = [1]u8{0} ** 4;
384 try bc.reader.readNoEof(bit_buffer[trailing_bytes..]);
385 bc.bit_buffer = std.mem.readInt(u32, &bit_buffer, .little);
386 bc.bit_offset = @intCast(trailing_bytes * 8);
387 }
388}
389
390fn readFixed(bc: *BitcodeReader, comptime T: type, bits: u7) !T {
391 var result: T = 0;
392 var shift: std.math.Log2IntCeil(T) = 0;
393 var remaining = bits;
394 while (remaining > 0) {
395 if (bc.bit_offset == 0) bc.bit_buffer = try bc.read32Bits();
396 const chunk_len = @min(@as(u6, 32) - bc.bit_offset, remaining);
397 const chunk_mask = @as(u32, std.math.maxInt(u32)) >> @intCast(32 - chunk_len);
398 result |= @as(T, @intCast(bc.bit_buffer >> bc.bit_offset & chunk_mask)) << @intCast(shift);
399 shift += @intCast(chunk_len);
400 remaining -= chunk_len;
401 bc.bit_offset = @truncate(bc.bit_offset + chunk_len);
402 }
403 return result;
404}
405
406fn readVbr(bc: *BitcodeReader, comptime T: type, bits: u7) !T {
407 const chunk_bits: u6 = @intCast(bits - 1);
408 const chunk_msb = @as(u64, 1) << chunk_bits;
409
410 var result: u64 = 0;
411 var shift: u6 = 0;
412 while (true) {
413 const chunk = try bc.readFixed(u64, bits);
414 result |= (chunk & (chunk_msb - 1)) << shift;
415 if (chunk & chunk_msb == 0) break;
416 shift += chunk_bits;
417 }
418 return @intCast(result);
419}
420
421fn readChar6(bc: *BitcodeReader) !u8 {
422 return switch (try bc.readFixed(u6, 6)) {
423 0...25 => |c| @as(u8, c - 0) + 'a',
424 26...51 => |c| @as(u8, c - 26) + 'A',
425 52...61 => |c| @as(u8, c - 52) + '0',
426 62 => '.',
427 63 => '_',
428 };
429}
430
431const State = struct {
432 block_id: ?u32,
433 abbrev_id_width: u6,
434 abbrevs: Abbrev.Store,
435
436 fn deinit(state: *State, allocator: std.mem.Allocator) void {
437 state.abbrevs.deinit(allocator);
438 state.* = undefined;
439 }
440};
441
442const Abbrev = struct {
443 operands: []const Operand,
444
445 const Builtin = enum(u2) {
446 end_block,
447 enter_subblock,
448 define_abbrev,
449 unabbrev_record,
450
451 const first_record_id: u32 = std.math.maxInt(u32) - @typeInfo(Builtin).@"enum".fields.len + 1;
452 fn toRecordId(builtin: Builtin) u32 {
453 return first_record_id + @intFromEnum(builtin);
454 }
455 };
456
457 const Operand = union(enum) {
458 literal: u64,
459 encoding: union(Encoding) {
460 fixed: u7,
461 vbr: u6,
462 array: u3,
463 char6,
464 blob: u3,
465 },
466 align_32_bits,
467 block_len,
468 abbrev_op,
469
470 const literal_id = std.math.maxInt(u64);
471 const Encoding = enum(u3) {
472 fixed = 1,
473 vbr = 2,
474 array = 3,
475 char6 = 4,
476 blob = 5,
477 _,
478 };
479 };
480
481 const Store = struct {
482 abbrevs: std.ArrayListUnmanaged(Abbrev),
483
484 fn deinit(store: *Store, allocator: std.mem.Allocator) void {
485 for (store.abbrevs.items) |abbrev| allocator.free(abbrev.operands);
486 store.abbrevs.deinit(allocator);
487 store.* = undefined;
488 }
489
490 fn addAbbrev(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void {
491 try store.ensureUnusedCapacity(allocator, 1);
492 store.addAbbrevAssumeCapacity(abbrev);
493 }
494
495 fn addAbbrevAssumeCapacity(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void {
496 store.abbrevs.appendAssumeCapacity(.{
497 .operands = try allocator.dupe(Abbrev.Operand, abbrev.operands),
498 });
499 }
500
501 fn addOwnedAbbrev(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void {
502 try store.abbrevs.ensureUnusedCapacity(allocator, 1);
503 store.addOwnedAbbrevAssumeCapacity(abbrev);
504 }
505
506 fn addOwnedAbbrevAssumeCapacity(store: *Store, abbrev: Abbrev) void {
507 store.abbrevs.appendAssumeCapacity(abbrev);
508 }
509 };
510};
511
512const assert = std.debug.assert;
513const std = @import("std");
514
515const BitcodeReader = @This();
src/codegen/llvm/Builder.zig deleted-15225
......@@ -1,15225 +0,0 @@
1gpa: Allocator,
2strip: bool,
3
4source_filename: String,
5data_layout: String,
6target_triple: String,
7module_asm: std.ArrayListUnmanaged(u8),
8
9string_map: std.AutoArrayHashMapUnmanaged(void, void),
10string_indices: std.ArrayListUnmanaged(u32),
11string_bytes: std.ArrayListUnmanaged(u8),
12
13types: std.AutoArrayHashMapUnmanaged(String, Type),
14next_unnamed_type: String,
15next_unique_type_id: std.AutoHashMapUnmanaged(String, u32),
16type_map: std.AutoArrayHashMapUnmanaged(void, void),
17type_items: std.ArrayListUnmanaged(Type.Item),
18type_extra: std.ArrayListUnmanaged(u32),
19
20attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void),
21attributes_map: std.AutoArrayHashMapUnmanaged(void, void),
22attributes_indices: std.ArrayListUnmanaged(u32),
23attributes_extra: std.ArrayListUnmanaged(u32),
24
25function_attributes_set: std.AutoArrayHashMapUnmanaged(FunctionAttributes, void),
26
27globals: std.AutoArrayHashMapUnmanaged(StrtabString, Global),
28next_unnamed_global: StrtabString,
29next_replaced_global: StrtabString,
30next_unique_global_id: std.AutoHashMapUnmanaged(StrtabString, u32),
31aliases: std.ArrayListUnmanaged(Alias),
32variables: std.ArrayListUnmanaged(Variable),
33functions: std.ArrayListUnmanaged(Function),
34
35strtab_string_map: std.AutoArrayHashMapUnmanaged(void, void),
36strtab_string_indices: std.ArrayListUnmanaged(u32),
37strtab_string_bytes: std.ArrayListUnmanaged(u8),
38
39constant_map: std.AutoArrayHashMapUnmanaged(void, void),
40constant_items: std.MultiArrayList(Constant.Item),
41constant_extra: std.ArrayListUnmanaged(u32),
42constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
43
44metadata_map: std.AutoArrayHashMapUnmanaged(void, void),
45metadata_items: std.MultiArrayList(Metadata.Item),
46metadata_extra: std.ArrayListUnmanaged(u32),
47metadata_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
48metadata_forward_references: std.ArrayListUnmanaged(Metadata),
49metadata_named: std.AutoArrayHashMapUnmanaged(MetadataString, struct {
50 len: u32,
51 index: Metadata.Item.ExtraIndex,
52}),
53
54metadata_string_map: std.AutoArrayHashMapUnmanaged(void, void),
55metadata_string_indices: std.ArrayListUnmanaged(u32),
56metadata_string_bytes: std.ArrayListUnmanaged(u8),
57
58pub const expected_args_len = 16;
59pub const expected_attrs_len = 16;
60pub const expected_fields_len = 32;
61pub const expected_gep_indices_len = 8;
62pub const expected_cases_len = 8;
63pub const expected_incoming_len = 8;
64
65pub const Options = struct {
66 allocator: Allocator,
67 strip: bool = true,
68 name: []const u8 = &.{},
69 target: std.Target = builtin.target,
70 triple: []const u8 = &.{},
71};
72
73pub const String = enum(u32) {
74 none = std.math.maxInt(u31),
75 empty,
76 _,
77
78 pub fn isAnon(self: String) bool {
79 assert(self != .none);
80 return self.toIndex() == null;
81 }
82
83 pub fn slice(self: String, builder: *const Builder) ?[]const u8 {
84 const index = self.toIndex() orelse return null;
85 const start = builder.string_indices.items[index];
86 const end = builder.string_indices.items[index + 1];
87 return builder.string_bytes.items[start..end];
88 }
89
90 const FormatData = struct {
91 string: String,
92 builder: *const Builder,
93 };
94 fn format(
95 data: FormatData,
96 comptime fmt_str: []const u8,
97 _: std.fmt.FormatOptions,
98 writer: anytype,
99 ) @TypeOf(writer).Error!void {
100 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_|
101 @compileError("invalid format string: '" ++ fmt_str ++ "'");
102 assert(data.string != .none);
103 const string_slice = data.string.slice(data.builder) orelse
104 return writer.print("{d}", .{@intFromEnum(data.string)});
105 if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_|
106 return writer.writeAll(string_slice);
107 try printEscapedString(
108 string_slice,
109 if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
110 .always_quote
111 else
112 .quote_unless_valid_identifier,
113 writer,
114 );
115 }
116 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
117 return .{ .data = .{ .string = self, .builder = builder } };
118 }
119
120 fn fromIndex(index: ?usize) String {
121 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
122 @intFromEnum(String.empty))));
123 }
124
125 fn toIndex(self: String) ?usize {
126 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;
127 }
128
129 const Adapter = struct {
130 builder: *const Builder,
131 pub fn hash(_: Adapter, key: []const u8) u32 {
132 return @truncate(std.hash.Wyhash.hash(0, key));
133 }
134 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
135 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).slice(ctx.builder).?);
136 }
137 };
138};
139
140pub const BinaryOpcode = enum(u4) {
141 add = 0,
142 sub = 1,
143 mul = 2,
144 udiv = 3,
145 sdiv = 4,
146 urem = 5,
147 srem = 6,
148 shl = 7,
149 lshr = 8,
150 ashr = 9,
151 @"and" = 10,
152 @"or" = 11,
153 xor = 12,
154};
155
156pub const CastOpcode = enum(u4) {
157 trunc = 0,
158 zext = 1,
159 sext = 2,
160 fptoui = 3,
161 fptosi = 4,
162 uitofp = 5,
163 sitofp = 6,
164 fptrunc = 7,
165 fpext = 8,
166 ptrtoint = 9,
167 inttoptr = 10,
168 bitcast = 11,
169 addrspacecast = 12,
170};
171
172pub const CmpPredicate = enum(u6) {
173 fcmp_false = 0,
174 fcmp_oeq = 1,
175 fcmp_ogt = 2,
176 fcmp_oge = 3,
177 fcmp_olt = 4,
178 fcmp_ole = 5,
179 fcmp_one = 6,
180 fcmp_ord = 7,
181 fcmp_uno = 8,
182 fcmp_ueq = 9,
183 fcmp_ugt = 10,
184 fcmp_uge = 11,
185 fcmp_ult = 12,
186 fcmp_ule = 13,
187 fcmp_une = 14,
188 fcmp_true = 15,
189 icmp_eq = 32,
190 icmp_ne = 33,
191 icmp_ugt = 34,
192 icmp_uge = 35,
193 icmp_ult = 36,
194 icmp_ule = 37,
195 icmp_sgt = 38,
196 icmp_sge = 39,
197 icmp_slt = 40,
198 icmp_sle = 41,
199};
200
201pub const Type = enum(u32) {
202 void,
203 half,
204 bfloat,
205 float,
206 double,
207 fp128,
208 x86_fp80,
209 ppc_fp128,
210 x86_amx,
211 x86_mmx,
212 label,
213 token,
214 metadata,
215
216 i1,
217 i8,
218 i16,
219 i29,
220 i32,
221 i64,
222 i80,
223 i128,
224 ptr,
225 @"ptr addrspace(4)",
226
227 none = std.math.maxInt(u32),
228 _,
229
230 pub const ptr_amdgpu_constant =
231 @field(Type, std.fmt.comptimePrint("ptr{ }", .{AddrSpace.amdgpu.constant}));
232
233 pub const Tag = enum(u4) {
234 simple,
235 function,
236 vararg_function,
237 integer,
238 pointer,
239 target,
240 vector,
241 scalable_vector,
242 small_array,
243 array,
244 structure,
245 packed_structure,
246 named_structure,
247 };
248
249 pub const Simple = enum(u5) {
250 void = 2,
251 half = 10,
252 bfloat = 23,
253 float = 3,
254 double = 4,
255 fp128 = 14,
256 x86_fp80 = 13,
257 ppc_fp128 = 15,
258 x86_amx = 24,
259 x86_mmx = 17,
260 label = 5,
261 token = 22,
262 metadata = 16,
263 };
264
265 pub const Function = struct {
266 ret: Type,
267 params_len: u32,
268 //params: [params_len]Value,
269
270 pub const Kind = enum { normal, vararg };
271 };
272
273 pub const Target = extern struct {
274 name: String,
275 types_len: u32,
276 ints_len: u32,
277 //types: [types_len]Type,
278 //ints: [ints_len]u32,
279 };
280
281 pub const Vector = extern struct {
282 len: u32,
283 child: Type,
284
285 fn length(self: Vector) u32 {
286 return self.len;
287 }
288
289 pub const Kind = enum { normal, scalable };
290 };
291
292 pub const Array = extern struct {
293 len_lo: u32,
294 len_hi: u32,
295 child: Type,
296
297 fn length(self: Array) u64 {
298 return @as(u64, self.len_hi) << 32 | self.len_lo;
299 }
300 };
301
302 pub const Structure = struct {
303 fields_len: u32,
304 //fields: [fields_len]Type,
305
306 pub const Kind = enum { normal, @"packed" };
307 };
308
309 pub const NamedStructure = struct {
310 id: String,
311 body: Type,
312 };
313
314 pub const Item = packed struct(u32) {
315 tag: Tag,
316 data: ExtraIndex,
317
318 pub const ExtraIndex = u28;
319 };
320
321 pub fn tag(self: Type, builder: *const Builder) Tag {
322 return builder.type_items.items[@intFromEnum(self)].tag;
323 }
324
325 pub fn unnamedTag(self: Type, builder: *const Builder) Tag {
326 const item = builder.type_items.items[@intFromEnum(self)];
327 return switch (item.tag) {
328 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
329 .unnamedTag(builder),
330 else => item.tag,
331 };
332 }
333
334 pub fn scalarTag(self: Type, builder: *const Builder) Tag {
335 const item = builder.type_items.items[@intFromEnum(self)];
336 return switch (item.tag) {
337 .vector, .scalable_vector => builder.typeExtraData(Type.Vector, item.data)
338 .child.tag(builder),
339 else => item.tag,
340 };
341 }
342
343 pub fn isFloatingPoint(self: Type) bool {
344 return switch (self) {
345 .half, .bfloat, .float, .double, .fp128, .x86_fp80, .ppc_fp128 => true,
346 else => false,
347 };
348 }
349
350 pub fn isInteger(self: Type, builder: *const Builder) bool {
351 return switch (self) {
352 .i1, .i8, .i16, .i29, .i32, .i64, .i80, .i128 => true,
353 else => switch (self.tag(builder)) {
354 .integer => true,
355 else => false,
356 },
357 };
358 }
359
360 pub fn isPointer(self: Type, builder: *const Builder) bool {
361 return switch (self) {
362 .ptr => true,
363 else => switch (self.tag(builder)) {
364 .pointer => true,
365 else => false,
366 },
367 };
368 }
369
370 pub fn pointerAddrSpace(self: Type, builder: *const Builder) AddrSpace {
371 switch (self) {
372 .ptr => return .default,
373 else => {
374 const item = builder.type_items.items[@intFromEnum(self)];
375 assert(item.tag == .pointer);
376 return @enumFromInt(item.data);
377 },
378 }
379 }
380
381 pub fn isFunction(self: Type, builder: *const Builder) bool {
382 return switch (self.tag(builder)) {
383 .function, .vararg_function => true,
384 else => false,
385 };
386 }
387
388 pub fn functionKind(self: Type, builder: *const Builder) Type.Function.Kind {
389 return switch (self.tag(builder)) {
390 .function => .normal,
391 .vararg_function => .vararg,
392 else => unreachable,
393 };
394 }
395
396 pub fn functionParameters(self: Type, builder: *const Builder) []const Type {
397 const item = builder.type_items.items[@intFromEnum(self)];
398 switch (item.tag) {
399 .function,
400 .vararg_function,
401 => {
402 var extra = builder.typeExtraDataTrail(Type.Function, item.data);
403 return extra.trail.next(extra.data.params_len, Type, builder);
404 },
405 else => unreachable,
406 }
407 }
408
409 pub fn functionReturn(self: Type, builder: *const Builder) Type {
410 const item = builder.type_items.items[@intFromEnum(self)];
411 switch (item.tag) {
412 .function,
413 .vararg_function,
414 => return builder.typeExtraData(Type.Function, item.data).ret,
415 else => unreachable,
416 }
417 }
418
419 pub fn isVector(self: Type, builder: *const Builder) bool {
420 return switch (self.tag(builder)) {
421 .vector, .scalable_vector => true,
422 else => false,
423 };
424 }
425
426 pub fn vectorKind(self: Type, builder: *const Builder) Type.Vector.Kind {
427 return switch (self.tag(builder)) {
428 .vector => .normal,
429 .scalable_vector => .scalable,
430 else => unreachable,
431 };
432 }
433
434 pub fn isStruct(self: Type, builder: *const Builder) bool {
435 return switch (self.tag(builder)) {
436 .structure, .packed_structure, .named_structure => true,
437 else => false,
438 };
439 }
440
441 pub fn structKind(self: Type, builder: *const Builder) Type.Structure.Kind {
442 return switch (self.unnamedTag(builder)) {
443 .structure => .normal,
444 .packed_structure => .@"packed",
445 else => unreachable,
446 };
447 }
448
449 pub fn isAggregate(self: Type, builder: *const Builder) bool {
450 return switch (self.tag(builder)) {
451 .small_array, .array, .structure, .packed_structure, .named_structure => true,
452 else => false,
453 };
454 }
455
456 pub fn scalarBits(self: Type, builder: *const Builder) u24 {
457 return switch (self) {
458 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,
459 .i1 => 1,
460 .i8 => 8,
461 .half, .bfloat, .i16 => 16,
462 .i29 => 29,
463 .float, .i32 => 32,
464 .double, .i64, .x86_mmx => 64,
465 .x86_fp80, .i80 => 80,
466 .fp128, .ppc_fp128, .i128 => 128,
467 .ptr, .@"ptr addrspace(4)" => @panic("TODO: query data layout"),
468 _ => {
469 const item = builder.type_items.items[@intFromEnum(self)];
470 return switch (item.tag) {
471 .simple,
472 .function,
473 .vararg_function,
474 => unreachable,
475 .integer => @intCast(item.data),
476 .pointer => @panic("TODO: query data layout"),
477 .target => unreachable,
478 .vector,
479 .scalable_vector,
480 => builder.typeExtraData(Type.Vector, item.data).child.scalarBits(builder),
481 .small_array,
482 .array,
483 .structure,
484 .packed_structure,
485 .named_structure,
486 => unreachable,
487 };
488 },
489 };
490 }
491
492 pub fn childType(self: Type, builder: *const Builder) Type {
493 const item = builder.type_items.items[@intFromEnum(self)];
494 return switch (item.tag) {
495 .vector,
496 .scalable_vector,
497 .small_array,
498 => builder.typeExtraData(Type.Vector, item.data).child,
499 .array => builder.typeExtraData(Type.Array, item.data).child,
500 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body,
501 else => unreachable,
502 };
503 }
504
505 pub fn scalarType(self: Type, builder: *const Builder) Type {
506 if (self.isFloatingPoint()) return self;
507 const item = builder.type_items.items[@intFromEnum(self)];
508 return switch (item.tag) {
509 .integer,
510 .pointer,
511 => self,
512 .vector,
513 .scalable_vector,
514 => builder.typeExtraData(Type.Vector, item.data).child,
515 else => unreachable,
516 };
517 }
518
519 pub fn changeScalar(self: Type, scalar: Type, builder: *Builder) Allocator.Error!Type {
520 try builder.ensureUnusedTypeCapacity(1, Type.Vector, 0);
521 return self.changeScalarAssumeCapacity(scalar, builder);
522 }
523
524 pub fn changeScalarAssumeCapacity(self: Type, scalar: Type, builder: *Builder) Type {
525 if (self.isFloatingPoint()) return scalar;
526 const item = builder.type_items.items[@intFromEnum(self)];
527 return switch (item.tag) {
528 .integer,
529 .pointer,
530 => scalar,
531 inline .vector,
532 .scalable_vector,
533 => |kind| builder.vectorTypeAssumeCapacity(
534 switch (kind) {
535 .vector => .normal,
536 .scalable_vector => .scalable,
537 else => unreachable,
538 },
539 builder.typeExtraData(Type.Vector, item.data).len,
540 scalar,
541 ),
542 else => unreachable,
543 };
544 }
545
546 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
547 const item = builder.type_items.items[@intFromEnum(self)];
548 return switch (item.tag) {
549 .vector,
550 .scalable_vector,
551 => builder.typeExtraData(Type.Vector, item.data).len,
552 else => unreachable,
553 };
554 }
555
556 pub fn changeLength(self: Type, len: u32, builder: *Builder) Allocator.Error!Type {
557 try builder.ensureUnusedTypeCapacity(1, Type.Array, 0);
558 return self.changeLengthAssumeCapacity(len, builder);
559 }
560
561 pub fn changeLengthAssumeCapacity(self: Type, len: u32, builder: *Builder) Type {
562 const item = builder.type_items.items[@intFromEnum(self)];
563 return switch (item.tag) {
564 inline .vector,
565 .scalable_vector,
566 => |kind| builder.vectorTypeAssumeCapacity(
567 switch (kind) {
568 .vector => .normal,
569 .scalable_vector => .scalable,
570 else => unreachable,
571 },
572 len,
573 builder.typeExtraData(Type.Vector, item.data).child,
574 ),
575 .small_array => builder.arrayTypeAssumeCapacity(
576 len,
577 builder.typeExtraData(Type.Vector, item.data).child,
578 ),
579 .array => builder.arrayTypeAssumeCapacity(
580 len,
581 builder.typeExtraData(Type.Array, item.data).child,
582 ),
583 else => unreachable,
584 };
585 }
586
587 pub fn aggregateLen(self: Type, builder: *const Builder) usize {
588 const item = builder.type_items.items[@intFromEnum(self)];
589 return switch (item.tag) {
590 .vector,
591 .scalable_vector,
592 .small_array,
593 => builder.typeExtraData(Type.Vector, item.data).len,
594 .array => @intCast(builder.typeExtraData(Type.Array, item.data).length()),
595 .structure,
596 .packed_structure,
597 => builder.typeExtraData(Type.Structure, item.data).fields_len,
598 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
599 .aggregateLen(builder),
600 else => unreachable,
601 };
602 }
603
604 pub fn structFields(self: Type, builder: *const Builder) []const Type {
605 const item = builder.type_items.items[@intFromEnum(self)];
606 switch (item.tag) {
607 .structure,
608 .packed_structure,
609 => {
610 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
611 return extra.trail.next(extra.data.fields_len, Type, builder);
612 },
613 .named_structure => return builder.typeExtraData(Type.NamedStructure, item.data).body
614 .structFields(builder),
615 else => unreachable,
616 }
617 }
618
619 pub fn childTypeAt(self: Type, indices: []const u32, builder: *const Builder) Type {
620 if (indices.len == 0) return self;
621 const item = builder.type_items.items[@intFromEnum(self)];
622 return switch (item.tag) {
623 .small_array => builder.typeExtraData(Type.Vector, item.data).child
624 .childTypeAt(indices[1..], builder),
625 .array => builder.typeExtraData(Type.Array, item.data).child
626 .childTypeAt(indices[1..], builder),
627 .structure,
628 .packed_structure,
629 => {
630 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
631 const fields = extra.trail.next(extra.data.fields_len, Type, builder);
632 return fields[indices[0]].childTypeAt(indices[1..], builder);
633 },
634 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
635 .childTypeAt(indices, builder),
636 else => unreachable,
637 };
638 }
639
640 pub fn targetLayoutType(self: Type, builder: *const Builder) Type {
641 _ = self;
642 _ = builder;
643 @panic("TODO: implement targetLayoutType");
644 }
645
646 pub fn isSized(self: Type, builder: *const Builder) Allocator.Error!bool {
647 var visited: IsSizedVisited = .{};
648 defer visited.deinit(builder.gpa);
649 const result = try self.isSizedVisited(&visited, builder);
650 return result;
651 }
652
653 const FormatData = struct {
654 type: Type,
655 builder: *const Builder,
656 };
657 fn format(
658 data: FormatData,
659 comptime fmt_str: []const u8,
660 fmt_opts: std.fmt.FormatOptions,
661 writer: anytype,
662 ) @TypeOf(writer).Error!void {
663 assert(data.type != .none);
664 if (comptime std.mem.eql(u8, fmt_str, "m")) {
665 const item = data.builder.type_items.items[@intFromEnum(data.type)];
666 switch (item.tag) {
667 .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) {
668 .void => "isVoid",
669 .half => "f16",
670 .bfloat => "bf16",
671 .float => "f32",
672 .double => "f64",
673 .fp128 => "f128",
674 .x86_fp80 => "f80",
675 .ppc_fp128 => "ppcf128",
676 .x86_amx => "x86amx",
677 .x86_mmx => "x86mmx",
678 .label, .token => unreachable,
679 .metadata => "Metadata",
680 }),
681 .function, .vararg_function => |kind| {
682 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
683 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
684 try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)});
685 for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)});
686 switch (kind) {
687 .function => {},
688 .vararg_function => try writer.writeAll("vararg"),
689 else => unreachable,
690 }
691 try writer.writeByte('f');
692 },
693 .integer => try writer.print("i{d}", .{item.data}),
694 .pointer => try writer.print("p{d}", .{item.data}),
695 .target => {
696 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
697 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
698 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
699 try writer.print("t{s}", .{extra.data.name.slice(data.builder).?});
700 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
701 for (ints) |int| try writer.print("_{d}", .{int});
702 try writer.writeByte('t');
703 },
704 .vector, .scalable_vector => |kind| {
705 const extra = data.builder.typeExtraData(Type.Vector, item.data);
706 try writer.print("{s}v{d}{m}", .{
707 switch (kind) {
708 .vector => "",
709 .scalable_vector => "nx",
710 else => unreachable,
711 },
712 extra.len,
713 extra.child.fmt(data.builder),
714 });
715 },
716 inline .small_array, .array => |kind| {
717 const extra = data.builder.typeExtraData(switch (kind) {
718 .small_array => Type.Vector,
719 .array => Type.Array,
720 else => unreachable,
721 }, item.data);
722 try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) });
723 },
724 .structure, .packed_structure => {
725 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
726 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
727 try writer.writeAll("sl_");
728 for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)});
729 try writer.writeByte('s');
730 },
731 .named_structure => {
732 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
733 try writer.writeAll("s_");
734 if (extra.id.slice(data.builder)) |id| try writer.writeAll(id);
735 },
736 }
737 return;
738 }
739 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
740 const item = data.builder.type_items.items[@intFromEnum(data.type)];
741 switch (item.tag) {
742 .simple => unreachable,
743 .function, .vararg_function => |kind| {
744 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
745 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
746 if (!comptime std.mem.eql(u8, fmt_str, ">"))
747 try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)});
748 if (!comptime std.mem.eql(u8, fmt_str, "<")) {
749 try writer.writeByte('(');
750 for (params, 0..) |param, index| {
751 if (index > 0) try writer.writeAll(", ");
752 try writer.print("{%}", .{param.fmt(data.builder)});
753 }
754 switch (kind) {
755 .function => {},
756 .vararg_function => {
757 if (params.len > 0) try writer.writeAll(", ");
758 try writer.writeAll("...");
759 },
760 else => unreachable,
761 }
762 try writer.writeByte(')');
763 }
764 },
765 .integer => try writer.print("i{d}", .{item.data}),
766 .pointer => try writer.print("ptr{ }", .{@as(AddrSpace, @enumFromInt(item.data))}),
767 .target => {
768 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
769 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
770 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
771 try writer.print(
772 \\target({"}
773 , .{extra.data.name.fmt(data.builder)});
774 for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)});
775 for (ints) |int| try writer.print(", {d}", .{int});
776 try writer.writeByte(')');
777 },
778 .vector, .scalable_vector => |kind| {
779 const extra = data.builder.typeExtraData(Type.Vector, item.data);
780 try writer.print("<{s}{d} x {%}>", .{
781 switch (kind) {
782 .vector => "",
783 .scalable_vector => "vscale x ",
784 else => unreachable,
785 },
786 extra.len,
787 extra.child.fmt(data.builder),
788 });
789 },
790 inline .small_array, .array => |kind| {
791 const extra = data.builder.typeExtraData(switch (kind) {
792 .small_array => Type.Vector,
793 .array => Type.Array,
794 else => unreachable,
795 }, item.data);
796 try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) });
797 },
798 .structure, .packed_structure => |kind| {
799 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
800 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
801 switch (kind) {
802 .structure => {},
803 .packed_structure => try writer.writeByte('<'),
804 else => unreachable,
805 }
806 try writer.writeAll("{ ");
807 for (fields, 0..) |field, index| {
808 if (index > 0) try writer.writeAll(", ");
809 try writer.print("{%}", .{field.fmt(data.builder)});
810 }
811 try writer.writeAll(" }");
812 switch (kind) {
813 .structure => {},
814 .packed_structure => try writer.writeByte('>'),
815 else => unreachable,
816 }
817 },
818 .named_structure => {
819 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
820 if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
821 extra.id.fmt(data.builder),
822 }) else switch (extra.body) {
823 .none => try writer.writeAll("opaque"),
824 else => try format(.{
825 .type = extra.body,
826 .builder = data.builder,
827 }, fmt_str, fmt_opts, writer),
828 }
829 },
830 }
831 }
832 pub fn fmt(self: Type, builder: *const Builder) std.fmt.Formatter(format) {
833 return .{ .data = .{ .type = self, .builder = builder } };
834 }
835
836 const IsSizedVisited = std.AutoHashMapUnmanaged(Type, void);
837 fn isSizedVisited(
838 self: Type,
839 visited: *IsSizedVisited,
840 builder: *const Builder,
841 ) Allocator.Error!bool {
842 return switch (self) {
843 .void,
844 .label,
845 .token,
846 .metadata,
847 => false,
848 .half,
849 .bfloat,
850 .float,
851 .double,
852 .fp128,
853 .x86_fp80,
854 .ppc_fp128,
855 .x86_amx,
856 .x86_mmx,
857 .i1,
858 .i8,
859 .i16,
860 .i29,
861 .i32,
862 .i64,
863 .i80,
864 .i128,
865 .ptr,
866 .@"ptr addrspace(4)",
867 => true,
868 .none => unreachable,
869 _ => {
870 const item = builder.type_items.items[@intFromEnum(self)];
871 return switch (item.tag) {
872 .simple => unreachable,
873 .function,
874 .vararg_function,
875 => false,
876 .integer,
877 .pointer,
878 => true,
879 .target => self.targetLayoutType(builder).isSizedVisited(visited, builder),
880 .vector,
881 .scalable_vector,
882 .small_array,
883 => builder.typeExtraData(Type.Vector, item.data)
884 .child.isSizedVisited(visited, builder),
885 .array => builder.typeExtraData(Type.Array, item.data)
886 .child.isSizedVisited(visited, builder),
887 .structure,
888 .packed_structure,
889 => {
890 if (try visited.fetchPut(builder.gpa, self, {})) |_| return false;
891
892 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
893 const fields = extra.trail.next(extra.data.fields_len, Type, builder);
894 for (fields) |field| {
895 if (field.isVector(builder) and field.vectorKind(builder) == .scalable)
896 return false;
897 if (!try field.isSizedVisited(visited, builder))
898 return false;
899 }
900 return true;
901 },
902 .named_structure => {
903 const body = builder.typeExtraData(Type.NamedStructure, item.data).body;
904 return body != .none and try body.isSizedVisited(visited, builder);
905 },
906 };
907 },
908 };
909 }
910};
911
912pub const Attribute = union(Kind) {
913 // Parameter Attributes
914 zeroext,
915 signext,
916 inreg,
917 byval: Type,
918 byref: Type,
919 preallocated: Type,
920 inalloca: Type,
921 sret: Type,
922 elementtype: Type,
923 @"align": Alignment,
924 @"noalias",
925 nocapture,
926 nofree,
927 nest,
928 returned,
929 nonnull,
930 dereferenceable: u32,
931 dereferenceable_or_null: u32,
932 swiftself,
933 swiftasync,
934 swifterror,
935 immarg,
936 noundef,
937 nofpclass: FpClass,
938 alignstack: Alignment,
939 allocalign,
940 allocptr,
941 readnone,
942 readonly,
943 writeonly,
944
945 // Function Attributes
946 //alignstack: Alignment,
947 allockind: AllocKind,
948 allocsize: AllocSize,
949 alwaysinline,
950 builtin,
951 cold,
952 convergent,
953 disable_sanitizer_information,
954 fn_ret_thunk_extern,
955 hot,
956 inlinehint,
957 jumptable,
958 memory: Memory,
959 minsize,
960 naked,
961 nobuiltin,
962 nocallback,
963 noduplicate,
964 //nofree,
965 noimplicitfloat,
966 @"noinline",
967 nomerge,
968 nonlazybind,
969 noprofile,
970 skipprofile,
971 noredzone,
972 noreturn,
973 norecurse,
974 willreturn,
975 nosync,
976 nounwind,
977 nosanitize_bounds,
978 nosanitize_coverage,
979 null_pointer_is_valid,
980 optforfuzzing,
981 optnone,
982 optsize,
983 //preallocated: Type,
984 returns_twice,
985 safestack,
986 sanitize_address,
987 sanitize_memory,
988 sanitize_thread,
989 sanitize_hwaddress,
990 sanitize_memtag,
991 speculative_load_hardening,
992 speculatable,
993 ssp,
994 sspstrong,
995 sspreq,
996 strictfp,
997 uwtable: UwTable,
998 nocf_check,
999 shadowcallstack,
1000 mustprogress,
1001 vscale_range: VScaleRange,
1002
1003 // Global Attributes
1004 no_sanitize_address,
1005 no_sanitize_hwaddress,
1006 //sanitize_memtag,
1007 sanitize_address_dyninit,
1008
1009 string: struct { kind: String, value: String },
1010 none: noreturn,
1011
1012 pub const Index = enum(u32) {
1013 _,
1014
1015 pub fn getKind(self: Index, builder: *const Builder) Kind {
1016 return self.toStorage(builder).kind;
1017 }
1018
1019 pub fn toAttribute(self: Index, builder: *const Builder) Attribute {
1020 @setEvalBranchQuota(2_000);
1021 const storage = self.toStorage(builder);
1022 if (storage.kind.toString()) |kind| return .{ .string = .{
1023 .kind = kind,
1024 .value = @enumFromInt(storage.value),
1025 } } else return switch (storage.kind) {
1026 inline .zeroext,
1027 .signext,
1028 .inreg,
1029 .byval,
1030 .byref,
1031 .preallocated,
1032 .inalloca,
1033 .sret,
1034 .elementtype,
1035 .@"align",
1036 .@"noalias",
1037 .nocapture,
1038 .nofree,
1039 .nest,
1040 .returned,
1041 .nonnull,
1042 .dereferenceable,
1043 .dereferenceable_or_null,
1044 .swiftself,
1045 .swiftasync,
1046 .swifterror,
1047 .immarg,
1048 .noundef,
1049 .nofpclass,
1050 .alignstack,
1051 .allocalign,
1052 .allocptr,
1053 .readnone,
1054 .readonly,
1055 .writeonly,
1056 //.alignstack,
1057 .allockind,
1058 .allocsize,
1059 .alwaysinline,
1060 .builtin,
1061 .cold,
1062 .convergent,
1063 .disable_sanitizer_information,
1064 .fn_ret_thunk_extern,
1065 .hot,
1066 .inlinehint,
1067 .jumptable,
1068 .memory,
1069 .minsize,
1070 .naked,
1071 .nobuiltin,
1072 .nocallback,
1073 .noduplicate,
1074 //.nofree,
1075 .noimplicitfloat,
1076 .@"noinline",
1077 .nomerge,
1078 .nonlazybind,
1079 .noprofile,
1080 .skipprofile,
1081 .noredzone,
1082 .noreturn,
1083 .norecurse,
1084 .willreturn,
1085 .nosync,
1086 .nounwind,
1087 .nosanitize_bounds,
1088 .nosanitize_coverage,
1089 .null_pointer_is_valid,
1090 .optforfuzzing,
1091 .optnone,
1092 .optsize,
1093 //.preallocated,
1094 .returns_twice,
1095 .safestack,
1096 .sanitize_address,
1097 .sanitize_memory,
1098 .sanitize_thread,
1099 .sanitize_hwaddress,
1100 .sanitize_memtag,
1101 .speculative_load_hardening,
1102 .speculatable,
1103 .ssp,
1104 .sspstrong,
1105 .sspreq,
1106 .strictfp,
1107 .uwtable,
1108 .nocf_check,
1109 .shadowcallstack,
1110 .mustprogress,
1111 .vscale_range,
1112 .no_sanitize_address,
1113 .no_sanitize_hwaddress,
1114 .sanitize_address_dyninit,
1115 => |kind| {
1116 const field = comptime blk: {
1117 @setEvalBranchQuota(10_000);
1118 for (@typeInfo(Attribute).@"union".fields) |field| {
1119 if (std.mem.eql(u8, field.name, @tagName(kind))) break :blk field;
1120 }
1121 unreachable;
1122 };
1123 comptime assert(std.mem.eql(u8, @tagName(kind), field.name));
1124 return @unionInit(Attribute, field.name, switch (field.type) {
1125 void => {},
1126 u32 => storage.value,
1127 Alignment, String, Type, UwTable => @enumFromInt(storage.value),
1128 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
1129 else => @compileError("bad payload type: " ++ field.name ++ ": " ++
1130 @typeName(field.type)),
1131 });
1132 },
1133 .string, .none => unreachable,
1134 _ => unreachable,
1135 };
1136 }
1137
1138 const FormatData = struct {
1139 attribute_index: Index,
1140 builder: *const Builder,
1141 };
1142 fn format(
1143 data: FormatData,
1144 comptime fmt_str: []const u8,
1145 _: std.fmt.FormatOptions,
1146 writer: anytype,
1147 ) @TypeOf(writer).Error!void {
1148 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
1149 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1150 const attribute = data.attribute_index.toAttribute(data.builder);
1151 switch (attribute) {
1152 .zeroext,
1153 .signext,
1154 .inreg,
1155 .@"noalias",
1156 .nocapture,
1157 .nofree,
1158 .nest,
1159 .returned,
1160 .nonnull,
1161 .swiftself,
1162 .swiftasync,
1163 .swifterror,
1164 .immarg,
1165 .noundef,
1166 .allocalign,
1167 .allocptr,
1168 .readnone,
1169 .readonly,
1170 .writeonly,
1171 .alwaysinline,
1172 .builtin,
1173 .cold,
1174 .convergent,
1175 .disable_sanitizer_information,
1176 .fn_ret_thunk_extern,
1177 .hot,
1178 .inlinehint,
1179 .jumptable,
1180 .minsize,
1181 .naked,
1182 .nobuiltin,
1183 .nocallback,
1184 .noduplicate,
1185 .noimplicitfloat,
1186 .@"noinline",
1187 .nomerge,
1188 .nonlazybind,
1189 .noprofile,
1190 .skipprofile,
1191 .noredzone,
1192 .noreturn,
1193 .norecurse,
1194 .willreturn,
1195 .nosync,
1196 .nounwind,
1197 .nosanitize_bounds,
1198 .nosanitize_coverage,
1199 .null_pointer_is_valid,
1200 .optforfuzzing,
1201 .optnone,
1202 .optsize,
1203 .returns_twice,
1204 .safestack,
1205 .sanitize_address,
1206 .sanitize_memory,
1207 .sanitize_thread,
1208 .sanitize_hwaddress,
1209 .sanitize_memtag,
1210 .speculative_load_hardening,
1211 .speculatable,
1212 .ssp,
1213 .sspstrong,
1214 .sspreq,
1215 .strictfp,
1216 .nocf_check,
1217 .shadowcallstack,
1218 .mustprogress,
1219 .no_sanitize_address,
1220 .no_sanitize_hwaddress,
1221 .sanitize_address_dyninit,
1222 => try writer.print(" {s}", .{@tagName(attribute)}),
1223 .byval,
1224 .byref,
1225 .preallocated,
1226 .inalloca,
1227 .sret,
1228 .elementtype,
1229 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1230 .@"align" => |alignment| try writer.print("{ }", .{alignment}),
1231 .dereferenceable,
1232 .dereferenceable_or_null,
1233 => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
1234 .nofpclass => |fpclass| {
1235 const Int = @typeInfo(FpClass).@"struct".backing_integer.?;
1236 try writer.print(" {s}(", .{@tagName(attribute)});
1237 var any = false;
1238 var remaining: Int = @bitCast(fpclass);
1239 inline for (@typeInfo(FpClass).@"struct".decls) |decl| {
1240 const pattern: Int = @bitCast(@field(FpClass, decl.name));
1241 if (remaining & pattern == pattern) {
1242 if (!any) {
1243 try writer.writeByte(' ');
1244 any = true;
1245 }
1246 try writer.writeAll(decl.name);
1247 remaining &= ~pattern;
1248 }
1249 }
1250 try writer.writeByte(')');
1251 },
1252 .alignstack => |alignment| try writer.print(
1253 if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
1254 " {s}={d}"
1255 else
1256 " {s}({d})",
1257 .{ @tagName(attribute), alignment.toByteUnits() orelse return },
1258 ),
1259 .allockind => |allockind| {
1260 try writer.print(" {s}(\"", .{@tagName(attribute)});
1261 var any = false;
1262 inline for (@typeInfo(AllocKind).@"struct".fields) |field| {
1263 if (comptime std.mem.eql(u8, field.name, "_")) continue;
1264 if (@field(allockind, field.name)) {
1265 if (!any) {
1266 try writer.writeByte(',');
1267 any = true;
1268 }
1269 try writer.writeAll(field.name);
1270 }
1271 }
1272 try writer.writeAll("\")");
1273 },
1274 .allocsize => |allocsize| {
1275 try writer.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size });
1276 if (allocsize.num_elems != AllocSize.none)
1277 try writer.print(",{d}", .{allocsize.num_elems});
1278 try writer.writeByte(')');
1279 },
1280 .memory => |memory| {
1281 try writer.print(" {s}(", .{@tagName(attribute)});
1282 var any = memory.other != .none or
1283 (memory.argmem == .none and memory.inaccessiblemem == .none);
1284 if (any) try writer.writeAll(@tagName(memory.other));
1285 inline for (.{ "argmem", "inaccessiblemem" }) |kind| {
1286 if (@field(memory, kind) != memory.other) {
1287 if (any) try writer.writeAll(", ");
1288 try writer.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) });
1289 any = true;
1290 }
1291 }
1292 try writer.writeByte(')');
1293 },
1294 .uwtable => |uwtable| if (uwtable != .none) {
1295 try writer.print(" {s}", .{@tagName(attribute)});
1296 if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
1297 },
1298 .vscale_range => |vscale_range| try writer.print(" {s}({d},{d})", .{
1299 @tagName(attribute),
1300 vscale_range.min.toByteUnits().?,
1301 vscale_range.max.toByteUnits() orelse 0,
1302 }),
1303 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
1304 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
1305 if (string_attr.value != .empty)
1306 try writer.print("={\"}", .{string_attr.value.fmt(data.builder)});
1307 },
1308 .none => unreachable,
1309 }
1310 }
1311 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
1312 return .{ .data = .{ .attribute_index = self, .builder = builder } };
1313 }
1314
1315 fn toStorage(self: Index, builder: *const Builder) Storage {
1316 return builder.attributes.keys()[@intFromEnum(self)];
1317 }
1318 };
1319
1320 pub const Kind = enum(u32) {
1321 // Parameter Attributes
1322 zeroext = 34,
1323 signext = 24,
1324 inreg = 5,
1325 byval = 3,
1326 byref = 69,
1327 preallocated = 65,
1328 inalloca = 38,
1329 sret = 29, // TODO: ?
1330 elementtype = 77,
1331 @"align" = 1,
1332 @"noalias" = 9,
1333 nocapture = 11,
1334 nofree = 62,
1335 nest = 8,
1336 returned = 22,
1337 nonnull = 39,
1338 dereferenceable = 41,
1339 dereferenceable_or_null = 42,
1340 swiftself = 46,
1341 swiftasync = 75,
1342 swifterror = 47,
1343 immarg = 60,
1344 noundef = 68,
1345 nofpclass = 87,
1346 alignstack = 25,
1347 allocalign = 80,
1348 allocptr = 81,
1349 readnone = 20,
1350 readonly = 21,
1351 writeonly = 52,
1352
1353 // Function Attributes
1354 //alignstack,
1355 allockind = 82,
1356 allocsize = 51,
1357 alwaysinline = 2,
1358 builtin = 35,
1359 cold = 36,
1360 convergent = 43,
1361 disable_sanitizer_information = 78,
1362 fn_ret_thunk_extern = 84,
1363 hot = 72,
1364 inlinehint = 4,
1365 jumptable = 40,
1366 memory = 86,
1367 minsize = 6,
1368 naked = 7,
1369 nobuiltin = 10,
1370 nocallback = 71,
1371 noduplicate = 12,
1372 //nofree,
1373 noimplicitfloat = 13,
1374 @"noinline" = 14,
1375 nomerge = 66,
1376 nonlazybind = 15,
1377 noprofile = 73,
1378 skipprofile = 85,
1379 noredzone = 16,
1380 noreturn = 17,
1381 norecurse = 48,
1382 willreturn = 61,
1383 nosync = 63,
1384 nounwind = 18,
1385 nosanitize_bounds = 79,
1386 nosanitize_coverage = 76,
1387 null_pointer_is_valid = 67,
1388 optforfuzzing = 57,
1389 optnone = 37,
1390 optsize = 19,
1391 //preallocated,
1392 returns_twice = 23,
1393 safestack = 44,
1394 sanitize_address = 30,
1395 sanitize_memory = 32,
1396 sanitize_thread = 31,
1397 sanitize_hwaddress = 55,
1398 sanitize_memtag = 64,
1399 speculative_load_hardening = 59,
1400 speculatable = 53,
1401 ssp = 26,
1402 sspstrong = 28,
1403 sspreq = 27,
1404 strictfp = 54,
1405 uwtable = 33,
1406 nocf_check = 56,
1407 shadowcallstack = 58,
1408 mustprogress = 70,
1409 vscale_range = 74,
1410
1411 // Global Attributes
1412 no_sanitize_address = 100,
1413 no_sanitize_hwaddress = 101,
1414 //sanitize_memtag,
1415 sanitize_address_dyninit = 102,
1416
1417 string = std.math.maxInt(u31),
1418 none = std.math.maxInt(u32),
1419 _,
1420
1421 pub const len = @typeInfo(Kind).@"enum".fields.len - 2;
1422
1423 pub fn fromString(str: String) Kind {
1424 assert(!str.isAnon());
1425 const kind: Kind = @enumFromInt(@intFromEnum(str));
1426 assert(kind != .none);
1427 return kind;
1428 }
1429
1430 fn toString(self: Kind) ?String {
1431 assert(self != .none);
1432 const str: String = @enumFromInt(@intFromEnum(self));
1433 return if (str.isAnon()) null else str;
1434 }
1435 };
1436
1437 pub const FpClass = packed struct(u32) {
1438 signaling_nan: bool = false,
1439 quiet_nan: bool = false,
1440 negative_infinity: bool = false,
1441 negative_normal: bool = false,
1442 negative_subnormal: bool = false,
1443 negative_zero: bool = false,
1444 positive_zero: bool = false,
1445 positive_subnormal: bool = false,
1446 positive_normal: bool = false,
1447 positive_infinity: bool = false,
1448 _: u22 = 0,
1449
1450 pub const all = FpClass{
1451 .signaling_nan = true,
1452 .quiet_nan = true,
1453 .negative_infinity = true,
1454 .negative_normal = true,
1455 .negative_subnormal = true,
1456 .negative_zero = true,
1457 .positive_zero = true,
1458 .positive_subnormal = true,
1459 .positive_normal = true,
1460 .positive_infinity = true,
1461 };
1462
1463 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
1464 pub const snan = FpClass{ .signaling_nan = true };
1465 pub const qnan = FpClass{ .quiet_nan = true };
1466
1467 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
1468 pub const ninf = FpClass{ .negative_infinity = true };
1469 pub const pinf = FpClass{ .positive_infinity = true };
1470
1471 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
1472 pub const nzero = FpClass{ .negative_zero = true };
1473 pub const pzero = FpClass{ .positive_zero = true };
1474
1475 pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
1476 pub const nsub = FpClass{ .negative_subnormal = true };
1477 pub const psub = FpClass{ .positive_subnormal = true };
1478
1479 pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
1480 pub const nnorm = FpClass{ .negative_normal = true };
1481 pub const pnorm = FpClass{ .positive_normal = true };
1482 };
1483
1484 pub const AllocKind = packed struct(u32) {
1485 alloc: bool,
1486 realloc: bool,
1487 free: bool,
1488 uninitialized: bool,
1489 zeroed: bool,
1490 aligned: bool,
1491 _: u26 = 0,
1492 };
1493
1494 pub const AllocSize = packed struct(u32) {
1495 elem_size: u16,
1496 num_elems: u16,
1497
1498 pub const none = std.math.maxInt(u16);
1499
1500 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
1501 return .{ .num_elems = switch (self.num_elems) {
1502 else => self.num_elems,
1503 none => std.math.maxInt(u32),
1504 }, .elem_size = self.elem_size };
1505 }
1506 };
1507
1508 pub const Memory = packed struct(u32) {
1509 argmem: Effect = .none,
1510 inaccessiblemem: Effect = .none,
1511 other: Effect = .none,
1512 _: u26 = 0,
1513
1514 pub const Effect = enum(u2) { none, read, write, readwrite };
1515
1516 fn all(effect: Effect) Memory {
1517 return .{ .argmem = effect, .inaccessiblemem = effect, .other = effect };
1518 }
1519 };
1520
1521 pub const UwTable = enum(u32) {
1522 none,
1523 sync,
1524 @"async",
1525
1526 pub const default = UwTable.@"async";
1527 };
1528
1529 pub const VScaleRange = packed struct(u32) {
1530 min: Alignment,
1531 max: Alignment,
1532 _: u20 = 0,
1533
1534 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {
1535 return .{
1536 .max = @intCast(self.max.toByteUnits() orelse 0),
1537 .min = @intCast(self.min.toByteUnits().?),
1538 };
1539 }
1540 };
1541
1542 pub fn getKind(self: Attribute) Kind {
1543 return switch (self) {
1544 else => self,
1545 .string => |string_attr| Kind.fromString(string_attr.kind),
1546 };
1547 }
1548
1549 const Storage = extern struct {
1550 kind: Kind,
1551 value: u32,
1552 };
1553
1554 fn toStorage(self: Attribute) Storage {
1555 return switch (self) {
1556 inline else => |value, tag| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
1557 void => 0,
1558 u32 => value,
1559 Alignment, String, Type, UwTable => @intFromEnum(value),
1560 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
1561 else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))),
1562 } },
1563 .string => |string_attr| .{
1564 .kind = Kind.fromString(string_attr.kind),
1565 .value = @intFromEnum(string_attr.value),
1566 },
1567 .none => unreachable,
1568 };
1569 }
1570};
1571
1572pub const Attributes = enum(u32) {
1573 none,
1574 _,
1575
1576 pub fn slice(self: Attributes, builder: *const Builder) []const Attribute.Index {
1577 const start = builder.attributes_indices.items[@intFromEnum(self)];
1578 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1579 return @ptrCast(builder.attributes_extra.items[start..end]);
1580 }
1581
1582 const FormatData = struct {
1583 attributes: Attributes,
1584 builder: *const Builder,
1585 };
1586 fn format(
1587 data: FormatData,
1588 comptime fmt_str: []const u8,
1589 fmt_opts: std.fmt.FormatOptions,
1590 writer: anytype,
1591 ) @TypeOf(writer).Error!void {
1592 for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{
1593 .attribute_index = attribute_index,
1594 .builder = data.builder,
1595 }, fmt_str, fmt_opts, writer);
1596 }
1597 pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) {
1598 return .{ .data = .{ .attributes = self, .builder = builder } };
1599 }
1600};
1601
1602pub const FunctionAttributes = enum(u32) {
1603 none,
1604 _,
1605
1606 const function_index = 0;
1607 const return_index = 1;
1608 const params_index = 2;
1609
1610 pub const Wip = struct {
1611 maps: Maps = .{},
1612
1613 const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index);
1614 const Maps = std.ArrayListUnmanaged(Map);
1615
1616 pub fn deinit(self: *Wip, builder: *const Builder) void {
1617 for (self.maps.items) |*map| map.deinit(builder.gpa);
1618 self.maps.deinit(builder.gpa);
1619 self.* = undefined;
1620 }
1621
1622 pub fn addFnAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1623 try self.addAttr(function_index, attribute, builder);
1624 }
1625
1626 pub fn addFnAttrIndex(
1627 self: *Wip,
1628 attribute_index: Attribute.Index,
1629 builder: *const Builder,
1630 ) Allocator.Error!void {
1631 try self.addAttrIndex(function_index, attribute_index, builder);
1632 }
1633
1634 pub fn removeFnAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1635 return self.removeAttr(function_index, attribute_kind);
1636 }
1637
1638 pub fn addRetAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1639 try self.addAttr(return_index, attribute, builder);
1640 }
1641
1642 pub fn addRetAttrIndex(
1643 self: *Wip,
1644 attribute_index: Attribute.Index,
1645 builder: *const Builder,
1646 ) Allocator.Error!void {
1647 try self.addAttrIndex(return_index, attribute_index, builder);
1648 }
1649
1650 pub fn removeRetAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1651 return self.removeAttr(return_index, attribute_kind);
1652 }
1653
1654 pub fn addParamAttr(
1655 self: *Wip,
1656 param_index: usize,
1657 attribute: Attribute,
1658 builder: *Builder,
1659 ) Allocator.Error!void {
1660 try self.addAttr(params_index + param_index, attribute, builder);
1661 }
1662
1663 pub fn addParamAttrIndex(
1664 self: *Wip,
1665 param_index: usize,
1666 attribute_index: Attribute.Index,
1667 builder: *const Builder,
1668 ) Allocator.Error!void {
1669 try self.addAttrIndex(params_index + param_index, attribute_index, builder);
1670 }
1671
1672 pub fn removeParamAttr(
1673 self: *Wip,
1674 param_index: usize,
1675 attribute_kind: Attribute.Kind,
1676 ) Allocator.Error!bool {
1677 return self.removeAttr(params_index + param_index, attribute_kind);
1678 }
1679
1680 pub fn finish(self: *const Wip, builder: *Builder) Allocator.Error!FunctionAttributes {
1681 const attributes = try builder.gpa.alloc(Attributes, self.maps.items.len);
1682 defer builder.gpa.free(attributes);
1683 for (attributes, self.maps.items) |*attribute, map|
1684 attribute.* = try builder.attrs(map.values());
1685 return builder.fnAttrs(attributes);
1686 }
1687
1688 fn addAttr(
1689 self: *Wip,
1690 index: usize,
1691 attribute: Attribute,
1692 builder: *Builder,
1693 ) Allocator.Error!void {
1694 const map = try self.getOrPutMap(builder.gpa, index);
1695 try map.put(builder.gpa, attribute.getKind(), try builder.attr(attribute));
1696 }
1697
1698 fn addAttrIndex(
1699 self: *Wip,
1700 index: usize,
1701 attribute_index: Attribute.Index,
1702 builder: *const Builder,
1703 ) Allocator.Error!void {
1704 const map = try self.getOrPutMap(builder.gpa, index);
1705 try map.put(builder.gpa, attribute_index.getKind(builder), attribute_index);
1706 }
1707
1708 fn removeAttr(self: *Wip, index: usize, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1709 const map = self.getMap(index) orelse return false;
1710 return map.swapRemove(attribute_kind);
1711 }
1712
1713 fn getOrPutMap(self: *Wip, allocator: Allocator, index: usize) Allocator.Error!*Map {
1714 if (index >= self.maps.items.len)
1715 try self.maps.appendNTimes(allocator, .{}, index + 1 - self.maps.items.len);
1716 return &self.maps.items[index];
1717 }
1718
1719 fn getMap(self: *Wip, index: usize) ?*Map {
1720 return if (index >= self.maps.items.len) null else &self.maps.items[index];
1721 }
1722
1723 fn ensureTotalLength(self: *Wip, new_len: usize) Allocator.Error!void {
1724 try self.maps.appendNTimes(
1725 .{},
1726 std.math.sub(usize, new_len, self.maps.items.len) catch return,
1727 );
1728 }
1729 };
1730
1731 pub fn func(self: FunctionAttributes, builder: *const Builder) Attributes {
1732 return self.get(function_index, builder);
1733 }
1734
1735 pub fn ret(self: FunctionAttributes, builder: *const Builder) Attributes {
1736 return self.get(return_index, builder);
1737 }
1738
1739 pub fn param(self: FunctionAttributes, param_index: usize, builder: *const Builder) Attributes {
1740 return self.get(params_index + param_index, builder);
1741 }
1742
1743 pub fn toWip(self: FunctionAttributes, builder: *const Builder) Allocator.Error!Wip {
1744 var wip: Wip = .{};
1745 errdefer wip.deinit(builder);
1746 const attributes_slice = self.slice(builder);
1747 try wip.maps.ensureTotalCapacityPrecise(builder.gpa, attributes_slice.len);
1748 for (attributes_slice) |attributes| {
1749 const map = wip.maps.addOneAssumeCapacity();
1750 map.* = .{};
1751 const attribute_slice = attributes.slice(builder);
1752 try map.ensureTotalCapacity(builder.gpa, attribute_slice.len);
1753 for (attributes.slice(builder)) |attribute|
1754 map.putAssumeCapacityNoClobber(attribute.getKind(builder), attribute);
1755 }
1756 return wip;
1757 }
1758
1759 fn get(self: FunctionAttributes, index: usize, builder: *const Builder) Attributes {
1760 const attribute_slice = self.slice(builder);
1761 return if (index < attribute_slice.len) attribute_slice[index] else .none;
1762 }
1763
1764 fn slice(self: FunctionAttributes, builder: *const Builder) []const Attributes {
1765 const start = builder.attributes_indices.items[@intFromEnum(self)];
1766 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1767 return @ptrCast(builder.attributes_extra.items[start..end]);
1768 }
1769};
1770
1771pub const Linkage = enum(u4) {
1772 private = 9,
1773 internal = 3,
1774 weak = 1,
1775 weak_odr = 10,
1776 linkonce = 4,
1777 linkonce_odr = 11,
1778 available_externally = 12,
1779 appending = 2,
1780 common = 8,
1781 extern_weak = 7,
1782 external = 0,
1783
1784 pub fn format(
1785 self: Linkage,
1786 comptime _: []const u8,
1787 _: std.fmt.FormatOptions,
1788 writer: anytype,
1789 ) @TypeOf(writer).Error!void {
1790 if (self != .external) try writer.print(" {s}", .{@tagName(self)});
1791 }
1792
1793 fn formatOptional(
1794 data: ?Linkage,
1795 comptime _: []const u8,
1796 _: std.fmt.FormatOptions,
1797 writer: anytype,
1798 ) @TypeOf(writer).Error!void {
1799 if (data) |linkage| try writer.print(" {s}", .{@tagName(linkage)});
1800 }
1801 pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(formatOptional) {
1802 return .{ .data = self };
1803 }
1804};
1805
1806pub const Preemption = enum {
1807 dso_preemptable,
1808 dso_local,
1809 implicit_dso_local,
1810
1811 pub fn format(
1812 self: Preemption,
1813 comptime _: []const u8,
1814 _: std.fmt.FormatOptions,
1815 writer: anytype,
1816 ) @TypeOf(writer).Error!void {
1817 if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)});
1818 }
1819};
1820
1821pub const Visibility = enum(u2) {
1822 default = 0,
1823 hidden = 1,
1824 protected = 2,
1825
1826 pub fn format(
1827 self: Visibility,
1828 comptime _: []const u8,
1829 _: std.fmt.FormatOptions,
1830 writer: anytype,
1831 ) @TypeOf(writer).Error!void {
1832 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1833 }
1834};
1835
1836pub const DllStorageClass = enum(u2) {
1837 default = 0,
1838 dllimport = 1,
1839 dllexport = 2,
1840
1841 pub fn format(
1842 self: DllStorageClass,
1843 comptime _: []const u8,
1844 _: std.fmt.FormatOptions,
1845 writer: anytype,
1846 ) @TypeOf(writer).Error!void {
1847 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1848 }
1849};
1850
1851pub const ThreadLocal = enum(u3) {
1852 default = 0,
1853 generaldynamic = 1,
1854 localdynamic = 2,
1855 initialexec = 3,
1856 localexec = 4,
1857
1858 pub fn format(
1859 self: ThreadLocal,
1860 comptime prefix: []const u8,
1861 _: std.fmt.FormatOptions,
1862 writer: anytype,
1863 ) @TypeOf(writer).Error!void {
1864 if (self == .default) return;
1865 try writer.print("{s}thread_local", .{prefix});
1866 if (self != .generaldynamic) try writer.print("({s})", .{@tagName(self)});
1867 }
1868};
1869
1870pub const Mutability = enum { global, constant };
1871
1872pub const UnnamedAddr = enum(u2) {
1873 default = 0,
1874 unnamed_addr = 1,
1875 local_unnamed_addr = 2,
1876
1877 pub fn format(
1878 self: UnnamedAddr,
1879 comptime _: []const u8,
1880 _: std.fmt.FormatOptions,
1881 writer: anytype,
1882 ) @TypeOf(writer).Error!void {
1883 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1884 }
1885};
1886
1887pub const AddrSpace = enum(u24) {
1888 default,
1889 _,
1890
1891 // See llvm/lib/Target/X86/X86.h
1892 pub const x86 = struct {
1893 pub const gs: AddrSpace = @enumFromInt(256);
1894 pub const fs: AddrSpace = @enumFromInt(257);
1895 pub const ss: AddrSpace = @enumFromInt(258);
1896
1897 pub const ptr32_sptr: AddrSpace = @enumFromInt(270);
1898 pub const ptr32_uptr: AddrSpace = @enumFromInt(271);
1899 pub const ptr64: AddrSpace = @enumFromInt(272);
1900 };
1901 pub const x86_64 = x86;
1902
1903 // See llvm/lib/Target/AVR/AVR.h
1904 pub const avr = struct {
1905 pub const data: AddrSpace = @enumFromInt(0);
1906 pub const program: AddrSpace = @enumFromInt(1);
1907 pub const program1: AddrSpace = @enumFromInt(2);
1908 pub const program2: AddrSpace = @enumFromInt(3);
1909 pub const program3: AddrSpace = @enumFromInt(4);
1910 pub const program4: AddrSpace = @enumFromInt(5);
1911 pub const program5: AddrSpace = @enumFromInt(6);
1912 };
1913
1914 // See llvm/lib/Target/NVPTX/NVPTX.h
1915 pub const nvptx = struct {
1916 pub const generic: AddrSpace = @enumFromInt(0);
1917 pub const global: AddrSpace = @enumFromInt(1);
1918 pub const constant: AddrSpace = @enumFromInt(2);
1919 pub const shared: AddrSpace = @enumFromInt(3);
1920 pub const param: AddrSpace = @enumFromInt(4);
1921 pub const local: AddrSpace = @enumFromInt(5);
1922 };
1923
1924 // See llvm/lib/Target/AMDGPU/AMDGPU.h
1925 pub const amdgpu = struct {
1926 pub const flat: AddrSpace = @enumFromInt(0);
1927 pub const global: AddrSpace = @enumFromInt(1);
1928 pub const region: AddrSpace = @enumFromInt(2);
1929 pub const local: AddrSpace = @enumFromInt(3);
1930 pub const constant: AddrSpace = @enumFromInt(4);
1931 pub const private: AddrSpace = @enumFromInt(5);
1932 pub const constant_32bit: AddrSpace = @enumFromInt(6);
1933 pub const buffer_fat_pointer: AddrSpace = @enumFromInt(7);
1934 pub const buffer_resource: AddrSpace = @enumFromInt(8);
1935 pub const buffer_strided_pointer: AddrSpace = @enumFromInt(9);
1936 pub const param_d: AddrSpace = @enumFromInt(6);
1937 pub const param_i: AddrSpace = @enumFromInt(7);
1938 pub const constant_buffer_0: AddrSpace = @enumFromInt(8);
1939 pub const constant_buffer_1: AddrSpace = @enumFromInt(9);
1940 pub const constant_buffer_2: AddrSpace = @enumFromInt(10);
1941 pub const constant_buffer_3: AddrSpace = @enumFromInt(11);
1942 pub const constant_buffer_4: AddrSpace = @enumFromInt(12);
1943 pub const constant_buffer_5: AddrSpace = @enumFromInt(13);
1944 pub const constant_buffer_6: AddrSpace = @enumFromInt(14);
1945 pub const constant_buffer_7: AddrSpace = @enumFromInt(15);
1946 pub const constant_buffer_8: AddrSpace = @enumFromInt(16);
1947 pub const constant_buffer_9: AddrSpace = @enumFromInt(17);
1948 pub const constant_buffer_10: AddrSpace = @enumFromInt(18);
1949 pub const constant_buffer_11: AddrSpace = @enumFromInt(19);
1950 pub const constant_buffer_12: AddrSpace = @enumFromInt(20);
1951 pub const constant_buffer_13: AddrSpace = @enumFromInt(21);
1952 pub const constant_buffer_14: AddrSpace = @enumFromInt(22);
1953 pub const constant_buffer_15: AddrSpace = @enumFromInt(23);
1954 pub const streamout_register: AddrSpace = @enumFromInt(128);
1955 };
1956
1957 pub const spirv = struct {
1958 pub const function: AddrSpace = @enumFromInt(0);
1959 pub const cross_workgroup: AddrSpace = @enumFromInt(1);
1960 pub const uniform_constant: AddrSpace = @enumFromInt(2);
1961 pub const workgroup: AddrSpace = @enumFromInt(3);
1962 pub const generic: AddrSpace = @enumFromInt(4);
1963 pub const device_only_intel: AddrSpace = @enumFromInt(5);
1964 pub const host_only_intel: AddrSpace = @enumFromInt(6);
1965 pub const input: AddrSpace = @enumFromInt(7);
1966 };
1967
1968 // See llvm/include/llvm/CodeGen/WasmAddressSpaces.h
1969 pub const wasm = struct {
1970 pub const default: AddrSpace = @enumFromInt(0);
1971 pub const variable: AddrSpace = @enumFromInt(1);
1972 pub const externref: AddrSpace = @enumFromInt(10);
1973 pub const funcref: AddrSpace = @enumFromInt(20);
1974 };
1975
1976 pub fn format(
1977 self: AddrSpace,
1978 comptime prefix: []const u8,
1979 _: std.fmt.FormatOptions,
1980 writer: anytype,
1981 ) @TypeOf(writer).Error!void {
1982 if (self != .default) try writer.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) });
1983 }
1984};
1985
1986pub const ExternallyInitialized = enum {
1987 default,
1988 externally_initialized,
1989
1990 pub fn format(
1991 self: ExternallyInitialized,
1992 comptime _: []const u8,
1993 _: std.fmt.FormatOptions,
1994 writer: anytype,
1995 ) @TypeOf(writer).Error!void {
1996 if (self == .default) return;
1997 try writer.writeByte(' ');
1998 try writer.writeAll(@tagName(self));
1999 }
2000};
2001
2002pub const Alignment = enum(u6) {
2003 default = std.math.maxInt(u6),
2004 _,
2005
2006 pub fn fromByteUnits(bytes: u64) Alignment {
2007 if (bytes == 0) return .default;
2008 assert(std.math.isPowerOfTwo(bytes));
2009 assert(bytes <= 1 << 32);
2010 return @enumFromInt(@ctz(bytes));
2011 }
2012
2013 pub fn toByteUnits(self: Alignment) ?u64 {
2014 return if (self == .default) null else @as(u64, 1) << @intFromEnum(self);
2015 }
2016
2017 pub fn toLlvm(self: Alignment) u6 {
2018 return if (self == .default) 0 else (@intFromEnum(self) + 1);
2019 }
2020
2021 pub fn format(
2022 self: Alignment,
2023 comptime prefix: []const u8,
2024 _: std.fmt.FormatOptions,
2025 writer: anytype,
2026 ) @TypeOf(writer).Error!void {
2027 try writer.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return });
2028 }
2029};
2030
2031pub const CallConv = enum(u10) {
2032 ccc,
2033
2034 fastcc = 8,
2035 coldcc,
2036 ghccc,
2037
2038 webkit_jscc = 12,
2039 anyregcc,
2040 preserve_mostcc,
2041 preserve_allcc,
2042 swiftcc,
2043 cxx_fast_tlscc,
2044 tailcc,
2045 cfguard_checkcc,
2046 swifttailcc,
2047
2048 x86_stdcallcc = 64,
2049 x86_fastcallcc,
2050 arm_apcscc,
2051 arm_aapcscc,
2052 arm_aapcs_vfpcc,
2053 msp430_intrcc,
2054 x86_thiscallcc,
2055 ptx_kernel,
2056 ptx_device,
2057
2058 spir_func = 75,
2059 spir_kernel,
2060 intel_ocl_bicc,
2061 x86_64_sysvcc,
2062 win64cc,
2063 x86_vectorcallcc,
2064 hhvmcc,
2065 hhvm_ccc,
2066 x86_intrcc,
2067 avr_intrcc,
2068 avr_signalcc,
2069 avr_builtincc,
2070
2071 amdgpu_vs = 87,
2072 amdgpu_gs,
2073 amdgpu_ps,
2074 amdgpu_cs,
2075 amdgpu_kernel,
2076 x86_regcallcc,
2077 amdgpu_hs,
2078 msp430_builtincc,
2079
2080 amdgpu_ls = 95,
2081 amdgpu_es,
2082 aarch64_vector_pcs,
2083 aarch64_sve_vector_pcs,
2084
2085 amdgpu_gfx = 100,
2086
2087 m68k_intrcc,
2088
2089 aarch64_sme_preservemost_from_x0 = 102,
2090 aarch64_sme_preservemost_from_x2,
2091
2092 m68k_rtdcc = 106,
2093
2094 riscv_vectorcallcc = 110,
2095
2096 _,
2097
2098 pub const default = CallConv.ccc;
2099
2100 pub fn format(
2101 self: CallConv,
2102 comptime _: []const u8,
2103 _: std.fmt.FormatOptions,
2104 writer: anytype,
2105 ) @TypeOf(writer).Error!void {
2106 switch (self) {
2107 default => {},
2108 .fastcc,
2109 .coldcc,
2110 .ghccc,
2111 .webkit_jscc,
2112 .anyregcc,
2113 .preserve_mostcc,
2114 .preserve_allcc,
2115 .swiftcc,
2116 .cxx_fast_tlscc,
2117 .tailcc,
2118 .cfguard_checkcc,
2119 .swifttailcc,
2120 .x86_stdcallcc,
2121 .x86_fastcallcc,
2122 .arm_apcscc,
2123 .arm_aapcscc,
2124 .arm_aapcs_vfpcc,
2125 .msp430_intrcc,
2126 .x86_thiscallcc,
2127 .ptx_kernel,
2128 .ptx_device,
2129 .spir_func,
2130 .spir_kernel,
2131 .intel_ocl_bicc,
2132 .x86_64_sysvcc,
2133 .win64cc,
2134 .x86_vectorcallcc,
2135 .hhvmcc,
2136 .hhvm_ccc,
2137 .x86_intrcc,
2138 .avr_intrcc,
2139 .avr_signalcc,
2140 .avr_builtincc,
2141 .amdgpu_vs,
2142 .amdgpu_gs,
2143 .amdgpu_ps,
2144 .amdgpu_cs,
2145 .amdgpu_kernel,
2146 .x86_regcallcc,
2147 .amdgpu_hs,
2148 .msp430_builtincc,
2149 .amdgpu_ls,
2150 .amdgpu_es,
2151 .aarch64_vector_pcs,
2152 .aarch64_sve_vector_pcs,
2153 .amdgpu_gfx,
2154 .m68k_intrcc,
2155 .aarch64_sme_preservemost_from_x0,
2156 .aarch64_sme_preservemost_from_x2,
2157 .m68k_rtdcc,
2158 .riscv_vectorcallcc,
2159 => try writer.print(" {s}", .{@tagName(self)}),
2160 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
2161 }
2162 }
2163};
2164
2165pub const StrtabString = enum(u32) {
2166 none = std.math.maxInt(u31),
2167 empty,
2168 _,
2169
2170 pub fn isAnon(self: StrtabString) bool {
2171 assert(self != .none);
2172 return self.toIndex() == null;
2173 }
2174
2175 pub fn slice(self: StrtabString, builder: *const Builder) ?[]const u8 {
2176 const index = self.toIndex() orelse return null;
2177 const start = builder.strtab_string_indices.items[index];
2178 const end = builder.strtab_string_indices.items[index + 1];
2179 return builder.strtab_string_bytes.items[start..end];
2180 }
2181
2182 const FormatData = struct {
2183 string: StrtabString,
2184 builder: *const Builder,
2185 };
2186 fn format(
2187 data: FormatData,
2188 comptime fmt_str: []const u8,
2189 _: std.fmt.FormatOptions,
2190 writer: anytype,
2191 ) @TypeOf(writer).Error!void {
2192 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_|
2193 @compileError("invalid format string: '" ++ fmt_str ++ "'");
2194 assert(data.string != .none);
2195 const string_slice = data.string.slice(data.builder) orelse
2196 return writer.print("{d}", .{@intFromEnum(data.string)});
2197 if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_|
2198 return writer.writeAll(string_slice);
2199 try printEscapedString(
2200 string_slice,
2201 if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
2202 .always_quote
2203 else
2204 .quote_unless_valid_identifier,
2205 writer,
2206 );
2207 }
2208 pub fn fmt(self: StrtabString, builder: *const Builder) std.fmt.Formatter(format) {
2209 return .{ .data = .{ .string = self, .builder = builder } };
2210 }
2211
2212 fn fromIndex(index: ?usize) StrtabString {
2213 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
2214 @intFromEnum(StrtabString.empty))));
2215 }
2216
2217 fn toIndex(self: StrtabString) ?usize {
2218 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(StrtabString.empty)) catch null;
2219 }
2220
2221 const Adapter = struct {
2222 builder: *const Builder,
2223 pub fn hash(_: Adapter, key: []const u8) u32 {
2224 return @truncate(std.hash.Wyhash.hash(0, key));
2225 }
2226 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
2227 return std.mem.eql(u8, lhs_key, StrtabString.fromIndex(rhs_index).slice(ctx.builder).?);
2228 }
2229 };
2230};
2231
2232pub fn strtabString(self: *Builder, bytes: []const u8) Allocator.Error!StrtabString {
2233 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, bytes.len);
2234 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
2235 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
2236
2237 const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self });
2238 if (!gop.found_existing) {
2239 self.strtab_string_bytes.appendSliceAssumeCapacity(bytes);
2240 self.strtab_string_indices.appendAssumeCapacity(@intCast(self.strtab_string_bytes.items.len));
2241 }
2242 return StrtabString.fromIndex(gop.index);
2243}
2244
2245pub fn strtabStringIfExists(self: *const Builder, bytes: []const u8) ?StrtabString {
2246 return StrtabString.fromIndex(
2247 self.strtab_string_map.getIndexAdapted(bytes, StrtabString.Adapter{ .builder = self }) orelse return null,
2248 );
2249}
2250
2251pub fn strtabStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allocator.Error!StrtabString {
2252 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
2253 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, @intCast(std.fmt.count(fmt_str, fmt_args)));
2254 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
2255 return self.strtabStringFmtAssumeCapacity(fmt_str, fmt_args);
2256}
2257
2258pub fn strtabStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) StrtabString {
2259 self.strtab_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
2260 return self.trailingStrtabStringAssumeCapacity();
2261}
2262
2263pub fn trailingStrtabString(self: *Builder) Allocator.Error!StrtabString {
2264 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
2265 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
2266 return self.trailingStrtabStringAssumeCapacity();
2267}
2268
2269pub fn trailingStrtabStringAssumeCapacity(self: *Builder) StrtabString {
2270 const start = self.strtab_string_indices.getLast();
2271 const bytes: []const u8 = self.strtab_string_bytes.items[start..];
2272 const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self });
2273 if (gop.found_existing) {
2274 self.strtab_string_bytes.shrinkRetainingCapacity(start);
2275 } else {
2276 self.strtab_string_indices.appendAssumeCapacity(@intCast(self.strtab_string_bytes.items.len));
2277 }
2278 return StrtabString.fromIndex(gop.index);
2279}
2280
2281pub const Global = struct {
2282 linkage: Linkage = .external,
2283 preemption: Preemption = .dso_preemptable,
2284 visibility: Visibility = .default,
2285 dll_storage_class: DllStorageClass = .default,
2286 unnamed_addr: UnnamedAddr = .default,
2287 addr_space: AddrSpace = .default,
2288 externally_initialized: ExternallyInitialized = .default,
2289 type: Type,
2290 partition: String = .none,
2291 dbg: Metadata = .none,
2292 kind: union(enum) {
2293 alias: Alias.Index,
2294 variable: Variable.Index,
2295 function: Function.Index,
2296 replaced: Global.Index,
2297 },
2298
2299 pub const Index = enum(u32) {
2300 none = std.math.maxInt(u32),
2301 _,
2302
2303 pub fn unwrap(self: Index, builder: *const Builder) Index {
2304 var cur = self;
2305 while (true) {
2306 const replacement = cur.getReplacement(builder);
2307 if (replacement == .none) return cur;
2308 cur = replacement;
2309 }
2310 }
2311
2312 pub fn eql(self: Index, other: Index, builder: *const Builder) bool {
2313 return self.unwrap(builder) == other.unwrap(builder);
2314 }
2315
2316 pub fn ptr(self: Index, builder: *Builder) *Global {
2317 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
2318 }
2319
2320 pub fn ptrConst(self: Index, builder: *const Builder) *const Global {
2321 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
2322 }
2323
2324 pub fn name(self: Index, builder: *const Builder) StrtabString {
2325 return builder.globals.keys()[@intFromEnum(self.unwrap(builder))];
2326 }
2327
2328 pub fn strtab(self: Index, builder: *const Builder) struct {
2329 offset: u32,
2330 size: u32,
2331 } {
2332 const name_index = self.name(builder).toIndex() orelse return .{
2333 .offset = 0,
2334 .size = 0,
2335 };
2336
2337 return .{
2338 .offset = builder.strtab_string_indices.items[name_index],
2339 .size = builder.strtab_string_indices.items[name_index + 1] -
2340 builder.strtab_string_indices.items[name_index],
2341 };
2342 }
2343
2344 pub fn typeOf(self: Index, builder: *const Builder) Type {
2345 return self.ptrConst(builder).type;
2346 }
2347
2348 pub fn toConst(self: Index) Constant {
2349 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
2350 }
2351
2352 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
2353 self.ptr(builder).linkage = linkage;
2354 self.updateDsoLocal(builder);
2355 }
2356
2357 pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
2358 self.ptr(builder).visibility = visibility;
2359 self.updateDsoLocal(builder);
2360 }
2361
2362 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2363 self.ptr(builder).dll_storage_class = class;
2364 }
2365
2366 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
2367 self.ptr(builder).unnamed_addr = unnamed_addr;
2368 }
2369
2370 pub fn setDebugMetadata(self: Index, dbg: Metadata, builder: *Builder) void {
2371 self.ptr(builder).dbg = dbg;
2372 }
2373
2374 const FormatData = struct {
2375 global: Index,
2376 builder: *const Builder,
2377 };
2378 fn format(
2379 data: FormatData,
2380 comptime _: []const u8,
2381 _: std.fmt.FormatOptions,
2382 writer: anytype,
2383 ) @TypeOf(writer).Error!void {
2384 try writer.print("@{}", .{
2385 data.global.unwrap(data.builder).name(data.builder).fmt(data.builder),
2386 });
2387 }
2388 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
2389 return .{ .data = .{ .global = self, .builder = builder } };
2390 }
2391
2392 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
2393 try builder.ensureUnusedGlobalCapacity(new_name);
2394 self.renameAssumeCapacity(new_name, builder);
2395 }
2396
2397 pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
2398 try builder.ensureUnusedGlobalCapacity(.empty);
2399 self.takeNameAssumeCapacity(other, builder);
2400 }
2401
2402 pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
2403 try builder.ensureUnusedGlobalCapacity(.empty);
2404 self.replaceAssumeCapacity(other, builder);
2405 }
2406
2407 pub fn delete(self: Index, builder: *Builder) void {
2408 self.ptr(builder).kind = .{ .replaced = .none };
2409 }
2410
2411 fn updateDsoLocal(self: Index, builder: *Builder) void {
2412 const self_ptr = self.ptr(builder);
2413 switch (self_ptr.linkage) {
2414 .private, .internal => {
2415 self_ptr.visibility = .default;
2416 self_ptr.dll_storage_class = .default;
2417 self_ptr.preemption = .implicit_dso_local;
2418 },
2419 .extern_weak => if (self_ptr.preemption == .implicit_dso_local) {
2420 self_ptr.preemption = .dso_local;
2421 },
2422 else => switch (self_ptr.visibility) {
2423 .default => if (self_ptr.preemption == .implicit_dso_local) {
2424 self_ptr.preemption = .dso_local;
2425 },
2426 else => self_ptr.preemption = .implicit_dso_local,
2427 },
2428 }
2429 }
2430
2431 fn renameAssumeCapacity(self: Index, new_name: StrtabString, builder: *Builder) void {
2432 const old_name = self.name(builder);
2433 if (new_name == old_name) return;
2434 const index = @intFromEnum(self.unwrap(builder));
2435 _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]);
2436 builder.globals.swapRemoveAt(index);
2437 if (!old_name.isAnon()) return;
2438 builder.next_unnamed_global = @enumFromInt(@intFromEnum(builder.next_unnamed_global) - 1);
2439 if (builder.next_unnamed_global == old_name) return;
2440 builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder);
2441 }
2442
2443 fn takeNameAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
2444 const other_name = other.name(builder);
2445 other.renameAssumeCapacity(.empty, builder);
2446 self.renameAssumeCapacity(other_name, builder);
2447 }
2448
2449 fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
2450 if (self.eql(other, builder)) return;
2451 builder.next_replaced_global = @enumFromInt(@intFromEnum(builder.next_replaced_global) - 1);
2452 self.renameAssumeCapacity(builder.next_replaced_global, builder);
2453 self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
2454 }
2455
2456 fn getReplacement(self: Index, builder: *const Builder) Index {
2457 return switch (builder.globals.values()[@intFromEnum(self)].kind) {
2458 .replaced => |replacement| replacement,
2459 else => .none,
2460 };
2461 }
2462 };
2463};
2464
2465pub const Alias = struct {
2466 global: Global.Index,
2467 thread_local: ThreadLocal = .default,
2468 aliasee: Constant = .no_init,
2469
2470 pub const Index = enum(u32) {
2471 none = std.math.maxInt(u32),
2472 _,
2473
2474 pub fn ptr(self: Index, builder: *Builder) *Alias {
2475 return &builder.aliases.items[@intFromEnum(self)];
2476 }
2477
2478 pub fn ptrConst(self: Index, builder: *const Builder) *const Alias {
2479 return &builder.aliases.items[@intFromEnum(self)];
2480 }
2481
2482 pub fn name(self: Index, builder: *const Builder) StrtabString {
2483 return self.ptrConst(builder).global.name(builder);
2484 }
2485
2486 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
2487 return self.ptrConst(builder).global.rename(new_name, builder);
2488 }
2489
2490 pub fn typeOf(self: Index, builder: *const Builder) Type {
2491 return self.ptrConst(builder).global.typeOf(builder);
2492 }
2493
2494 pub fn toConst(self: Index, builder: *const Builder) Constant {
2495 return self.ptrConst(builder).global.toConst();
2496 }
2497
2498 pub fn toValue(self: Index, builder: *const Builder) Value {
2499 return self.toConst(builder).toValue();
2500 }
2501
2502 pub fn getAliasee(self: Index, builder: *const Builder) Global.Index {
2503 const aliasee = self.ptrConst(builder).aliasee.getBase(builder);
2504 assert(aliasee != .none);
2505 return aliasee;
2506 }
2507
2508 pub fn setAliasee(self: Index, aliasee: Constant, builder: *Builder) void {
2509 self.ptr(builder).aliasee = aliasee;
2510 }
2511 };
2512};
2513
2514pub const Variable = struct {
2515 global: Global.Index,
2516 thread_local: ThreadLocal = .default,
2517 mutability: Mutability = .global,
2518 init: Constant = .no_init,
2519 section: String = .none,
2520 alignment: Alignment = .default,
2521
2522 pub const Index = enum(u32) {
2523 none = std.math.maxInt(u32),
2524 _,
2525
2526 pub fn ptr(self: Index, builder: *Builder) *Variable {
2527 return &builder.variables.items[@intFromEnum(self)];
2528 }
2529
2530 pub fn ptrConst(self: Index, builder: *const Builder) *const Variable {
2531 return &builder.variables.items[@intFromEnum(self)];
2532 }
2533
2534 pub fn name(self: Index, builder: *const Builder) StrtabString {
2535 return self.ptrConst(builder).global.name(builder);
2536 }
2537
2538 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
2539 return self.ptrConst(builder).global.rename(new_name, builder);
2540 }
2541
2542 pub fn typeOf(self: Index, builder: *const Builder) Type {
2543 return self.ptrConst(builder).global.typeOf(builder);
2544 }
2545
2546 pub fn toConst(self: Index, builder: *const Builder) Constant {
2547 return self.ptrConst(builder).global.toConst();
2548 }
2549
2550 pub fn toValue(self: Index, builder: *const Builder) Value {
2551 return self.toConst(builder).toValue();
2552 }
2553
2554 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
2555 return self.ptrConst(builder).global.setLinkage(linkage, builder);
2556 }
2557
2558 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2559 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
2560 }
2561
2562 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
2563 return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
2564 }
2565
2566 pub fn setThreadLocal(self: Index, thread_local: ThreadLocal, builder: *Builder) void {
2567 self.ptr(builder).thread_local = thread_local;
2568 }
2569
2570 pub fn setMutability(self: Index, mutability: Mutability, builder: *Builder) void {
2571 self.ptr(builder).mutability = mutability;
2572 }
2573
2574 pub fn setInitializer(
2575 self: Index,
2576 initializer: Constant,
2577 builder: *Builder,
2578 ) Allocator.Error!void {
2579 if (initializer != .no_init) {
2580 const variable = self.ptrConst(builder);
2581 const global = variable.global.ptr(builder);
2582 const initializer_type = initializer.typeOf(builder);
2583 global.type = initializer_type;
2584 }
2585 self.ptr(builder).init = initializer;
2586 }
2587
2588 pub fn setSection(self: Index, section: String, builder: *Builder) void {
2589 self.ptr(builder).section = section;
2590 }
2591
2592 pub fn setAlignment(self: Index, alignment: Alignment, builder: *Builder) void {
2593 self.ptr(builder).alignment = alignment;
2594 }
2595
2596 pub fn getAlignment(self: Index, builder: *Builder) Alignment {
2597 return self.ptr(builder).alignment;
2598 }
2599
2600 pub fn setGlobalVariableExpression(self: Index, expression: Metadata, builder: *Builder) void {
2601 self.ptrConst(builder).global.setDebugMetadata(expression, builder);
2602 }
2603 };
2604};
2605
2606pub const Intrinsic = enum {
2607 // Variable Argument Handling
2608 va_start,
2609 va_end,
2610 va_copy,
2611
2612 // Code Generator
2613 returnaddress,
2614 addressofreturnaddress,
2615 sponentry,
2616 frameaddress,
2617 prefetch,
2618 @"thread.pointer",
2619
2620 // Standard C/C++ Library
2621 abs,
2622 smax,
2623 smin,
2624 umax,
2625 umin,
2626 memcpy,
2627 @"memcpy.inline",
2628 memmove,
2629 memset,
2630 @"memset.inline",
2631 sqrt,
2632 powi,
2633 sin,
2634 cos,
2635 pow,
2636 exp,
2637 exp10,
2638 exp2,
2639 ldexp,
2640 frexp,
2641 log,
2642 log10,
2643 log2,
2644 fma,
2645 fabs,
2646 minnum,
2647 maxnum,
2648 minimum,
2649 maximum,
2650 copysign,
2651 floor,
2652 ceil,
2653 trunc,
2654 rint,
2655 nearbyint,
2656 round,
2657 roundeven,
2658 lround,
2659 llround,
2660 lrint,
2661 llrint,
2662
2663 // Bit Manipulation
2664 bitreverse,
2665 bswap,
2666 ctpop,
2667 ctlz,
2668 cttz,
2669 fshl,
2670 fshr,
2671
2672 // Arithmetic with Overflow
2673 @"sadd.with.overflow",
2674 @"uadd.with.overflow",
2675 @"ssub.with.overflow",
2676 @"usub.with.overflow",
2677 @"smul.with.overflow",
2678 @"umul.with.overflow",
2679
2680 // Saturation Arithmetic
2681 @"sadd.sat",
2682 @"uadd.sat",
2683 @"ssub.sat",
2684 @"usub.sat",
2685 @"sshl.sat",
2686 @"ushl.sat",
2687
2688 // Fixed Point Arithmetic
2689 @"smul.fix",
2690 @"umul.fix",
2691 @"smul.fix.sat",
2692 @"umul.fix.sat",
2693 @"sdiv.fix",
2694 @"udiv.fix",
2695 @"sdiv.fix.sat",
2696 @"udiv.fix.sat",
2697
2698 // Specialised Arithmetic
2699 canonicalize,
2700 fmuladd,
2701
2702 // Vector Reduction
2703 @"vector.reduce.add",
2704 @"vector.reduce.fadd",
2705 @"vector.reduce.mul",
2706 @"vector.reduce.fmul",
2707 @"vector.reduce.and",
2708 @"vector.reduce.or",
2709 @"vector.reduce.xor",
2710 @"vector.reduce.smax",
2711 @"vector.reduce.smin",
2712 @"vector.reduce.umax",
2713 @"vector.reduce.umin",
2714 @"vector.reduce.fmax",
2715 @"vector.reduce.fmin",
2716 @"vector.reduce.fmaximum",
2717 @"vector.reduce.fminimum",
2718 @"vector.insert",
2719 @"vector.extract",
2720
2721 // Floating-Point Test
2722 @"is.fpclass",
2723
2724 // General
2725 @"var.annotation",
2726 @"ptr.annotation",
2727 annotation,
2728 @"codeview.annotation",
2729 trap,
2730 debugtrap,
2731 ubsantrap,
2732 stackprotector,
2733 stackguard,
2734 objectsize,
2735 expect,
2736 @"expect.with.probability",
2737 assume,
2738 @"ssa.copy",
2739 @"type.test",
2740 @"type.checked.load",
2741 @"type.checked.load.relative",
2742 @"arithmetic.fence",
2743 donothing,
2744 @"load.relative",
2745 sideeffect,
2746 @"is.constant",
2747 ptrmask,
2748 @"threadlocal.address",
2749 vscale,
2750
2751 // Debug
2752 @"dbg.declare",
2753 @"dbg.value",
2754
2755 // AMDGPU
2756 @"amdgcn.workitem.id.x",
2757 @"amdgcn.workitem.id.y",
2758 @"amdgcn.workitem.id.z",
2759 @"amdgcn.workgroup.id.x",
2760 @"amdgcn.workgroup.id.y",
2761 @"amdgcn.workgroup.id.z",
2762 @"amdgcn.dispatch.ptr",
2763
2764 // NVPTX
2765 @"nvvm.read.ptx.sreg.tid.x",
2766 @"nvvm.read.ptx.sreg.tid.y",
2767 @"nvvm.read.ptx.sreg.tid.z",
2768 @"nvvm.read.ptx.sreg.ntid.x",
2769 @"nvvm.read.ptx.sreg.ntid.y",
2770 @"nvvm.read.ptx.sreg.ntid.z",
2771 @"nvvm.read.ptx.sreg.ctaid.x",
2772 @"nvvm.read.ptx.sreg.ctaid.y",
2773 @"nvvm.read.ptx.sreg.ctaid.z",
2774
2775 // WebAssembly
2776 @"wasm.memory.size",
2777 @"wasm.memory.grow",
2778
2779 const Signature = struct {
2780 ret_len: u8,
2781 params: []const Parameter,
2782 attrs: []const Attribute = &.{},
2783
2784 const Parameter = struct {
2785 kind: Kind,
2786 attrs: []const Attribute = &.{},
2787
2788 const Kind = union(enum) {
2789 type: Type,
2790 overloaded,
2791 matches: u8,
2792 matches_scalar: u8,
2793 matches_changed_scalar: struct {
2794 index: u8,
2795 scalar: Type,
2796 },
2797 };
2798 };
2799 };
2800
2801 const signatures = std.enums.EnumArray(Intrinsic, Signature).init(.{
2802 .va_start = .{
2803 .ret_len = 0,
2804 .params = &.{
2805 .{ .kind = .overloaded },
2806 },
2807 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2808 },
2809 .va_end = .{
2810 .ret_len = 0,
2811 .params = &.{
2812 .{ .kind = .overloaded },
2813 },
2814 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2815 },
2816 .va_copy = .{
2817 .ret_len = 0,
2818 .params = &.{
2819 .{ .kind = .overloaded },
2820 .{ .kind = .{ .matches = 0 } },
2821 },
2822 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2823 },
2824
2825 .returnaddress = .{
2826 .ret_len = 1,
2827 .params = &.{
2828 .{ .kind = .{ .type = .ptr } },
2829 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2830 },
2831 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2832 },
2833 .addressofreturnaddress = .{
2834 .ret_len = 1,
2835 .params = &.{
2836 .{ .kind = .overloaded },
2837 },
2838 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2839 },
2840 .sponentry = .{
2841 .ret_len = 1,
2842 .params = &.{
2843 .{ .kind = .overloaded },
2844 },
2845 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2846 },
2847 .frameaddress = .{
2848 .ret_len = 1,
2849 .params = &.{
2850 .{ .kind = .overloaded },
2851 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2852 },
2853 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2854 },
2855 .prefetch = .{
2856 .ret_len = 0,
2857 .params = &.{
2858 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .readonly } },
2859 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2860 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2861 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
2862 },
2863 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.readwrite) } },
2864 },
2865 .@"thread.pointer" = .{
2866 .ret_len = 1,
2867 .params = &.{
2868 .{ .kind = .{ .type = .ptr } },
2869 },
2870 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2871 },
2872
2873 .abs = .{
2874 .ret_len = 1,
2875 .params = &.{
2876 .{ .kind = .overloaded },
2877 .{ .kind = .{ .matches = 0 } },
2878 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2879 },
2880 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2881 },
2882 .smax = .{
2883 .ret_len = 1,
2884 .params = &.{
2885 .{ .kind = .overloaded },
2886 .{ .kind = .{ .matches = 0 } },
2887 .{ .kind = .{ .matches = 0 } },
2888 },
2889 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2890 },
2891 .smin = .{
2892 .ret_len = 1,
2893 .params = &.{
2894 .{ .kind = .overloaded },
2895 .{ .kind = .{ .matches = 0 } },
2896 .{ .kind = .{ .matches = 0 } },
2897 },
2898 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2899 },
2900 .umax = .{
2901 .ret_len = 1,
2902 .params = &.{
2903 .{ .kind = .overloaded },
2904 .{ .kind = .{ .matches = 0 } },
2905 .{ .kind = .{ .matches = 0 } },
2906 },
2907 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2908 },
2909 .umin = .{
2910 .ret_len = 1,
2911 .params = &.{
2912 .{ .kind = .overloaded },
2913 .{ .kind = .{ .matches = 0 } },
2914 .{ .kind = .{ .matches = 0 } },
2915 },
2916 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2917 },
2918 .memcpy = .{
2919 .ret_len = 0,
2920 .params = &.{
2921 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
2922 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
2923 .{ .kind = .overloaded },
2924 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2925 },
2926 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
2927 },
2928 .@"memcpy.inline" = .{
2929 .ret_len = 0,
2930 .params = &.{
2931 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
2932 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
2933 .{ .kind = .overloaded },
2934 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2935 },
2936 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
2937 },
2938 .memmove = .{
2939 .ret_len = 0,
2940 .params = &.{
2941 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
2942 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .readonly } },
2943 .{ .kind = .overloaded },
2944 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2945 },
2946 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
2947 },
2948 .memset = .{
2949 .ret_len = 0,
2950 .params = &.{
2951 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
2952 .{ .kind = .{ .type = .i8 } },
2953 .{ .kind = .overloaded },
2954 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2955 },
2956 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
2957 },
2958 .@"memset.inline" = .{
2959 .ret_len = 0,
2960 .params = &.{
2961 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
2962 .{ .kind = .{ .type = .i8 } },
2963 .{ .kind = .overloaded },
2964 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2965 },
2966 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
2967 },
2968 .sqrt = .{
2969 .ret_len = 1,
2970 .params = &.{
2971 .{ .kind = .overloaded },
2972 .{ .kind = .{ .matches = 0 } },
2973 },
2974 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2975 },
2976 .powi = .{
2977 .ret_len = 1,
2978 .params = &.{
2979 .{ .kind = .overloaded },
2980 .{ .kind = .{ .matches = 0 } },
2981 .{ .kind = .overloaded },
2982 },
2983 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2984 },
2985 .sin = .{
2986 .ret_len = 1,
2987 .params = &.{
2988 .{ .kind = .overloaded },
2989 .{ .kind = .{ .matches = 0 } },
2990 },
2991 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
2992 },
2993 .cos = .{
2994 .ret_len = 1,
2995 .params = &.{
2996 .{ .kind = .overloaded },
2997 .{ .kind = .{ .matches = 0 } },
2998 },
2999 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3000 },
3001 .pow = .{
3002 .ret_len = 1,
3003 .params = &.{
3004 .{ .kind = .overloaded },
3005 .{ .kind = .{ .matches = 0 } },
3006 .{ .kind = .{ .matches = 0 } },
3007 },
3008 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3009 },
3010 .exp = .{
3011 .ret_len = 1,
3012 .params = &.{
3013 .{ .kind = .overloaded },
3014 .{ .kind = .{ .matches = 0 } },
3015 },
3016 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3017 },
3018 .exp2 = .{
3019 .ret_len = 1,
3020 .params = &.{
3021 .{ .kind = .overloaded },
3022 .{ .kind = .{ .matches = 0 } },
3023 },
3024 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3025 },
3026 .exp10 = .{
3027 .ret_len = 1,
3028 .params = &.{
3029 .{ .kind = .overloaded },
3030 .{ .kind = .{ .matches = 0 } },
3031 },
3032 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3033 },
3034 .ldexp = .{
3035 .ret_len = 1,
3036 .params = &.{
3037 .{ .kind = .overloaded },
3038 .{ .kind = .{ .matches = 0 } },
3039 .{ .kind = .overloaded },
3040 },
3041 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3042 },
3043 .frexp = .{
3044 .ret_len = 2,
3045 .params = &.{
3046 .{ .kind = .overloaded },
3047 .{ .kind = .overloaded },
3048 .{ .kind = .{ .matches = 0 } },
3049 },
3050 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3051 },
3052 .log = .{
3053 .ret_len = 1,
3054 .params = &.{
3055 .{ .kind = .overloaded },
3056 .{ .kind = .{ .matches = 0 } },
3057 },
3058 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3059 },
3060 .log10 = .{
3061 .ret_len = 1,
3062 .params = &.{
3063 .{ .kind = .overloaded },
3064 .{ .kind = .{ .matches = 0 } },
3065 },
3066 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3067 },
3068 .log2 = .{
3069 .ret_len = 1,
3070 .params = &.{
3071 .{ .kind = .overloaded },
3072 .{ .kind = .{ .matches = 0 } },
3073 },
3074 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3075 },
3076 .fma = .{
3077 .ret_len = 1,
3078 .params = &.{
3079 .{ .kind = .overloaded },
3080 .{ .kind = .{ .matches = 0 } },
3081 .{ .kind = .{ .matches = 0 } },
3082 .{ .kind = .{ .matches = 0 } },
3083 },
3084 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3085 },
3086 .fabs = .{
3087 .ret_len = 1,
3088 .params = &.{
3089 .{ .kind = .overloaded },
3090 .{ .kind = .{ .matches = 0 } },
3091 },
3092 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3093 },
3094 .minnum = .{
3095 .ret_len = 1,
3096 .params = &.{
3097 .{ .kind = .overloaded },
3098 .{ .kind = .{ .matches = 0 } },
3099 .{ .kind = .{ .matches = 0 } },
3100 },
3101 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3102 },
3103 .maxnum = .{
3104 .ret_len = 1,
3105 .params = &.{
3106 .{ .kind = .overloaded },
3107 .{ .kind = .{ .matches = 0 } },
3108 .{ .kind = .{ .matches = 0 } },
3109 },
3110 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3111 },
3112 .minimum = .{
3113 .ret_len = 1,
3114 .params = &.{
3115 .{ .kind = .overloaded },
3116 .{ .kind = .{ .matches = 0 } },
3117 .{ .kind = .{ .matches = 0 } },
3118 },
3119 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3120 },
3121 .maximum = .{
3122 .ret_len = 1,
3123 .params = &.{
3124 .{ .kind = .overloaded },
3125 .{ .kind = .{ .matches = 0 } },
3126 .{ .kind = .{ .matches = 0 } },
3127 },
3128 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3129 },
3130 .copysign = .{
3131 .ret_len = 1,
3132 .params = &.{
3133 .{ .kind = .overloaded },
3134 .{ .kind = .{ .matches = 0 } },
3135 .{ .kind = .{ .matches = 0 } },
3136 },
3137 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3138 },
3139 .floor = .{
3140 .ret_len = 1,
3141 .params = &.{
3142 .{ .kind = .overloaded },
3143 .{ .kind = .{ .matches = 0 } },
3144 },
3145 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3146 },
3147 .ceil = .{
3148 .ret_len = 1,
3149 .params = &.{
3150 .{ .kind = .overloaded },
3151 .{ .kind = .{ .matches = 0 } },
3152 },
3153 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3154 },
3155 .trunc = .{
3156 .ret_len = 1,
3157 .params = &.{
3158 .{ .kind = .overloaded },
3159 .{ .kind = .{ .matches = 0 } },
3160 },
3161 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3162 },
3163 .rint = .{
3164 .ret_len = 1,
3165 .params = &.{
3166 .{ .kind = .overloaded },
3167 .{ .kind = .{ .matches = 0 } },
3168 },
3169 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3170 },
3171 .nearbyint = .{
3172 .ret_len = 1,
3173 .params = &.{
3174 .{ .kind = .overloaded },
3175 .{ .kind = .{ .matches = 0 } },
3176 },
3177 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3178 },
3179 .round = .{
3180 .ret_len = 1,
3181 .params = &.{
3182 .{ .kind = .overloaded },
3183 .{ .kind = .{ .matches = 0 } },
3184 },
3185 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3186 },
3187 .roundeven = .{
3188 .ret_len = 1,
3189 .params = &.{
3190 .{ .kind = .overloaded },
3191 .{ .kind = .{ .matches = 0 } },
3192 },
3193 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3194 },
3195 .lround = .{
3196 .ret_len = 1,
3197 .params = &.{
3198 .{ .kind = .overloaded },
3199 .{ .kind = .overloaded },
3200 },
3201 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3202 },
3203 .llround = .{
3204 .ret_len = 1,
3205 .params = &.{
3206 .{ .kind = .overloaded },
3207 .{ .kind = .overloaded },
3208 },
3209 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3210 },
3211 .lrint = .{
3212 .ret_len = 1,
3213 .params = &.{
3214 .{ .kind = .overloaded },
3215 .{ .kind = .overloaded },
3216 },
3217 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3218 },
3219 .llrint = .{
3220 .ret_len = 1,
3221 .params = &.{
3222 .{ .kind = .overloaded },
3223 .{ .kind = .overloaded },
3224 },
3225 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3226 },
3227
3228 .bitreverse = .{
3229 .ret_len = 1,
3230 .params = &.{
3231 .{ .kind = .overloaded },
3232 .{ .kind = .{ .matches = 0 } },
3233 },
3234 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3235 },
3236 .bswap = .{
3237 .ret_len = 1,
3238 .params = &.{
3239 .{ .kind = .overloaded },
3240 .{ .kind = .{ .matches = 0 } },
3241 },
3242 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3243 },
3244 .ctpop = .{
3245 .ret_len = 1,
3246 .params = &.{
3247 .{ .kind = .overloaded },
3248 .{ .kind = .{ .matches = 0 } },
3249 },
3250 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3251 },
3252 .ctlz = .{
3253 .ret_len = 1,
3254 .params = &.{
3255 .{ .kind = .overloaded },
3256 .{ .kind = .{ .matches = 0 } },
3257 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3258 },
3259 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3260 },
3261 .cttz = .{
3262 .ret_len = 1,
3263 .params = &.{
3264 .{ .kind = .overloaded },
3265 .{ .kind = .{ .matches = 0 } },
3266 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3267 },
3268 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3269 },
3270 .fshl = .{
3271 .ret_len = 1,
3272 .params = &.{
3273 .{ .kind = .overloaded },
3274 .{ .kind = .{ .matches = 0 } },
3275 .{ .kind = .{ .matches = 0 } },
3276 .{ .kind = .{ .matches = 0 } },
3277 },
3278 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3279 },
3280 .fshr = .{
3281 .ret_len = 1,
3282 .params = &.{
3283 .{ .kind = .overloaded },
3284 .{ .kind = .{ .matches = 0 } },
3285 .{ .kind = .{ .matches = 0 } },
3286 .{ .kind = .{ .matches = 0 } },
3287 },
3288 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3289 },
3290
3291 .@"sadd.with.overflow" = .{
3292 .ret_len = 2,
3293 .params = &.{
3294 .{ .kind = .overloaded },
3295 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3296 .{ .kind = .{ .matches = 0 } },
3297 .{ .kind = .{ .matches = 0 } },
3298 },
3299 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3300 },
3301 .@"uadd.with.overflow" = .{
3302 .ret_len = 2,
3303 .params = &.{
3304 .{ .kind = .overloaded },
3305 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3306 .{ .kind = .{ .matches = 0 } },
3307 .{ .kind = .{ .matches = 0 } },
3308 },
3309 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3310 },
3311 .@"ssub.with.overflow" = .{
3312 .ret_len = 2,
3313 .params = &.{
3314 .{ .kind = .overloaded },
3315 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3316 .{ .kind = .{ .matches = 0 } },
3317 .{ .kind = .{ .matches = 0 } },
3318 },
3319 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3320 },
3321 .@"usub.with.overflow" = .{
3322 .ret_len = 2,
3323 .params = &.{
3324 .{ .kind = .overloaded },
3325 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3326 .{ .kind = .{ .matches = 0 } },
3327 .{ .kind = .{ .matches = 0 } },
3328 },
3329 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3330 },
3331 .@"smul.with.overflow" = .{
3332 .ret_len = 2,
3333 .params = &.{
3334 .{ .kind = .overloaded },
3335 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3336 .{ .kind = .{ .matches = 0 } },
3337 .{ .kind = .{ .matches = 0 } },
3338 },
3339 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3340 },
3341 .@"umul.with.overflow" = .{
3342 .ret_len = 2,
3343 .params = &.{
3344 .{ .kind = .overloaded },
3345 .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
3346 .{ .kind = .{ .matches = 0 } },
3347 .{ .kind = .{ .matches = 0 } },
3348 },
3349 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3350 },
3351
3352 .@"sadd.sat" = .{
3353 .ret_len = 1,
3354 .params = &.{
3355 .{ .kind = .overloaded },
3356 .{ .kind = .{ .matches = 0 } },
3357 .{ .kind = .{ .matches = 0 } },
3358 },
3359 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3360 },
3361 .@"uadd.sat" = .{
3362 .ret_len = 1,
3363 .params = &.{
3364 .{ .kind = .overloaded },
3365 .{ .kind = .{ .matches = 0 } },
3366 .{ .kind = .{ .matches = 0 } },
3367 },
3368 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3369 },
3370 .@"ssub.sat" = .{
3371 .ret_len = 1,
3372 .params = &.{
3373 .{ .kind = .overloaded },
3374 .{ .kind = .{ .matches = 0 } },
3375 .{ .kind = .{ .matches = 0 } },
3376 },
3377 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3378 },
3379 .@"usub.sat" = .{
3380 .ret_len = 1,
3381 .params = &.{
3382 .{ .kind = .overloaded },
3383 .{ .kind = .{ .matches = 0 } },
3384 .{ .kind = .{ .matches = 0 } },
3385 },
3386 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3387 },
3388 .@"sshl.sat" = .{
3389 .ret_len = 1,
3390 .params = &.{
3391 .{ .kind = .overloaded },
3392 .{ .kind = .{ .matches = 0 } },
3393 .{ .kind = .{ .matches = 0 } },
3394 },
3395 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3396 },
3397 .@"ushl.sat" = .{
3398 .ret_len = 1,
3399 .params = &.{
3400 .{ .kind = .overloaded },
3401 .{ .kind = .{ .matches = 0 } },
3402 .{ .kind = .{ .matches = 0 } },
3403 },
3404 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3405 },
3406
3407 .@"smul.fix" = .{
3408 .ret_len = 1,
3409 .params = &.{
3410 .{ .kind = .overloaded },
3411 .{ .kind = .{ .matches = 0 } },
3412 .{ .kind = .{ .matches = 0 } },
3413 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3414 },
3415 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3416 },
3417 .@"umul.fix" = .{
3418 .ret_len = 1,
3419 .params = &.{
3420 .{ .kind = .overloaded },
3421 .{ .kind = .{ .matches = 0 } },
3422 .{ .kind = .{ .matches = 0 } },
3423 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3424 },
3425 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3426 },
3427 .@"smul.fix.sat" = .{
3428 .ret_len = 1,
3429 .params = &.{
3430 .{ .kind = .overloaded },
3431 .{ .kind = .{ .matches = 0 } },
3432 .{ .kind = .{ .matches = 0 } },
3433 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3434 },
3435 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3436 },
3437 .@"umul.fix.sat" = .{
3438 .ret_len = 1,
3439 .params = &.{
3440 .{ .kind = .overloaded },
3441 .{ .kind = .{ .matches = 0 } },
3442 .{ .kind = .{ .matches = 0 } },
3443 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3444 },
3445 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3446 },
3447 .@"sdiv.fix" = .{
3448 .ret_len = 1,
3449 .params = &.{
3450 .{ .kind = .overloaded },
3451 .{ .kind = .{ .matches = 0 } },
3452 .{ .kind = .{ .matches = 0 } },
3453 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3454 },
3455 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3456 },
3457 .@"udiv.fix" = .{
3458 .ret_len = 1,
3459 .params = &.{
3460 .{ .kind = .overloaded },
3461 .{ .kind = .{ .matches = 0 } },
3462 .{ .kind = .{ .matches = 0 } },
3463 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3464 },
3465 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3466 },
3467 .@"sdiv.fix.sat" = .{
3468 .ret_len = 1,
3469 .params = &.{
3470 .{ .kind = .overloaded },
3471 .{ .kind = .{ .matches = 0 } },
3472 .{ .kind = .{ .matches = 0 } },
3473 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3474 },
3475 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3476 },
3477 .@"udiv.fix.sat" = .{
3478 .ret_len = 1,
3479 .params = &.{
3480 .{ .kind = .overloaded },
3481 .{ .kind = .{ .matches = 0 } },
3482 .{ .kind = .{ .matches = 0 } },
3483 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3484 },
3485 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3486 },
3487
3488 .canonicalize = .{
3489 .ret_len = 1,
3490 .params = &.{
3491 .{ .kind = .overloaded },
3492 .{ .kind = .{ .matches = 0 } },
3493 },
3494 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3495 },
3496 .fmuladd = .{
3497 .ret_len = 1,
3498 .params = &.{
3499 .{ .kind = .overloaded },
3500 .{ .kind = .{ .matches = 0 } },
3501 .{ .kind = .{ .matches = 0 } },
3502 .{ .kind = .{ .matches = 0 } },
3503 },
3504 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3505 },
3506
3507 .@"vector.reduce.add" = .{
3508 .ret_len = 1,
3509 .params = &.{
3510 .{ .kind = .{ .matches_scalar = 1 } },
3511 .{ .kind = .overloaded },
3512 },
3513 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3514 },
3515 .@"vector.reduce.fadd" = .{
3516 .ret_len = 1,
3517 .params = &.{
3518 .{ .kind = .{ .matches_scalar = 2 } },
3519 .{ .kind = .{ .matches_scalar = 2 } },
3520 .{ .kind = .overloaded },
3521 },
3522 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3523 },
3524 .@"vector.reduce.mul" = .{
3525 .ret_len = 1,
3526 .params = &.{
3527 .{ .kind = .{ .matches_scalar = 1 } },
3528 .{ .kind = .overloaded },
3529 },
3530 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3531 },
3532 .@"vector.reduce.fmul" = .{
3533 .ret_len = 1,
3534 .params = &.{
3535 .{ .kind = .{ .matches_scalar = 2 } },
3536 .{ .kind = .{ .matches_scalar = 2 } },
3537 .{ .kind = .overloaded },
3538 },
3539 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3540 },
3541 .@"vector.reduce.and" = .{
3542 .ret_len = 1,
3543 .params = &.{
3544 .{ .kind = .{ .matches_scalar = 1 } },
3545 .{ .kind = .overloaded },
3546 },
3547 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3548 },
3549 .@"vector.reduce.or" = .{
3550 .ret_len = 1,
3551 .params = &.{
3552 .{ .kind = .{ .matches_scalar = 1 } },
3553 .{ .kind = .overloaded },
3554 },
3555 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3556 },
3557 .@"vector.reduce.xor" = .{
3558 .ret_len = 1,
3559 .params = &.{
3560 .{ .kind = .{ .matches_scalar = 1 } },
3561 .{ .kind = .overloaded },
3562 },
3563 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3564 },
3565 .@"vector.reduce.smax" = .{
3566 .ret_len = 1,
3567 .params = &.{
3568 .{ .kind = .{ .matches_scalar = 1 } },
3569 .{ .kind = .overloaded },
3570 },
3571 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3572 },
3573 .@"vector.reduce.smin" = .{
3574 .ret_len = 1,
3575 .params = &.{
3576 .{ .kind = .{ .matches_scalar = 1 } },
3577 .{ .kind = .overloaded },
3578 },
3579 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3580 },
3581 .@"vector.reduce.umax" = .{
3582 .ret_len = 1,
3583 .params = &.{
3584 .{ .kind = .{ .matches_scalar = 1 } },
3585 .{ .kind = .overloaded },
3586 },
3587 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3588 },
3589 .@"vector.reduce.umin" = .{
3590 .ret_len = 1,
3591 .params = &.{
3592 .{ .kind = .{ .matches_scalar = 1 } },
3593 .{ .kind = .overloaded },
3594 },
3595 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3596 },
3597 .@"vector.reduce.fmax" = .{
3598 .ret_len = 1,
3599 .params = &.{
3600 .{ .kind = .{ .matches_scalar = 1 } },
3601 .{ .kind = .overloaded },
3602 },
3603 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3604 },
3605 .@"vector.reduce.fmin" = .{
3606 .ret_len = 1,
3607 .params = &.{
3608 .{ .kind = .{ .matches_scalar = 1 } },
3609 .{ .kind = .overloaded },
3610 },
3611 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3612 },
3613 .@"vector.reduce.fmaximum" = .{
3614 .ret_len = 1,
3615 .params = &.{
3616 .{ .kind = .{ .matches_scalar = 1 } },
3617 .{ .kind = .overloaded },
3618 },
3619 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3620 },
3621 .@"vector.reduce.fminimum" = .{
3622 .ret_len = 1,
3623 .params = &.{
3624 .{ .kind = .{ .matches_scalar = 1 } },
3625 .{ .kind = .overloaded },
3626 },
3627 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3628 },
3629 .@"vector.insert" = .{
3630 .ret_len = 1,
3631 .params = &.{
3632 .{ .kind = .overloaded },
3633 .{ .kind = .{ .matches = 0 } },
3634 .{ .kind = .overloaded },
3635 .{ .kind = .{ .type = .i64 } },
3636 },
3637 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3638 },
3639 .@"vector.extract" = .{
3640 .ret_len = 1,
3641 .params = &.{
3642 .{ .kind = .overloaded },
3643 .{ .kind = .overloaded },
3644 .{ .kind = .{ .type = .i64 } },
3645 },
3646 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3647 },
3648
3649 .@"is.fpclass" = .{
3650 .ret_len = 1,
3651 .params = &.{
3652 .{ .kind = .{ .matches_changed_scalar = .{ .index = 1, .scalar = .i1 } } },
3653 .{ .kind = .overloaded },
3654 .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
3655 },
3656 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3657 },
3658
3659 .@"var.annotation" = .{
3660 .ret_len = 0,
3661 .params = &.{
3662 .{ .kind = .overloaded },
3663 .{ .kind = .overloaded },
3664 .{ .kind = .{ .matches = 1 } },
3665 .{ .kind = .{ .type = .i32 } },
3666 .{ .kind = .{ .matches = 1 } },
3667 },
3668 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3669 },
3670 .@"ptr.annotation" = .{
3671 .ret_len = 1,
3672 .params = &.{
3673 .{ .kind = .overloaded },
3674 .{ .kind = .{ .matches = 0 } },
3675 .{ .kind = .overloaded },
3676 .{ .kind = .{ .matches = 2 } },
3677 .{ .kind = .{ .type = .i32 } },
3678 .{ .kind = .{ .matches = 2 } },
3679 },
3680 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3681 },
3682 .annotation = .{
3683 .ret_len = 1,
3684 .params = &.{
3685 .{ .kind = .overloaded },
3686 .{ .kind = .{ .matches = 0 } },
3687 .{ .kind = .overloaded },
3688 .{ .kind = .{ .matches = 2 } },
3689 .{ .kind = .{ .type = .i32 } },
3690 },
3691 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3692 },
3693 .@"codeview.annotation" = .{
3694 .ret_len = 0,
3695 .params = &.{
3696 .{ .kind = .{ .type = .metadata } },
3697 },
3698 .attrs = &.{ .nocallback, .noduplicate, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3699 },
3700 .trap = .{
3701 .ret_len = 0,
3702 .params = &.{},
3703 .attrs = &.{ .cold, .noreturn, .nounwind, .{ .memory = .{ .inaccessiblemem = .write } } },
3704 },
3705 .debugtrap = .{
3706 .ret_len = 0,
3707 .params = &.{},
3708 .attrs = &.{.nounwind},
3709 },
3710 .ubsantrap = .{
3711 .ret_len = 0,
3712 .params = &.{
3713 .{ .kind = .{ .type = .i8 }, .attrs = &.{.immarg} },
3714 },
3715 .attrs = &.{ .cold, .noreturn, .nounwind },
3716 },
3717 .stackprotector = .{
3718 .ret_len = 0,
3719 .params = &.{
3720 .{ .kind = .{ .type = .ptr } },
3721 .{ .kind = .{ .type = .ptr } },
3722 },
3723 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
3724 },
3725 .stackguard = .{
3726 .ret_len = 1,
3727 .params = &.{
3728 .{ .kind = .{ .type = .ptr } },
3729 },
3730 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
3731 },
3732 .objectsize = .{
3733 .ret_len = 1,
3734 .params = &.{
3735 .{ .kind = .overloaded },
3736 .{ .kind = .overloaded },
3737 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3738 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3739 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
3740 },
3741 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3742 },
3743 .expect = .{
3744 .ret_len = 1,
3745 .params = &.{
3746 .{ .kind = .overloaded },
3747 .{ .kind = .{ .matches = 0 } },
3748 .{ .kind = .{ .matches = 0 } },
3749 },
3750 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3751 },
3752 .@"expect.with.probability" = .{
3753 .ret_len = 1,
3754 .params = &.{
3755 .{ .kind = .overloaded },
3756 .{ .kind = .{ .matches = 0 } },
3757 .{ .kind = .{ .matches = 0 } },
3758 .{ .kind = .{ .type = .double }, .attrs = &.{.immarg} },
3759 },
3760 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3761 },
3762 .assume = .{
3763 .ret_len = 0,
3764 .params = &.{
3765 .{ .kind = .{ .type = .i1 }, .attrs = &.{.noundef} },
3766 },
3767 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .write } } },
3768 },
3769 .@"ssa.copy" = .{
3770 .ret_len = 1,
3771 .params = &.{
3772 .{ .kind = .overloaded },
3773 .{ .kind = .{ .matches = 0 }, .attrs = &.{.returned} },
3774 },
3775 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3776 },
3777 .@"type.test" = .{
3778 .ret_len = 1,
3779 .params = &.{
3780 .{ .kind = .{ .type = .i1 } },
3781 .{ .kind = .{ .type = .ptr } },
3782 .{ .kind = .{ .type = .metadata } },
3783 },
3784 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3785 },
3786 .@"type.checked.load" = .{
3787 .ret_len = 2,
3788 .params = &.{
3789 .{ .kind = .{ .type = .ptr } },
3790 .{ .kind = .{ .type = .i1 } },
3791 .{ .kind = .{ .type = .ptr } },
3792 .{ .kind = .{ .type = .i32 } },
3793 .{ .kind = .{ .type = .metadata } },
3794 },
3795 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3796 },
3797 .@"type.checked.load.relative" = .{
3798 .ret_len = 2,
3799 .params = &.{
3800 .{ .kind = .{ .type = .ptr } },
3801 .{ .kind = .{ .type = .i1 } },
3802 .{ .kind = .{ .type = .ptr } },
3803 .{ .kind = .{ .type = .i32 } },
3804 .{ .kind = .{ .type = .metadata } },
3805 },
3806 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3807 },
3808 .@"arithmetic.fence" = .{
3809 .ret_len = 1,
3810 .params = &.{
3811 .{ .kind = .overloaded },
3812 .{ .kind = .{ .matches = 0 } },
3813 },
3814 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3815 },
3816 .donothing = .{
3817 .ret_len = 0,
3818 .params = &.{},
3819 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3820 },
3821 .@"load.relative" = .{
3822 .ret_len = 1,
3823 .params = &.{
3824 .{ .kind = .{ .type = .ptr } },
3825 .{ .kind = .{ .type = .ptr } },
3826 .{ .kind = .overloaded },
3827 },
3828 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .argmem = .read } } },
3829 },
3830 .sideeffect = .{
3831 .ret_len = 0,
3832 .params = &.{},
3833 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
3834 },
3835 .@"is.constant" = .{
3836 .ret_len = 1,
3837 .params = &.{
3838 .{ .kind = .{ .type = .i1 } },
3839 .{ .kind = .overloaded },
3840 },
3841 .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3842 },
3843 .ptrmask = .{
3844 .ret_len = 1,
3845 .params = &.{
3846 .{ .kind = .overloaded },
3847 .{ .kind = .{ .matches = 0 } },
3848 .{ .kind = .overloaded },
3849 },
3850 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3851 },
3852 .@"threadlocal.address" = .{
3853 .ret_len = 1,
3854 .params = &.{
3855 .{ .kind = .overloaded, .attrs = &.{.nonnull} },
3856 .{ .kind = .{ .matches = 0 }, .attrs = &.{.nonnull} },
3857 },
3858 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3859 },
3860 .vscale = .{
3861 .ret_len = 1,
3862 .params = &.{
3863 .{ .kind = .overloaded },
3864 },
3865 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3866 },
3867
3868 .@"dbg.declare" = .{
3869 .ret_len = 0,
3870 .params = &.{
3871 .{ .kind = .{ .type = .metadata } },
3872 .{ .kind = .{ .type = .metadata } },
3873 .{ .kind = .{ .type = .metadata } },
3874 },
3875 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3876 },
3877 .@"dbg.value" = .{
3878 .ret_len = 0,
3879 .params = &.{
3880 .{ .kind = .{ .type = .metadata } },
3881 .{ .kind = .{ .type = .metadata } },
3882 .{ .kind = .{ .type = .metadata } },
3883 },
3884 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3885 },
3886
3887 .@"amdgcn.workitem.id.x" = .{
3888 .ret_len = 1,
3889 .params = &.{
3890 .{ .kind = .{ .type = .i32 } },
3891 },
3892 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3893 },
3894 .@"amdgcn.workitem.id.y" = .{
3895 .ret_len = 1,
3896 .params = &.{
3897 .{ .kind = .{ .type = .i32 } },
3898 },
3899 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3900 },
3901 .@"amdgcn.workitem.id.z" = .{
3902 .ret_len = 1,
3903 .params = &.{
3904 .{ .kind = .{ .type = .i32 } },
3905 },
3906 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3907 },
3908 .@"amdgcn.workgroup.id.x" = .{
3909 .ret_len = 1,
3910 .params = &.{
3911 .{ .kind = .{ .type = .i32 } },
3912 },
3913 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3914 },
3915 .@"amdgcn.workgroup.id.y" = .{
3916 .ret_len = 1,
3917 .params = &.{
3918 .{ .kind = .{ .type = .i32 } },
3919 },
3920 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3921 },
3922 .@"amdgcn.workgroup.id.z" = .{
3923 .ret_len = 1,
3924 .params = &.{
3925 .{ .kind = .{ .type = .i32 } },
3926 },
3927 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3928 },
3929 .@"amdgcn.dispatch.ptr" = .{
3930 .ret_len = 1,
3931 .params = &.{
3932 .{
3933 .kind = .{ .type = Type.ptr_amdgpu_constant },
3934 .attrs = &.{.{ .@"align" = Builder.Alignment.fromByteUnits(4) }},
3935 },
3936 },
3937 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3938 },
3939
3940 .@"nvvm.read.ptx.sreg.tid.x" = .{
3941 .ret_len = 1,
3942 .params = &.{
3943 .{ .kind = .{ .type = .i32 } },
3944 },
3945 .attrs = &.{ .nounwind, .readnone },
3946 },
3947 .@"nvvm.read.ptx.sreg.tid.y" = .{
3948 .ret_len = 1,
3949 .params = &.{
3950 .{ .kind = .{ .type = .i32 } },
3951 },
3952 .attrs = &.{ .nounwind, .readnone },
3953 },
3954 .@"nvvm.read.ptx.sreg.tid.z" = .{
3955 .ret_len = 1,
3956 .params = &.{
3957 .{ .kind = .{ .type = .i32 } },
3958 },
3959 .attrs = &.{ .nounwind, .readnone },
3960 },
3961
3962 .@"nvvm.read.ptx.sreg.ntid.x" = .{
3963 .ret_len = 1,
3964 .params = &.{
3965 .{ .kind = .{ .type = .i32 } },
3966 },
3967 .attrs = &.{ .nounwind, .readnone },
3968 },
3969 .@"nvvm.read.ptx.sreg.ntid.y" = .{
3970 .ret_len = 1,
3971 .params = &.{
3972 .{ .kind = .{ .type = .i32 } },
3973 },
3974 .attrs = &.{ .nounwind, .readnone },
3975 },
3976 .@"nvvm.read.ptx.sreg.ntid.z" = .{
3977 .ret_len = 1,
3978 .params = &.{
3979 .{ .kind = .{ .type = .i32 } },
3980 },
3981 .attrs = &.{ .nounwind, .readnone },
3982 },
3983
3984 .@"nvvm.read.ptx.sreg.ctaid.x" = .{
3985 .ret_len = 1,
3986 .params = &.{
3987 .{ .kind = .{ .type = .i32 } },
3988 },
3989 .attrs = &.{ .nounwind, .readnone },
3990 },
3991 .@"nvvm.read.ptx.sreg.ctaid.y" = .{
3992 .ret_len = 1,
3993 .params = &.{
3994 .{ .kind = .{ .type = .i32 } },
3995 },
3996 .attrs = &.{ .nounwind, .readnone },
3997 },
3998 .@"nvvm.read.ptx.sreg.ctaid.z" = .{
3999 .ret_len = 1,
4000 .params = &.{
4001 .{ .kind = .{ .type = .i32 } },
4002 },
4003 .attrs = &.{ .nounwind, .readnone },
4004 },
4005
4006 .@"wasm.memory.size" = .{
4007 .ret_len = 1,
4008 .params = &.{
4009 .{ .kind = .overloaded },
4010 .{ .kind = .{ .type = .i32 } },
4011 },
4012 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
4013 },
4014 .@"wasm.memory.grow" = .{
4015 .ret_len = 1,
4016 .params = &.{
4017 .{ .kind = .overloaded },
4018 .{ .kind = .{ .type = .i32 } },
4019 .{ .kind = .{ .matches = 0 } },
4020 },
4021 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
4022 },
4023 });
4024};
4025
4026pub const Function = struct {
4027 global: Global.Index,
4028 call_conv: CallConv = CallConv.default,
4029 attributes: FunctionAttributes = .none,
4030 section: String = .none,
4031 alignment: Alignment = .default,
4032 blocks: []const Block = &.{},
4033 instructions: std.MultiArrayList(Instruction) = .{},
4034 names: [*]const String = &[0]String{},
4035 value_indices: [*]const u32 = &[0]u32{},
4036 strip: bool,
4037 debug_locations: std.AutoHashMapUnmanaged(Instruction.Index, DebugLocation) = .empty,
4038 debug_values: []const Instruction.Index = &.{},
4039 extra: []const u32 = &.{},
4040
4041 pub const Index = enum(u32) {
4042 none = std.math.maxInt(u32),
4043 _,
4044
4045 pub fn ptr(self: Index, builder: *Builder) *Function {
4046 return &builder.functions.items[@intFromEnum(self)];
4047 }
4048
4049 pub fn ptrConst(self: Index, builder: *const Builder) *const Function {
4050 return &builder.functions.items[@intFromEnum(self)];
4051 }
4052
4053 pub fn name(self: Index, builder: *const Builder) StrtabString {
4054 return self.ptrConst(builder).global.name(builder);
4055 }
4056
4057 pub fn rename(self: Index, new_name: StrtabString, builder: *Builder) Allocator.Error!void {
4058 return self.ptrConst(builder).global.rename(new_name, builder);
4059 }
4060
4061 pub fn typeOf(self: Index, builder: *const Builder) Type {
4062 return self.ptrConst(builder).global.typeOf(builder);
4063 }
4064
4065 pub fn toConst(self: Index, builder: *const Builder) Constant {
4066 return self.ptrConst(builder).global.toConst();
4067 }
4068
4069 pub fn toValue(self: Index, builder: *const Builder) Value {
4070 return self.toConst(builder).toValue();
4071 }
4072
4073 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
4074 return self.ptrConst(builder).global.setLinkage(linkage, builder);
4075 }
4076
4077 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
4078 return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
4079 }
4080
4081 pub fn setCallConv(self: Index, call_conv: CallConv, builder: *Builder) void {
4082 self.ptr(builder).call_conv = call_conv;
4083 }
4084
4085 pub fn setAttributes(
4086 self: Index,
4087 new_function_attributes: FunctionAttributes,
4088 builder: *Builder,
4089 ) void {
4090 self.ptr(builder).attributes = new_function_attributes;
4091 }
4092
4093 pub fn setSection(self: Index, section: String, builder: *Builder) void {
4094 self.ptr(builder).section = section;
4095 }
4096
4097 pub fn setAlignment(self: Index, alignment: Alignment, builder: *Builder) void {
4098 self.ptr(builder).alignment = alignment;
4099 }
4100
4101 pub fn setSubprogram(self: Index, subprogram: Metadata, builder: *Builder) void {
4102 self.ptrConst(builder).global.setDebugMetadata(subprogram, builder);
4103 }
4104 };
4105
4106 pub const Block = struct {
4107 instruction: Instruction.Index,
4108
4109 pub const Index = WipFunction.Block.Index;
4110 };
4111
4112 pub const Instruction = struct {
4113 tag: Tag,
4114 data: u32,
4115
4116 pub const Tag = enum(u8) {
4117 add,
4118 @"add nsw",
4119 @"add nuw",
4120 @"add nuw nsw",
4121 addrspacecast,
4122 alloca,
4123 @"alloca inalloca",
4124 @"and",
4125 arg,
4126 ashr,
4127 @"ashr exact",
4128 atomicrmw,
4129 bitcast,
4130 block,
4131 br,
4132 br_cond,
4133 call,
4134 @"call fast",
4135 cmpxchg,
4136 @"cmpxchg weak",
4137 extractelement,
4138 extractvalue,
4139 fadd,
4140 @"fadd fast",
4141 @"fcmp false",
4142 @"fcmp fast false",
4143 @"fcmp fast oeq",
4144 @"fcmp fast oge",
4145 @"fcmp fast ogt",
4146 @"fcmp fast ole",
4147 @"fcmp fast olt",
4148 @"fcmp fast one",
4149 @"fcmp fast ord",
4150 @"fcmp fast true",
4151 @"fcmp fast ueq",
4152 @"fcmp fast uge",
4153 @"fcmp fast ugt",
4154 @"fcmp fast ule",
4155 @"fcmp fast ult",
4156 @"fcmp fast une",
4157 @"fcmp fast uno",
4158 @"fcmp oeq",
4159 @"fcmp oge",
4160 @"fcmp ogt",
4161 @"fcmp ole",
4162 @"fcmp olt",
4163 @"fcmp one",
4164 @"fcmp ord",
4165 @"fcmp true",
4166 @"fcmp ueq",
4167 @"fcmp uge",
4168 @"fcmp ugt",
4169 @"fcmp ule",
4170 @"fcmp ult",
4171 @"fcmp une",
4172 @"fcmp uno",
4173 fdiv,
4174 @"fdiv fast",
4175 fence,
4176 fmul,
4177 @"fmul fast",
4178 fneg,
4179 @"fneg fast",
4180 fpext,
4181 fptosi,
4182 fptoui,
4183 fptrunc,
4184 frem,
4185 @"frem fast",
4186 fsub,
4187 @"fsub fast",
4188 getelementptr,
4189 @"getelementptr inbounds",
4190 @"icmp eq",
4191 @"icmp ne",
4192 @"icmp sge",
4193 @"icmp sgt",
4194 @"icmp sle",
4195 @"icmp slt",
4196 @"icmp uge",
4197 @"icmp ugt",
4198 @"icmp ule",
4199 @"icmp ult",
4200 indirectbr,
4201 insertelement,
4202 insertvalue,
4203 inttoptr,
4204 load,
4205 @"load atomic",
4206 lshr,
4207 @"lshr exact",
4208 mul,
4209 @"mul nsw",
4210 @"mul nuw",
4211 @"mul nuw nsw",
4212 @"musttail call",
4213 @"musttail call fast",
4214 @"notail call",
4215 @"notail call fast",
4216 @"or",
4217 phi,
4218 @"phi fast",
4219 ptrtoint,
4220 ret,
4221 @"ret void",
4222 sdiv,
4223 @"sdiv exact",
4224 select,
4225 @"select fast",
4226 sext,
4227 shl,
4228 @"shl nsw",
4229 @"shl nuw",
4230 @"shl nuw nsw",
4231 shufflevector,
4232 sitofp,
4233 srem,
4234 store,
4235 @"store atomic",
4236 sub,
4237 @"sub nsw",
4238 @"sub nuw",
4239 @"sub nuw nsw",
4240 @"switch",
4241 @"tail call",
4242 @"tail call fast",
4243 trunc,
4244 udiv,
4245 @"udiv exact",
4246 urem,
4247 uitofp,
4248 @"unreachable",
4249 va_arg,
4250 xor,
4251 zext,
4252
4253 pub fn toBinaryOpcode(self: Tag) BinaryOpcode {
4254 return switch (self) {
4255 .add,
4256 .@"add nsw",
4257 .@"add nuw",
4258 .@"add nuw nsw",
4259 .fadd,
4260 .@"fadd fast",
4261 => .add,
4262 .sub,
4263 .@"sub nsw",
4264 .@"sub nuw",
4265 .@"sub nuw nsw",
4266 .fsub,
4267 .@"fsub fast",
4268 => .sub,
4269 .sdiv,
4270 .@"sdiv exact",
4271 .fdiv,
4272 .@"fdiv fast",
4273 => .sdiv,
4274 .fmul,
4275 .@"fmul fast",
4276 .mul,
4277 .@"mul nsw",
4278 .@"mul nuw",
4279 .@"mul nuw nsw",
4280 => .mul,
4281 .srem,
4282 .frem,
4283 .@"frem fast",
4284 => .srem,
4285 .udiv,
4286 .@"udiv exact",
4287 => .udiv,
4288 .shl,
4289 .@"shl nsw",
4290 .@"shl nuw",
4291 .@"shl nuw nsw",
4292 => .shl,
4293 .lshr,
4294 .@"lshr exact",
4295 => .lshr,
4296 .ashr,
4297 .@"ashr exact",
4298 => .ashr,
4299 .@"and" => .@"and",
4300 .@"or" => .@"or",
4301 .xor => .xor,
4302 .urem => .urem,
4303 else => unreachable,
4304 };
4305 }
4306
4307 pub fn toCastOpcode(self: Tag) CastOpcode {
4308 return switch (self) {
4309 .trunc => .trunc,
4310 .zext => .zext,
4311 .sext => .sext,
4312 .fptoui => .fptoui,
4313 .fptosi => .fptosi,
4314 .uitofp => .uitofp,
4315 .sitofp => .sitofp,
4316 .fptrunc => .fptrunc,
4317 .fpext => .fpext,
4318 .ptrtoint => .ptrtoint,
4319 .inttoptr => .inttoptr,
4320 .bitcast => .bitcast,
4321 .addrspacecast => .addrspacecast,
4322 else => unreachable,
4323 };
4324 }
4325
4326 pub fn toCmpPredicate(self: Tag) CmpPredicate {
4327 return switch (self) {
4328 .@"fcmp false",
4329 .@"fcmp fast false",
4330 => .fcmp_false,
4331 .@"fcmp oeq",
4332 .@"fcmp fast oeq",
4333 => .fcmp_oeq,
4334 .@"fcmp oge",
4335 .@"fcmp fast oge",
4336 => .fcmp_oge,
4337 .@"fcmp ogt",
4338 .@"fcmp fast ogt",
4339 => .fcmp_ogt,
4340 .@"fcmp ole",
4341 .@"fcmp fast ole",
4342 => .fcmp_ole,
4343 .@"fcmp olt",
4344 .@"fcmp fast olt",
4345 => .fcmp_olt,
4346 .@"fcmp one",
4347 .@"fcmp fast one",
4348 => .fcmp_one,
4349 .@"fcmp ord",
4350 .@"fcmp fast ord",
4351 => .fcmp_ord,
4352 .@"fcmp true",
4353 .@"fcmp fast true",
4354 => .fcmp_true,
4355 .@"fcmp ueq",
4356 .@"fcmp fast ueq",
4357 => .fcmp_ueq,
4358 .@"fcmp uge",
4359 .@"fcmp fast uge",
4360 => .fcmp_uge,
4361 .@"fcmp ugt",
4362 .@"fcmp fast ugt",
4363 => .fcmp_ugt,
4364 .@"fcmp ule",
4365 .@"fcmp fast ule",
4366 => .fcmp_ule,
4367 .@"fcmp ult",
4368 .@"fcmp fast ult",
4369 => .fcmp_ult,
4370 .@"fcmp une",
4371 .@"fcmp fast une",
4372 => .fcmp_une,
4373 .@"fcmp uno",
4374 .@"fcmp fast uno",
4375 => .fcmp_uno,
4376 .@"icmp eq" => .icmp_eq,
4377 .@"icmp ne" => .icmp_ne,
4378 .@"icmp sge" => .icmp_sge,
4379 .@"icmp sgt" => .icmp_sgt,
4380 .@"icmp sle" => .icmp_sle,
4381 .@"icmp slt" => .icmp_slt,
4382 .@"icmp uge" => .icmp_uge,
4383 .@"icmp ugt" => .icmp_ugt,
4384 .@"icmp ule" => .icmp_ule,
4385 .@"icmp ult" => .icmp_ult,
4386 else => unreachable,
4387 };
4388 }
4389 };
4390
4391 pub const Index = enum(u32) {
4392 none = std.math.maxInt(u31),
4393 _,
4394
4395 pub fn name(self: Instruction.Index, function: *const Function) String {
4396 return function.names[@intFromEnum(self)];
4397 }
4398
4399 pub fn valueIndex(self: Instruction.Index, function: *const Function) u32 {
4400 return function.value_indices[@intFromEnum(self)];
4401 }
4402
4403 pub fn toValue(self: Instruction.Index) Value {
4404 return @enumFromInt(@intFromEnum(self));
4405 }
4406
4407 pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool {
4408 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
4409 .br,
4410 .br_cond,
4411 .indirectbr,
4412 .ret,
4413 .@"ret void",
4414 .@"switch",
4415 .@"unreachable",
4416 => true,
4417 else => false,
4418 };
4419 }
4420
4421 pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool {
4422 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
4423 .br,
4424 .br_cond,
4425 .fence,
4426 .indirectbr,
4427 .ret,
4428 .@"ret void",
4429 .store,
4430 .@"store atomic",
4431 .@"switch",
4432 .@"unreachable",
4433 .block,
4434 => false,
4435 .call,
4436 .@"call fast",
4437 .@"musttail call",
4438 .@"musttail call fast",
4439 .@"notail call",
4440 .@"notail call fast",
4441 .@"tail call",
4442 .@"tail call fast",
4443 => self.typeOfWip(wip) != .void,
4444 else => true,
4445 };
4446 }
4447
4448 pub fn typeOfWip(self: Instruction.Index, wip: *const WipFunction) Type {
4449 const instruction = wip.instructions.get(@intFromEnum(self));
4450 return switch (instruction.tag) {
4451 .add,
4452 .@"add nsw",
4453 .@"add nuw",
4454 .@"add nuw nsw",
4455 .@"and",
4456 .ashr,
4457 .@"ashr exact",
4458 .fadd,
4459 .@"fadd fast",
4460 .fdiv,
4461 .@"fdiv fast",
4462 .fmul,
4463 .@"fmul fast",
4464 .frem,
4465 .@"frem fast",
4466 .fsub,
4467 .@"fsub fast",
4468 .lshr,
4469 .@"lshr exact",
4470 .mul,
4471 .@"mul nsw",
4472 .@"mul nuw",
4473 .@"mul nuw nsw",
4474 .@"or",
4475 .sdiv,
4476 .@"sdiv exact",
4477 .shl,
4478 .@"shl nsw",
4479 .@"shl nuw",
4480 .@"shl nuw nsw",
4481 .srem,
4482 .sub,
4483 .@"sub nsw",
4484 .@"sub nuw",
4485 .@"sub nuw nsw",
4486 .udiv,
4487 .@"udiv exact",
4488 .urem,
4489 .xor,
4490 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip),
4491 .addrspacecast,
4492 .bitcast,
4493 .fpext,
4494 .fptosi,
4495 .fptoui,
4496 .fptrunc,
4497 .inttoptr,
4498 .ptrtoint,
4499 .sext,
4500 .sitofp,
4501 .trunc,
4502 .uitofp,
4503 .zext,
4504 => wip.extraData(Cast, instruction.data).type,
4505 .alloca,
4506 .@"alloca inalloca",
4507 => wip.builder.ptrTypeAssumeCapacity(
4508 wip.extraData(Alloca, instruction.data).info.addr_space,
4509 ),
4510 .arg => wip.function.typeOf(wip.builder)
4511 .functionParameters(wip.builder)[instruction.data],
4512 .atomicrmw => wip.extraData(AtomicRmw, instruction.data).val.typeOfWip(wip),
4513 .block => .label,
4514 .br,
4515 .br_cond,
4516 .fence,
4517 .indirectbr,
4518 .ret,
4519 .@"ret void",
4520 .store,
4521 .@"store atomic",
4522 .@"switch",
4523 .@"unreachable",
4524 => .none,
4525 .call,
4526 .@"call fast",
4527 .@"musttail call",
4528 .@"musttail call fast",
4529 .@"notail call",
4530 .@"notail call fast",
4531 .@"tail call",
4532 .@"tail call fast",
4533 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
4534 .cmpxchg,
4535 .@"cmpxchg weak",
4536 => wip.builder.structTypeAssumeCapacity(.normal, &.{
4537 wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
4538 .i1,
4539 }),
4540 .extractelement => wip.extraData(ExtractElement, instruction.data)
4541 .val.typeOfWip(wip).childType(wip.builder),
4542 .extractvalue => {
4543 var extra = wip.extraDataTrail(ExtractValue, instruction.data);
4544 const indices = extra.trail.next(extra.data.indices_len, u32, wip);
4545 return extra.data.val.typeOfWip(wip).childTypeAt(indices, wip.builder);
4546 },
4547 .@"fcmp false",
4548 .@"fcmp fast false",
4549 .@"fcmp fast oeq",
4550 .@"fcmp fast oge",
4551 .@"fcmp fast ogt",
4552 .@"fcmp fast ole",
4553 .@"fcmp fast olt",
4554 .@"fcmp fast one",
4555 .@"fcmp fast ord",
4556 .@"fcmp fast true",
4557 .@"fcmp fast ueq",
4558 .@"fcmp fast uge",
4559 .@"fcmp fast ugt",
4560 .@"fcmp fast ule",
4561 .@"fcmp fast ult",
4562 .@"fcmp fast une",
4563 .@"fcmp fast uno",
4564 .@"fcmp oeq",
4565 .@"fcmp oge",
4566 .@"fcmp ogt",
4567 .@"fcmp ole",
4568 .@"fcmp olt",
4569 .@"fcmp one",
4570 .@"fcmp ord",
4571 .@"fcmp true",
4572 .@"fcmp ueq",
4573 .@"fcmp uge",
4574 .@"fcmp ugt",
4575 .@"fcmp ule",
4576 .@"fcmp ult",
4577 .@"fcmp une",
4578 .@"fcmp uno",
4579 .@"icmp eq",
4580 .@"icmp ne",
4581 .@"icmp sge",
4582 .@"icmp sgt",
4583 .@"icmp sle",
4584 .@"icmp slt",
4585 .@"icmp uge",
4586 .@"icmp ugt",
4587 .@"icmp ule",
4588 .@"icmp ult",
4589 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip)
4590 .changeScalarAssumeCapacity(.i1, wip.builder),
4591 .fneg,
4592 .@"fneg fast",
4593 => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
4594 .getelementptr,
4595 .@"getelementptr inbounds",
4596 => {
4597 var extra = wip.extraDataTrail(GetElementPtr, instruction.data);
4598 const indices = extra.trail.next(extra.data.indices_len, Value, wip);
4599 const base_ty = extra.data.base.typeOfWip(wip);
4600 if (!base_ty.isVector(wip.builder)) for (indices) |index| {
4601 const index_ty = index.typeOfWip(wip);
4602 if (!index_ty.isVector(wip.builder)) continue;
4603 return index_ty.changeScalarAssumeCapacity(base_ty, wip.builder);
4604 };
4605 return base_ty;
4606 },
4607 .insertelement => wip.extraData(InsertElement, instruction.data).val.typeOfWip(wip),
4608 .insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
4609 .load,
4610 .@"load atomic",
4611 => wip.extraData(Load, instruction.data).type,
4612 .phi,
4613 .@"phi fast",
4614 => wip.extraData(Phi, instruction.data).type,
4615 .select,
4616 .@"select fast",
4617 => wip.extraData(Select, instruction.data).lhs.typeOfWip(wip),
4618 .shufflevector => {
4619 const extra = wip.extraData(ShuffleVector, instruction.data);
4620 return extra.lhs.typeOfWip(wip).changeLengthAssumeCapacity(
4621 extra.mask.typeOfWip(wip).vectorLen(wip.builder),
4622 wip.builder,
4623 );
4624 },
4625 .va_arg => wip.extraData(VaArg, instruction.data).type,
4626 };
4627 }
4628
4629 pub fn typeOf(
4630 self: Instruction.Index,
4631 function_index: Function.Index,
4632 builder: *Builder,
4633 ) Type {
4634 const function = function_index.ptrConst(builder);
4635 const instruction = function.instructions.get(@intFromEnum(self));
4636 return switch (instruction.tag) {
4637 .add,
4638 .@"add nsw",
4639 .@"add nuw",
4640 .@"add nuw nsw",
4641 .@"and",
4642 .ashr,
4643 .@"ashr exact",
4644 .fadd,
4645 .@"fadd fast",
4646 .fdiv,
4647 .@"fdiv fast",
4648 .fmul,
4649 .@"fmul fast",
4650 .frem,
4651 .@"frem fast",
4652 .fsub,
4653 .@"fsub fast",
4654 .lshr,
4655 .@"lshr exact",
4656 .mul,
4657 .@"mul nsw",
4658 .@"mul nuw",
4659 .@"mul nuw nsw",
4660 .@"or",
4661 .sdiv,
4662 .@"sdiv exact",
4663 .shl,
4664 .@"shl nsw",
4665 .@"shl nuw",
4666 .@"shl nuw nsw",
4667 .srem,
4668 .sub,
4669 .@"sub nsw",
4670 .@"sub nuw",
4671 .@"sub nuw nsw",
4672 .udiv,
4673 .@"udiv exact",
4674 .urem,
4675 .xor,
4676 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder),
4677 .addrspacecast,
4678 .bitcast,
4679 .fpext,
4680 .fptosi,
4681 .fptoui,
4682 .fptrunc,
4683 .inttoptr,
4684 .ptrtoint,
4685 .sext,
4686 .sitofp,
4687 .trunc,
4688 .uitofp,
4689 .zext,
4690 => function.extraData(Cast, instruction.data).type,
4691 .alloca,
4692 .@"alloca inalloca",
4693 => builder.ptrTypeAssumeCapacity(
4694 function.extraData(Alloca, instruction.data).info.addr_space,
4695 ),
4696 .arg => function.global.typeOf(builder)
4697 .functionParameters(builder)[instruction.data],
4698 .atomicrmw => function.extraData(AtomicRmw, instruction.data)
4699 .val.typeOf(function_index, builder),
4700 .block => .label,
4701 .br,
4702 .br_cond,
4703 .fence,
4704 .indirectbr,
4705 .ret,
4706 .@"ret void",
4707 .store,
4708 .@"store atomic",
4709 .@"switch",
4710 .@"unreachable",
4711 => .none,
4712 .call,
4713 .@"call fast",
4714 .@"musttail call",
4715 .@"musttail call fast",
4716 .@"notail call",
4717 .@"notail call fast",
4718 .@"tail call",
4719 .@"tail call fast",
4720 => function.extraData(Call, instruction.data).ty.functionReturn(builder),
4721 .cmpxchg,
4722 .@"cmpxchg weak",
4723 => builder.structTypeAssumeCapacity(.normal, &.{
4724 function.extraData(CmpXchg, instruction.data)
4725 .cmp.typeOf(function_index, builder),
4726 .i1,
4727 }),
4728 .extractelement => function.extraData(ExtractElement, instruction.data)
4729 .val.typeOf(function_index, builder).childType(builder),
4730 .extractvalue => {
4731 var extra = function.extraDataTrail(ExtractValue, instruction.data);
4732 const indices = extra.trail.next(extra.data.indices_len, u32, function);
4733 return extra.data.val.typeOf(function_index, builder)
4734 .childTypeAt(indices, builder);
4735 },
4736 .@"fcmp false",
4737 .@"fcmp fast false",
4738 .@"fcmp fast oeq",
4739 .@"fcmp fast oge",
4740 .@"fcmp fast ogt",
4741 .@"fcmp fast ole",
4742 .@"fcmp fast olt",
4743 .@"fcmp fast one",
4744 .@"fcmp fast ord",
4745 .@"fcmp fast true",
4746 .@"fcmp fast ueq",
4747 .@"fcmp fast uge",
4748 .@"fcmp fast ugt",
4749 .@"fcmp fast ule",
4750 .@"fcmp fast ult",
4751 .@"fcmp fast une",
4752 .@"fcmp fast uno",
4753 .@"fcmp oeq",
4754 .@"fcmp oge",
4755 .@"fcmp ogt",
4756 .@"fcmp ole",
4757 .@"fcmp olt",
4758 .@"fcmp one",
4759 .@"fcmp ord",
4760 .@"fcmp true",
4761 .@"fcmp ueq",
4762 .@"fcmp uge",
4763 .@"fcmp ugt",
4764 .@"fcmp ule",
4765 .@"fcmp ult",
4766 .@"fcmp une",
4767 .@"fcmp uno",
4768 .@"icmp eq",
4769 .@"icmp ne",
4770 .@"icmp sge",
4771 .@"icmp sgt",
4772 .@"icmp sle",
4773 .@"icmp slt",
4774 .@"icmp uge",
4775 .@"icmp ugt",
4776 .@"icmp ule",
4777 .@"icmp ult",
4778 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder)
4779 .changeScalarAssumeCapacity(.i1, builder),
4780 .fneg,
4781 .@"fneg fast",
4782 => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
4783 .getelementptr,
4784 .@"getelementptr inbounds",
4785 => {
4786 var extra = function.extraDataTrail(GetElementPtr, instruction.data);
4787 const indices = extra.trail.next(extra.data.indices_len, Value, function);
4788 const base_ty = extra.data.base.typeOf(function_index, builder);
4789 if (!base_ty.isVector(builder)) for (indices) |index| {
4790 const index_ty = index.typeOf(function_index, builder);
4791 if (!index_ty.isVector(builder)) continue;
4792 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
4793 };
4794 return base_ty;
4795 },
4796 .insertelement => function.extraData(InsertElement, instruction.data)
4797 .val.typeOf(function_index, builder),
4798 .insertvalue => function.extraData(InsertValue, instruction.data)
4799 .val.typeOf(function_index, builder),
4800 .load,
4801 .@"load atomic",
4802 => function.extraData(Load, instruction.data).type,
4803 .phi,
4804 .@"phi fast",
4805 => function.extraData(Phi, instruction.data).type,
4806 .select,
4807 .@"select fast",
4808 => function.extraData(Select, instruction.data).lhs.typeOf(function_index, builder),
4809 .shufflevector => {
4810 const extra = function.extraData(ShuffleVector, instruction.data);
4811 return extra.lhs.typeOf(function_index, builder).changeLengthAssumeCapacity(
4812 extra.mask.typeOf(function_index, builder).vectorLen(builder),
4813 builder,
4814 );
4815 },
4816 .va_arg => function.extraData(VaArg, instruction.data).type,
4817 };
4818 }
4819
4820 const FormatData = struct {
4821 instruction: Instruction.Index,
4822 function: Function.Index,
4823 builder: *Builder,
4824 };
4825 fn format(
4826 data: FormatData,
4827 comptime fmt_str: []const u8,
4828 _: std.fmt.FormatOptions,
4829 writer: anytype,
4830 ) @TypeOf(writer).Error!void {
4831 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
4832 @compileError("invalid format string: '" ++ fmt_str ++ "'");
4833 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
4834 if (data.instruction == .none) return;
4835 try writer.writeByte(',');
4836 }
4837 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
4838 if (data.instruction == .none) return;
4839 try writer.writeByte(' ');
4840 }
4841 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print(
4842 "{%} ",
4843 .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)},
4844 );
4845 assert(data.instruction != .none);
4846 try writer.print("%{}", .{
4847 data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder),
4848 });
4849 }
4850 pub fn fmt(
4851 self: Instruction.Index,
4852 function: Function.Index,
4853 builder: *Builder,
4854 ) std.fmt.Formatter(format) {
4855 return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
4856 }
4857 };
4858
4859 pub const ExtraIndex = u32;
4860
4861 pub const BrCond = struct {
4862 cond: Value,
4863 then: Block.Index,
4864 @"else": Block.Index,
4865 weights: Weights,
4866 pub const Weights = enum(u32) {
4867 // We can do this as metadata indices 0 and 1 are reserved.
4868 none = 0,
4869 unpredictable = 1,
4870 /// These values should be converted to `Metadata` to be used
4871 /// in a `prof` annotation providing branch weights.
4872 _,
4873 };
4874 };
4875
4876 pub const Switch = struct {
4877 val: Value,
4878 default: Block.Index,
4879 cases_len: u32,
4880 weights: BrCond.Weights,
4881 //case_vals: [cases_len]Constant,
4882 //case_blocks: [cases_len]Block.Index,
4883 };
4884
4885 pub const IndirectBr = struct {
4886 addr: Value,
4887 targets_len: u32,
4888 //targets: [targets_len]Block.Index,
4889 };
4890
4891 pub const Binary = struct {
4892 lhs: Value,
4893 rhs: Value,
4894 };
4895
4896 pub const ExtractElement = struct {
4897 val: Value,
4898 index: Value,
4899 };
4900
4901 pub const InsertElement = struct {
4902 val: Value,
4903 elem: Value,
4904 index: Value,
4905 };
4906
4907 pub const ShuffleVector = struct {
4908 lhs: Value,
4909 rhs: Value,
4910 mask: Value,
4911 };
4912
4913 pub const ExtractValue = struct {
4914 val: Value,
4915 indices_len: u32,
4916 //indices: [indices_len]u32,
4917 };
4918
4919 pub const InsertValue = struct {
4920 val: Value,
4921 elem: Value,
4922 indices_len: u32,
4923 //indices: [indices_len]u32,
4924 };
4925
4926 pub const Alloca = struct {
4927 type: Type,
4928 len: Value,
4929 info: Info,
4930
4931 pub const Kind = enum { normal, inalloca };
4932 pub const Info = packed struct(u32) {
4933 alignment: Alignment,
4934 addr_space: AddrSpace,
4935 _: u2 = undefined,
4936 };
4937 };
4938
4939 pub const Load = struct {
4940 info: MemoryAccessInfo,
4941 type: Type,
4942 ptr: Value,
4943 };
4944
4945 pub const Store = struct {
4946 info: MemoryAccessInfo,
4947 val: Value,
4948 ptr: Value,
4949 };
4950
4951 pub const CmpXchg = struct {
4952 info: MemoryAccessInfo,
4953 ptr: Value,
4954 cmp: Value,
4955 new: Value,
4956
4957 pub const Kind = enum { strong, weak };
4958 };
4959
4960 pub const AtomicRmw = struct {
4961 info: MemoryAccessInfo,
4962 ptr: Value,
4963 val: Value,
4964
4965 pub const Operation = enum(u5) {
4966 xchg = 0,
4967 add = 1,
4968 sub = 2,
4969 @"and" = 3,
4970 nand = 4,
4971 @"or" = 5,
4972 xor = 6,
4973 max = 7,
4974 min = 8,
4975 umax = 9,
4976 umin = 10,
4977 fadd = 11,
4978 fsub = 12,
4979 fmax = 13,
4980 fmin = 14,
4981 none = std.math.maxInt(u5),
4982 };
4983 };
4984
4985 pub const GetElementPtr = struct {
4986 type: Type,
4987 base: Value,
4988 indices_len: u32,
4989 //indices: [indices_len]Value,
4990
4991 pub const Kind = Constant.GetElementPtr.Kind;
4992 };
4993
4994 pub const Cast = struct {
4995 val: Value,
4996 type: Type,
4997
4998 pub const Signedness = Constant.Cast.Signedness;
4999 };
5000
5001 pub const Phi = struct {
5002 type: Type,
5003 //incoming_vals: [block.incoming]Value,
5004 //incoming_blocks: [block.incoming]Block.Index,
5005 };
5006
5007 pub const Select = struct {
5008 cond: Value,
5009 lhs: Value,
5010 rhs: Value,
5011 };
5012
5013 pub const Call = struct {
5014 info: Info,
5015 attributes: FunctionAttributes,
5016 ty: Type,
5017 callee: Value,
5018 args_len: u32,
5019 //args: [args_len]Value,
5020
5021 pub const Kind = enum {
5022 normal,
5023 fast,
5024 musttail,
5025 musttail_fast,
5026 notail,
5027 notail_fast,
5028 tail,
5029 tail_fast,
5030 };
5031 pub const Info = packed struct(u32) {
5032 call_conv: CallConv,
5033 has_op_bundle_cold: bool,
5034 _: u21 = undefined,
5035 };
5036 };
5037
5038 pub const VaArg = struct {
5039 list: Value,
5040 type: Type,
5041 };
5042 };
5043
5044 pub fn deinit(self: *Function, gpa: Allocator) void {
5045 gpa.free(self.extra);
5046 gpa.free(self.debug_values);
5047 self.debug_locations.deinit(gpa);
5048 gpa.free(self.value_indices[0..self.instructions.len]);
5049 gpa.free(self.names[0..self.instructions.len]);
5050 self.instructions.deinit(gpa);
5051 gpa.free(self.blocks);
5052 self.* = undefined;
5053 }
5054
5055 pub fn arg(self: *const Function, index: u32) Value {
5056 const argument = self.instructions.get(index);
5057 assert(argument.tag == .arg);
5058 assert(argument.data == index);
5059
5060 const argument_index: Instruction.Index = @enumFromInt(index);
5061 return argument_index.toValue();
5062 }
5063
5064 const ExtraDataTrail = struct {
5065 index: Instruction.ExtraIndex,
5066
5067 fn nextMut(self: *ExtraDataTrail, len: u32, comptime Item: type, function: *Function) []Item {
5068 const items: []Item = @ptrCast(function.extra[self.index..][0..len]);
5069 self.index += @intCast(len);
5070 return items;
5071 }
5072
5073 fn next(
5074 self: *ExtraDataTrail,
5075 len: u32,
5076 comptime Item: type,
5077 function: *const Function,
5078 ) []const Item {
5079 const items: []const Item = @ptrCast(function.extra[self.index..][0..len]);
5080 self.index += @intCast(len);
5081 return items;
5082 }
5083 };
5084
5085 fn extraDataTrail(
5086 self: *const Function,
5087 comptime T: type,
5088 index: Instruction.ExtraIndex,
5089 ) struct { data: T, trail: ExtraDataTrail } {
5090 var result: T = undefined;
5091 const fields = @typeInfo(T).@"struct".fields;
5092 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
5093 @field(result, field.name) = switch (field.type) {
5094 u32 => value,
5095 Alignment,
5096 AtomicOrdering,
5097 Block.Index,
5098 FunctionAttributes,
5099 Type,
5100 Value,
5101 Instruction.BrCond.Weights,
5102 => @enumFromInt(value),
5103 MemoryAccessInfo,
5104 Instruction.Alloca.Info,
5105 Instruction.Call.Info,
5106 => @bitCast(value),
5107 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
5108 };
5109 return .{
5110 .data = result,
5111 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
5112 };
5113 }
5114
5115 fn extraData(self: *const Function, comptime T: type, index: Instruction.ExtraIndex) T {
5116 return self.extraDataTrail(T, index).data;
5117 }
5118};
5119
5120pub const DebugLocation = union(enum) {
5121 no_location: void,
5122 location: Location,
5123
5124 pub const Location = struct {
5125 line: u32,
5126 column: u32,
5127 scope: Builder.Metadata,
5128 inlined_at: Builder.Metadata,
5129 };
5130
5131 pub fn toMetadata(self: DebugLocation, builder: *Builder) Allocator.Error!Metadata {
5132 return switch (self) {
5133 .no_location => .none,
5134 .location => |location| try builder.debugLocation(
5135 location.line,
5136 location.column,
5137 location.scope,
5138 location.inlined_at,
5139 ),
5140 };
5141 }
5142};
5143
5144pub const WipFunction = struct {
5145 builder: *Builder,
5146 function: Function.Index,
5147 prev_debug_location: DebugLocation,
5148 debug_location: DebugLocation,
5149 cursor: Cursor,
5150 blocks: std.ArrayListUnmanaged(Block),
5151 instructions: std.MultiArrayList(Instruction),
5152 names: std.ArrayListUnmanaged(String),
5153 strip: bool,
5154 debug_locations: std.AutoArrayHashMapUnmanaged(Instruction.Index, DebugLocation),
5155 debug_values: std.AutoArrayHashMapUnmanaged(Instruction.Index, void),
5156 extra: std.ArrayListUnmanaged(u32),
5157
5158 pub const Cursor = struct { block: Block.Index, instruction: u32 = 0 };
5159
5160 pub const Block = struct {
5161 name: String,
5162 incoming: u32,
5163 branches: u32 = 0,
5164 instructions: std.ArrayListUnmanaged(Instruction.Index),
5165
5166 const Index = enum(u32) {
5167 entry,
5168 _,
5169
5170 pub fn ptr(self: Index, wip: *WipFunction) *Block {
5171 return &wip.blocks.items[@intFromEnum(self)];
5172 }
5173
5174 pub fn ptrConst(self: Index, wip: *const WipFunction) *const Block {
5175 return &wip.blocks.items[@intFromEnum(self)];
5176 }
5177
5178 pub fn toInst(self: Index, function: *const Function) Instruction.Index {
5179 return function.blocks[@intFromEnum(self)].instruction;
5180 }
5181 };
5182 };
5183
5184 pub const Instruction = Function.Instruction;
5185
5186 pub fn init(builder: *Builder, options: struct {
5187 function: Function.Index,
5188 strip: bool,
5189 }) Allocator.Error!WipFunction {
5190 var self: WipFunction = .{
5191 .builder = builder,
5192 .function = options.function,
5193 .prev_debug_location = .no_location,
5194 .debug_location = .no_location,
5195 .cursor = undefined,
5196 .blocks = .{},
5197 .instructions = .{},
5198 .names = .{},
5199 .strip = options.strip,
5200 .debug_locations = .{},
5201 .debug_values = .{},
5202 .extra = .{},
5203 };
5204 errdefer self.deinit();
5205
5206 const params_len = options.function.typeOf(self.builder).functionParameters(self.builder).len;
5207 try self.ensureUnusedExtraCapacity(params_len, NoExtra, 0);
5208 try self.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
5209 if (!self.strip) {
5210 try self.names.ensureUnusedCapacity(self.builder.gpa, params_len);
5211 }
5212 for (0..params_len) |param_index| {
5213 self.instructions.appendAssumeCapacity(.{ .tag = .arg, .data = @intCast(param_index) });
5214 if (!self.strip) {
5215 self.names.appendAssumeCapacity(.empty); // TODO: param names
5216 }
5217 }
5218
5219 return self;
5220 }
5221
5222 pub fn arg(self: *const WipFunction, index: u32) Value {
5223 const argument = self.instructions.get(index);
5224 assert(argument.tag == .arg);
5225 assert(argument.data == index);
5226
5227 const argument_index: Instruction.Index = @enumFromInt(index);
5228 return argument_index.toValue();
5229 }
5230
5231 pub fn block(self: *WipFunction, incoming: u32, name: []const u8) Allocator.Error!Block.Index {
5232 try self.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
5233
5234 const index: Block.Index = @enumFromInt(self.blocks.items.len);
5235 const final_name = if (self.strip) .empty else try self.builder.string(name);
5236 self.blocks.appendAssumeCapacity(.{
5237 .name = final_name,
5238 .incoming = incoming,
5239 .instructions = .{},
5240 });
5241 return index;
5242 }
5243
5244 pub fn ret(self: *WipFunction, val: Value) Allocator.Error!Instruction.Index {
5245 assert(val.typeOfWip(self) == self.function.typeOf(self.builder).functionReturn(self.builder));
5246 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5247 return try self.addInst(null, .{ .tag = .ret, .data = @intFromEnum(val) });
5248 }
5249
5250 pub fn retVoid(self: *WipFunction) Allocator.Error!Instruction.Index {
5251 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5252 return try self.addInst(null, .{ .tag = .@"ret void", .data = undefined });
5253 }
5254
5255 pub fn br(self: *WipFunction, dest: Block.Index) Allocator.Error!Instruction.Index {
5256 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5257 const instruction = try self.addInst(null, .{ .tag = .br, .data = @intFromEnum(dest) });
5258 dest.ptr(self).branches += 1;
5259 return instruction;
5260 }
5261
5262 pub fn brCond(
5263 self: *WipFunction,
5264 cond: Value,
5265 then: Block.Index,
5266 @"else": Block.Index,
5267 weights: enum { none, unpredictable, then_likely, else_likely },
5268 ) Allocator.Error!Instruction.Index {
5269 assert(cond.typeOfWip(self) == .i1);
5270 try self.ensureUnusedExtraCapacity(1, Instruction.BrCond, 0);
5271 const instruction = try self.addInst(null, .{
5272 .tag = .br_cond,
5273 .data = self.addExtraAssumeCapacity(Instruction.BrCond{
5274 .cond = cond,
5275 .then = then,
5276 .@"else" = @"else",
5277 .weights = switch (weights) {
5278 .none => .none,
5279 .unpredictable => .unpredictable,
5280 .then_likely, .else_likely => w: {
5281 const branch_weights_str = try self.builder.metadataString("branch_weights");
5282 const unlikely_const = try self.builder.metadataConstant(try self.builder.intConst(.i32, 1));
5283 const likely_const = try self.builder.metadataConstant(try self.builder.intConst(.i32, 2000));
5284 const weight_vals: [2]Metadata = switch (weights) {
5285 .none, .unpredictable => unreachable,
5286 .then_likely => .{ likely_const, unlikely_const },
5287 .else_likely => .{ unlikely_const, likely_const },
5288 };
5289 const tuple = try self.builder.strTuple(branch_weights_str, &weight_vals);
5290 break :w @enumFromInt(@intFromEnum(tuple));
5291 },
5292 },
5293 }),
5294 });
5295 then.ptr(self).branches += 1;
5296 @"else".ptr(self).branches += 1;
5297 return instruction;
5298 }
5299
5300 pub const WipSwitch = struct {
5301 index: u32,
5302 instruction: Instruction.Index,
5303
5304 pub fn addCase(
5305 self: *WipSwitch,
5306 val: Constant,
5307 dest: Block.Index,
5308 wip: *WipFunction,
5309 ) Allocator.Error!void {
5310 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
5311 var extra = wip.extraDataTrail(Instruction.Switch, instruction.data);
5312 assert(val.typeOf(wip.builder) == extra.data.val.typeOfWip(wip));
5313 extra.trail.nextMut(extra.data.cases_len, Constant, wip)[self.index] = val;
5314 extra.trail.nextMut(extra.data.cases_len, Block.Index, wip)[self.index] = dest;
5315 self.index += 1;
5316 dest.ptr(wip).branches += 1;
5317 }
5318
5319 pub fn finish(self: WipSwitch, wip: *WipFunction) void {
5320 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
5321 const extra = wip.extraData(Instruction.Switch, instruction.data);
5322 assert(self.index == extra.cases_len);
5323 }
5324 };
5325
5326 pub fn @"switch"(
5327 self: *WipFunction,
5328 val: Value,
5329 default: Block.Index,
5330 cases_len: u32,
5331 weights: Instruction.BrCond.Weights,
5332 ) Allocator.Error!WipSwitch {
5333 try self.ensureUnusedExtraCapacity(1, Instruction.Switch, cases_len * 2);
5334 const instruction = try self.addInst(null, .{
5335 .tag = .@"switch",
5336 .data = self.addExtraAssumeCapacity(Instruction.Switch{
5337 .val = val,
5338 .default = default,
5339 .cases_len = cases_len,
5340 .weights = weights,
5341 }),
5342 });
5343 _ = self.extra.addManyAsSliceAssumeCapacity(cases_len * 2);
5344 default.ptr(self).branches += 1;
5345 return .{ .index = 0, .instruction = instruction };
5346 }
5347
5348 pub fn indirectbr(
5349 self: *WipFunction,
5350 addr: Value,
5351 targets: []const Block.Index,
5352 ) Allocator.Error!Instruction.Index {
5353 try self.ensureUnusedExtraCapacity(1, Instruction.IndirectBr, targets.len);
5354 const instruction = try self.addInst(null, .{
5355 .tag = .indirectbr,
5356 .data = self.addExtraAssumeCapacity(Instruction.IndirectBr{
5357 .addr = addr,
5358 .targets_len = @intCast(targets.len),
5359 }),
5360 });
5361 _ = self.extra.appendSliceAssumeCapacity(@ptrCast(targets));
5362 for (targets) |target| target.ptr(self).branches += 1;
5363 return instruction;
5364 }
5365
5366 pub fn @"unreachable"(self: *WipFunction) Allocator.Error!Instruction.Index {
5367 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5368 return try self.addInst(null, .{ .tag = .@"unreachable", .data = undefined });
5369 }
5370
5371 pub fn un(
5372 self: *WipFunction,
5373 tag: Instruction.Tag,
5374 val: Value,
5375 name: []const u8,
5376 ) Allocator.Error!Value {
5377 switch (tag) {
5378 .fneg,
5379 .@"fneg fast",
5380 => assert(val.typeOfWip(self).scalarType(self.builder).isFloatingPoint()),
5381 else => unreachable,
5382 }
5383 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5384 const instruction = try self.addInst(name, .{ .tag = tag, .data = @intFromEnum(val) });
5385 return instruction.toValue();
5386 }
5387
5388 pub fn not(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
5389 const ty = val.typeOfWip(self);
5390 const all_ones = try self.builder.splatValue(
5391 ty,
5392 try self.builder.intConst(ty.scalarType(self.builder), -1),
5393 );
5394 return self.bin(.xor, val, all_ones, name);
5395 }
5396
5397 pub fn neg(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
5398 return self.bin(.sub, try self.builder.zeroInitValue(val.typeOfWip(self)), val, name);
5399 }
5400
5401 pub fn bin(
5402 self: *WipFunction,
5403 tag: Instruction.Tag,
5404 lhs: Value,
5405 rhs: Value,
5406 name: []const u8,
5407 ) Allocator.Error!Value {
5408 switch (tag) {
5409 .add,
5410 .@"add nsw",
5411 .@"add nuw",
5412 .@"and",
5413 .ashr,
5414 .@"ashr exact",
5415 .fadd,
5416 .@"fadd fast",
5417 .fdiv,
5418 .@"fdiv fast",
5419 .fmul,
5420 .@"fmul fast",
5421 .frem,
5422 .@"frem fast",
5423 .fsub,
5424 .@"fsub fast",
5425 .lshr,
5426 .@"lshr exact",
5427 .mul,
5428 .@"mul nsw",
5429 .@"mul nuw",
5430 .@"or",
5431 .sdiv,
5432 .@"sdiv exact",
5433 .shl,
5434 .@"shl nsw",
5435 .@"shl nuw",
5436 .srem,
5437 .sub,
5438 .@"sub nsw",
5439 .@"sub nuw",
5440 .udiv,
5441 .@"udiv exact",
5442 .urem,
5443 .xor,
5444 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
5445 else => unreachable,
5446 }
5447 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
5448 const instruction = try self.addInst(name, .{
5449 .tag = tag,
5450 .data = self.addExtraAssumeCapacity(Instruction.Binary{ .lhs = lhs, .rhs = rhs }),
5451 });
5452 return instruction.toValue();
5453 }
5454
5455 pub fn extractElement(
5456 self: *WipFunction,
5457 val: Value,
5458 index: Value,
5459 name: []const u8,
5460 ) Allocator.Error!Value {
5461 assert(val.typeOfWip(self).isVector(self.builder));
5462 assert(index.typeOfWip(self).isInteger(self.builder));
5463 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractElement, 0);
5464 const instruction = try self.addInst(name, .{
5465 .tag = .extractelement,
5466 .data = self.addExtraAssumeCapacity(Instruction.ExtractElement{
5467 .val = val,
5468 .index = index,
5469 }),
5470 });
5471 return instruction.toValue();
5472 }
5473
5474 pub fn insertElement(
5475 self: *WipFunction,
5476 val: Value,
5477 elem: Value,
5478 index: Value,
5479 name: []const u8,
5480 ) Allocator.Error!Value {
5481 assert(val.typeOfWip(self).scalarType(self.builder) == elem.typeOfWip(self));
5482 assert(index.typeOfWip(self).isInteger(self.builder));
5483 try self.ensureUnusedExtraCapacity(1, Instruction.InsertElement, 0);
5484 const instruction = try self.addInst(name, .{
5485 .tag = .insertelement,
5486 .data = self.addExtraAssumeCapacity(Instruction.InsertElement{
5487 .val = val,
5488 .elem = elem,
5489 .index = index,
5490 }),
5491 });
5492 return instruction.toValue();
5493 }
5494
5495 pub fn shuffleVector(
5496 self: *WipFunction,
5497 lhs: Value,
5498 rhs: Value,
5499 mask: Value,
5500 name: []const u8,
5501 ) Allocator.Error!Value {
5502 assert(lhs.typeOfWip(self).isVector(self.builder));
5503 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
5504 assert(mask.typeOfWip(self).scalarType(self.builder).isInteger(self.builder));
5505 _ = try self.ensureUnusedExtraCapacity(1, Instruction.ShuffleVector, 0);
5506 const instruction = try self.addInst(name, .{
5507 .tag = .shufflevector,
5508 .data = self.addExtraAssumeCapacity(Instruction.ShuffleVector{
5509 .lhs = lhs,
5510 .rhs = rhs,
5511 .mask = mask,
5512 }),
5513 });
5514 return instruction.toValue();
5515 }
5516
5517 pub fn splatVector(
5518 self: *WipFunction,
5519 ty: Type,
5520 elem: Value,
5521 name: []const u8,
5522 ) Allocator.Error!Value {
5523 const scalar_ty = try ty.changeLength(1, self.builder);
5524 const mask_ty = try ty.changeScalar(.i32, self.builder);
5525 const poison = try self.builder.poisonValue(scalar_ty);
5526 const mask = try self.builder.splatValue(mask_ty, .@"0");
5527 const scalar = try self.insertElement(poison, elem, .@"0", name);
5528 return self.shuffleVector(scalar, poison, mask, name);
5529 }
5530
5531 pub fn extractValue(
5532 self: *WipFunction,
5533 val: Value,
5534 indices: []const u32,
5535 name: []const u8,
5536 ) Allocator.Error!Value {
5537 assert(indices.len > 0);
5538 _ = val.typeOfWip(self).childTypeAt(indices, self.builder);
5539 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractValue, indices.len);
5540 const instruction = try self.addInst(name, .{
5541 .tag = .extractvalue,
5542 .data = self.addExtraAssumeCapacity(Instruction.ExtractValue{
5543 .val = val,
5544 .indices_len = @intCast(indices.len),
5545 }),
5546 });
5547 self.extra.appendSliceAssumeCapacity(indices);
5548 return instruction.toValue();
5549 }
5550
5551 pub fn insertValue(
5552 self: *WipFunction,
5553 val: Value,
5554 elem: Value,
5555 indices: []const u32,
5556 name: []const u8,
5557 ) Allocator.Error!Value {
5558 assert(indices.len > 0);
5559 assert(val.typeOfWip(self).childTypeAt(indices, self.builder) == elem.typeOfWip(self));
5560 try self.ensureUnusedExtraCapacity(1, Instruction.InsertValue, indices.len);
5561 const instruction = try self.addInst(name, .{
5562 .tag = .insertvalue,
5563 .data = self.addExtraAssumeCapacity(Instruction.InsertValue{
5564 .val = val,
5565 .elem = elem,
5566 .indices_len = @intCast(indices.len),
5567 }),
5568 });
5569 self.extra.appendSliceAssumeCapacity(indices);
5570 return instruction.toValue();
5571 }
5572
5573 pub fn buildAggregate(
5574 self: *WipFunction,
5575 ty: Type,
5576 elems: []const Value,
5577 name: []const u8,
5578 ) Allocator.Error!Value {
5579 assert(ty.aggregateLen(self.builder) == elems.len);
5580 var cur = try self.builder.poisonValue(ty);
5581 for (elems, 0..) |elem, index|
5582 cur = try self.insertValue(cur, elem, &[_]u32{@intCast(index)}, name);
5583 return cur;
5584 }
5585
5586 pub fn alloca(
5587 self: *WipFunction,
5588 kind: Instruction.Alloca.Kind,
5589 ty: Type,
5590 len: Value,
5591 alignment: Alignment,
5592 addr_space: AddrSpace,
5593 name: []const u8,
5594 ) Allocator.Error!Value {
5595 assert(len == .none or len.typeOfWip(self).isInteger(self.builder));
5596 _ = try self.builder.ptrType(addr_space);
5597 try self.ensureUnusedExtraCapacity(1, Instruction.Alloca, 0);
5598 const instruction = try self.addInst(name, .{
5599 .tag = switch (kind) {
5600 .normal => .alloca,
5601 .inalloca => .@"alloca inalloca",
5602 },
5603 .data = self.addExtraAssumeCapacity(Instruction.Alloca{
5604 .type = ty,
5605 .len = switch (len) {
5606 .none => .@"1",
5607 else => len,
5608 },
5609 .info = .{ .alignment = alignment, .addr_space = addr_space },
5610 }),
5611 });
5612 return instruction.toValue();
5613 }
5614
5615 pub fn load(
5616 self: *WipFunction,
5617 access_kind: MemoryAccessKind,
5618 ty: Type,
5619 ptr: Value,
5620 alignment: Alignment,
5621 name: []const u8,
5622 ) Allocator.Error!Value {
5623 return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name);
5624 }
5625
5626 pub fn loadAtomic(
5627 self: *WipFunction,
5628 access_kind: MemoryAccessKind,
5629 ty: Type,
5630 ptr: Value,
5631 sync_scope: SyncScope,
5632 ordering: AtomicOrdering,
5633 alignment: Alignment,
5634 name: []const u8,
5635 ) Allocator.Error!Value {
5636 assert(ptr.typeOfWip(self).isPointer(self.builder));
5637 try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
5638 const instruction = try self.addInst(name, .{
5639 .tag = switch (ordering) {
5640 .none => .load,
5641 else => .@"load atomic",
5642 },
5643 .data = self.addExtraAssumeCapacity(Instruction.Load{
5644 .info = .{
5645 .access_kind = access_kind,
5646 .sync_scope = switch (ordering) {
5647 .none => .system,
5648 else => sync_scope,
5649 },
5650 .success_ordering = ordering,
5651 .alignment = alignment,
5652 },
5653 .type = ty,
5654 .ptr = ptr,
5655 }),
5656 });
5657 return instruction.toValue();
5658 }
5659
5660 pub fn store(
5661 self: *WipFunction,
5662 kind: MemoryAccessKind,
5663 val: Value,
5664 ptr: Value,
5665 alignment: Alignment,
5666 ) Allocator.Error!Instruction.Index {
5667 return self.storeAtomic(kind, val, ptr, .system, .none, alignment);
5668 }
5669
5670 pub fn storeAtomic(
5671 self: *WipFunction,
5672 access_kind: MemoryAccessKind,
5673 val: Value,
5674 ptr: Value,
5675 sync_scope: SyncScope,
5676 ordering: AtomicOrdering,
5677 alignment: Alignment,
5678 ) Allocator.Error!Instruction.Index {
5679 assert(ptr.typeOfWip(self).isPointer(self.builder));
5680 try self.ensureUnusedExtraCapacity(1, Instruction.Store, 0);
5681 const instruction = try self.addInst(null, .{
5682 .tag = switch (ordering) {
5683 .none => .store,
5684 else => .@"store atomic",
5685 },
5686 .data = self.addExtraAssumeCapacity(Instruction.Store{
5687 .info = .{
5688 .access_kind = access_kind,
5689 .sync_scope = switch (ordering) {
5690 .none => .system,
5691 else => sync_scope,
5692 },
5693 .success_ordering = ordering,
5694 .alignment = alignment,
5695 },
5696 .val = val,
5697 .ptr = ptr,
5698 }),
5699 });
5700 return instruction;
5701 }
5702
5703 pub fn fence(
5704 self: *WipFunction,
5705 sync_scope: SyncScope,
5706 ordering: AtomicOrdering,
5707 ) Allocator.Error!Instruction.Index {
5708 assert(ordering != .none);
5709 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5710 const instruction = try self.addInst(null, .{
5711 .tag = .fence,
5712 .data = @bitCast(MemoryAccessInfo{
5713 .sync_scope = sync_scope,
5714 .success_ordering = ordering,
5715 }),
5716 });
5717 return instruction;
5718 }
5719
5720 pub fn cmpxchg(
5721 self: *WipFunction,
5722 kind: Instruction.CmpXchg.Kind,
5723 access_kind: MemoryAccessKind,
5724 ptr: Value,
5725 cmp: Value,
5726 new: Value,
5727 sync_scope: SyncScope,
5728 success_ordering: AtomicOrdering,
5729 failure_ordering: AtomicOrdering,
5730 alignment: Alignment,
5731 name: []const u8,
5732 ) Allocator.Error!Value {
5733 assert(ptr.typeOfWip(self).isPointer(self.builder));
5734 const ty = cmp.typeOfWip(self);
5735 assert(ty == new.typeOfWip(self));
5736 assert(success_ordering != .none);
5737 assert(failure_ordering != .none);
5738
5739 _ = try self.builder.structType(.normal, &.{ ty, .i1 });
5740 try self.ensureUnusedExtraCapacity(1, Instruction.CmpXchg, 0);
5741 const instruction = try self.addInst(name, .{
5742 .tag = switch (kind) {
5743 .strong => .cmpxchg,
5744 .weak => .@"cmpxchg weak",
5745 },
5746 .data = self.addExtraAssumeCapacity(Instruction.CmpXchg{
5747 .info = .{
5748 .access_kind = access_kind,
5749 .sync_scope = sync_scope,
5750 .success_ordering = success_ordering,
5751 .failure_ordering = failure_ordering,
5752 .alignment = alignment,
5753 },
5754 .ptr = ptr,
5755 .cmp = cmp,
5756 .new = new,
5757 }),
5758 });
5759 return instruction.toValue();
5760 }
5761
5762 pub fn atomicrmw(
5763 self: *WipFunction,
5764 access_kind: MemoryAccessKind,
5765 operation: Instruction.AtomicRmw.Operation,
5766 ptr: Value,
5767 val: Value,
5768 sync_scope: SyncScope,
5769 ordering: AtomicOrdering,
5770 alignment: Alignment,
5771 name: []const u8,
5772 ) Allocator.Error!Value {
5773 assert(ptr.typeOfWip(self).isPointer(self.builder));
5774 assert(ordering != .none);
5775
5776 try self.ensureUnusedExtraCapacity(1, Instruction.AtomicRmw, 0);
5777 const instruction = try self.addInst(name, .{
5778 .tag = .atomicrmw,
5779 .data = self.addExtraAssumeCapacity(Instruction.AtomicRmw{
5780 .info = .{
5781 .access_kind = access_kind,
5782 .atomic_rmw_operation = operation,
5783 .sync_scope = sync_scope,
5784 .success_ordering = ordering,
5785 .alignment = alignment,
5786 },
5787 .ptr = ptr,
5788 .val = val,
5789 }),
5790 });
5791 return instruction.toValue();
5792 }
5793
5794 pub fn gep(
5795 self: *WipFunction,
5796 kind: Instruction.GetElementPtr.Kind,
5797 ty: Type,
5798 base: Value,
5799 indices: []const Value,
5800 name: []const u8,
5801 ) Allocator.Error!Value {
5802 const base_ty = base.typeOfWip(self);
5803 const base_is_vector = base_ty.isVector(self.builder);
5804
5805 const VectorInfo = struct {
5806 kind: Type.Vector.Kind,
5807 len: u32,
5808
5809 fn init(vector_ty: Type, builder: *const Builder) @This() {
5810 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
5811 }
5812 };
5813 var vector_info: ?VectorInfo =
5814 if (base_is_vector) VectorInfo.init(base_ty, self.builder) else null;
5815 for (indices) |index| {
5816 const index_ty = index.typeOfWip(self);
5817 switch (index_ty.tag(self.builder)) {
5818 .integer => {},
5819 .vector, .scalable_vector => {
5820 const index_info = VectorInfo.init(index_ty, self.builder);
5821 if (vector_info) |info|
5822 assert(std.meta.eql(info, index_info))
5823 else
5824 vector_info = index_info;
5825 },
5826 else => unreachable,
5827 }
5828 }
5829 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
5830 inline else => |vector_kind| _ = try self.builder.vectorType(
5831 vector_kind,
5832 info.len,
5833 base_ty,
5834 ),
5835 };
5836
5837 try self.ensureUnusedExtraCapacity(1, Instruction.GetElementPtr, indices.len);
5838 const instruction = try self.addInst(name, .{
5839 .tag = switch (kind) {
5840 .normal => .getelementptr,
5841 .inbounds => .@"getelementptr inbounds",
5842 },
5843 .data = self.addExtraAssumeCapacity(Instruction.GetElementPtr{
5844 .type = ty,
5845 .base = base,
5846 .indices_len = @intCast(indices.len),
5847 }),
5848 });
5849 self.extra.appendSliceAssumeCapacity(@ptrCast(indices));
5850 return instruction.toValue();
5851 }
5852
5853 pub fn gepStruct(
5854 self: *WipFunction,
5855 ty: Type,
5856 base: Value,
5857 index: usize,
5858 name: []const u8,
5859 ) Allocator.Error!Value {
5860 assert(ty.isStruct(self.builder));
5861 return self.gep(.inbounds, ty, base, &.{ .@"0", try self.builder.intValue(.i32, index) }, name);
5862 }
5863
5864 pub fn conv(
5865 self: *WipFunction,
5866 signedness: Instruction.Cast.Signedness,
5867 val: Value,
5868 ty: Type,
5869 name: []const u8,
5870 ) Allocator.Error!Value {
5871 const val_ty = val.typeOfWip(self);
5872 if (val_ty == ty) return val;
5873 return self.cast(self.builder.convTag(signedness, val_ty, ty), val, ty, name);
5874 }
5875
5876 pub fn cast(
5877 self: *WipFunction,
5878 tag: Instruction.Tag,
5879 val: Value,
5880 ty: Type,
5881 name: []const u8,
5882 ) Allocator.Error!Value {
5883 switch (tag) {
5884 .addrspacecast,
5885 .bitcast,
5886 .fpext,
5887 .fptosi,
5888 .fptoui,
5889 .fptrunc,
5890 .inttoptr,
5891 .ptrtoint,
5892 .sext,
5893 .sitofp,
5894 .trunc,
5895 .uitofp,
5896 .zext,
5897 => {},
5898 else => unreachable,
5899 }
5900 if (val.typeOfWip(self) == ty) return val;
5901 try self.ensureUnusedExtraCapacity(1, Instruction.Cast, 0);
5902 const instruction = try self.addInst(name, .{
5903 .tag = tag,
5904 .data = self.addExtraAssumeCapacity(Instruction.Cast{
5905 .val = val,
5906 .type = ty,
5907 }),
5908 });
5909 return instruction.toValue();
5910 }
5911
5912 pub fn icmp(
5913 self: *WipFunction,
5914 cond: IntegerCondition,
5915 lhs: Value,
5916 rhs: Value,
5917 name: []const u8,
5918 ) Allocator.Error!Value {
5919 return self.cmpTag(switch (cond) {
5920 inline else => |tag| @field(Instruction.Tag, "icmp " ++ @tagName(tag)),
5921 }, lhs, rhs, name);
5922 }
5923
5924 pub fn fcmp(
5925 self: *WipFunction,
5926 fast: FastMathKind,
5927 cond: FloatCondition,
5928 lhs: Value,
5929 rhs: Value,
5930 name: []const u8,
5931 ) Allocator.Error!Value {
5932 return self.cmpTag(switch (fast) {
5933 inline else => |fast_tag| switch (cond) {
5934 inline else => |cond_tag| @field(Instruction.Tag, "fcmp " ++ switch (fast_tag) {
5935 .normal => "",
5936 .fast => "fast ",
5937 } ++ @tagName(cond_tag)),
5938 },
5939 }, lhs, rhs, name);
5940 }
5941
5942 pub const WipPhi = struct {
5943 block: Block.Index,
5944 instruction: Instruction.Index,
5945
5946 pub fn toValue(self: WipPhi) Value {
5947 return self.instruction.toValue();
5948 }
5949
5950 pub fn finish(
5951 self: WipPhi,
5952 vals: []const Value,
5953 blocks: []const Block.Index,
5954 wip: *WipFunction,
5955 ) void {
5956 const incoming_len = self.block.ptrConst(wip).incoming;
5957 assert(vals.len == incoming_len and blocks.len == incoming_len);
5958 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
5959 var extra = wip.extraDataTrail(Instruction.Phi, instruction.data);
5960 for (vals) |val| assert(val.typeOfWip(wip) == extra.data.type);
5961 @memcpy(extra.trail.nextMut(incoming_len, Value, wip), vals);
5962 @memcpy(extra.trail.nextMut(incoming_len, Block.Index, wip), blocks);
5963 }
5964 };
5965
5966 pub fn phi(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
5967 return self.phiTag(.phi, ty, name);
5968 }
5969
5970 pub fn phiFast(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
5971 return self.phiTag(.@"phi fast", ty, name);
5972 }
5973
5974 pub fn select(
5975 self: *WipFunction,
5976 fast: FastMathKind,
5977 cond: Value,
5978 lhs: Value,
5979 rhs: Value,
5980 name: []const u8,
5981 ) Allocator.Error!Value {
5982 return self.selectTag(switch (fast) {
5983 .normal => .select,
5984 .fast => .@"select fast",
5985 }, cond, lhs, rhs, name);
5986 }
5987
5988 pub fn call(
5989 self: *WipFunction,
5990 kind: Instruction.Call.Kind,
5991 call_conv: CallConv,
5992 function_attributes: FunctionAttributes,
5993 ty: Type,
5994 callee: Value,
5995 args: []const Value,
5996 name: []const u8,
5997 ) Allocator.Error!Value {
5998 return self.callInner(kind, call_conv, function_attributes, ty, callee, args, name, false);
5999 }
6000
6001 fn callInner(
6002 self: *WipFunction,
6003 kind: Instruction.Call.Kind,
6004 call_conv: CallConv,
6005 function_attributes: FunctionAttributes,
6006 ty: Type,
6007 callee: Value,
6008 args: []const Value,
6009 name: []const u8,
6010 has_op_bundle_cold: bool,
6011 ) Allocator.Error!Value {
6012 const ret_ty = ty.functionReturn(self.builder);
6013 assert(ty.isFunction(self.builder));
6014 assert(callee.typeOfWip(self).isPointer(self.builder));
6015 const params = ty.functionParameters(self.builder);
6016 for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self));
6017
6018 try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len);
6019 const instruction = try self.addInst(switch (ret_ty) {
6020 .void => null,
6021 else => name,
6022 }, .{
6023 .tag = switch (kind) {
6024 .normal => .call,
6025 .fast => .@"call fast",
6026 .musttail => .@"musttail call",
6027 .musttail_fast => .@"musttail call fast",
6028 .notail => .@"notail call",
6029 .notail_fast => .@"notail call fast",
6030 .tail => .@"tail call",
6031 .tail_fast => .@"tail call fast",
6032 },
6033 .data = self.addExtraAssumeCapacity(Instruction.Call{
6034 .info = .{
6035 .call_conv = call_conv,
6036 .has_op_bundle_cold = has_op_bundle_cold,
6037 },
6038 .attributes = function_attributes,
6039 .ty = ty,
6040 .callee = callee,
6041 .args_len = @intCast(args.len),
6042 }),
6043 });
6044 self.extra.appendSliceAssumeCapacity(@ptrCast(args));
6045 return instruction.toValue();
6046 }
6047
6048 pub fn callAsm(
6049 self: *WipFunction,
6050 function_attributes: FunctionAttributes,
6051 ty: Type,
6052 kind: Constant.Assembly.Info,
6053 assembly: String,
6054 constraints: String,
6055 args: []const Value,
6056 name: []const u8,
6057 ) Allocator.Error!Value {
6058 const callee = try self.builder.asmValue(ty, kind, assembly, constraints);
6059 return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name);
6060 }
6061
6062 pub fn callIntrinsic(
6063 self: *WipFunction,
6064 fast: FastMathKind,
6065 function_attributes: FunctionAttributes,
6066 id: Intrinsic,
6067 overload: []const Type,
6068 args: []const Value,
6069 name: []const u8,
6070 ) Allocator.Error!Value {
6071 const intrinsic = try self.builder.getIntrinsic(id, overload);
6072 return self.call(
6073 fast.toCallKind(),
6074 CallConv.default,
6075 function_attributes,
6076 intrinsic.typeOf(self.builder),
6077 intrinsic.toValue(self.builder),
6078 args,
6079 name,
6080 );
6081 }
6082
6083 pub fn callIntrinsicAssumeCold(self: *WipFunction) Allocator.Error!Value {
6084 const intrinsic = try self.builder.getIntrinsic(.assume, &.{});
6085 return self.callInner(
6086 .normal,
6087 CallConv.default,
6088 .none,
6089 intrinsic.typeOf(self.builder),
6090 intrinsic.toValue(self.builder),
6091 &.{try self.builder.intValue(.i1, 1)},
6092 "",
6093 true,
6094 );
6095 }
6096
6097 pub fn callMemCpy(
6098 self: *WipFunction,
6099 dst: Value,
6100 dst_align: Alignment,
6101 src: Value,
6102 src_align: Alignment,
6103 len: Value,
6104 kind: MemoryAccessKind,
6105 @"inline": bool,
6106 ) Allocator.Error!Instruction.Index {
6107 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6108 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
6109 const value = try self.callIntrinsic(
6110 .normal,
6111 try self.builder.fnAttrs(&.{
6112 .none,
6113 .none,
6114 try self.builder.attrs(&dst_attrs),
6115 try self.builder.attrs(&src_attrs),
6116 }),
6117 if (@"inline") .@"memcpy.inline" else .memcpy,
6118 &.{ dst.typeOfWip(self), src.typeOfWip(self), len.typeOfWip(self) },
6119 &.{ dst, src, len, switch (kind) {
6120 .normal => Value.false,
6121 .@"volatile" => Value.true,
6122 } },
6123 undefined,
6124 );
6125 return value.unwrap().instruction;
6126 }
6127
6128 pub fn callMemSet(
6129 self: *WipFunction,
6130 dst: Value,
6131 dst_align: Alignment,
6132 val: Value,
6133 len: Value,
6134 kind: MemoryAccessKind,
6135 @"inline": bool,
6136 ) Allocator.Error!Instruction.Index {
6137 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6138 const value = try self.callIntrinsic(
6139 .normal,
6140 try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
6141 if (@"inline") .@"memset.inline" else .memset,
6142 &.{ dst.typeOfWip(self), len.typeOfWip(self) },
6143 &.{ dst, val, len, switch (kind) {
6144 .normal => Value.false,
6145 .@"volatile" => Value.true,
6146 } },
6147 undefined,
6148 );
6149 return value.unwrap().instruction;
6150 }
6151
6152 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
6153 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
6154 const instruction = try self.addInst(name, .{
6155 .tag = .va_arg,
6156 .data = self.addExtraAssumeCapacity(Instruction.VaArg{
6157 .list = list,
6158 .type = ty,
6159 }),
6160 });
6161 return instruction.toValue();
6162 }
6163
6164 pub fn debugValue(self: *WipFunction, value: Value) Allocator.Error!Metadata {
6165 if (self.strip) return .none;
6166 return switch (value.unwrap()) {
6167 .instruction => |instr_index| blk: {
6168 const gop = try self.debug_values.getOrPut(self.builder.gpa, instr_index);
6169
6170 const metadata: Metadata = @enumFromInt(Metadata.first_local_metadata + gop.index);
6171 if (!gop.found_existing) gop.key_ptr.* = instr_index;
6172
6173 break :blk metadata;
6174 },
6175 .constant => |constant| try self.builder.metadataConstant(constant),
6176 .metadata => |metadata| metadata,
6177 };
6178 }
6179
6180 pub fn finish(self: *WipFunction) Allocator.Error!void {
6181 const gpa = self.builder.gpa;
6182 const function = self.function.ptr(self.builder);
6183 const params_len = self.function.typeOf(self.builder).functionParameters(self.builder).len;
6184 const final_instructions_len = self.blocks.items.len + self.instructions.len;
6185
6186 const blocks = try gpa.alloc(Function.Block, self.blocks.items.len);
6187 errdefer gpa.free(blocks);
6188
6189 const instructions: struct {
6190 items: []Instruction.Index,
6191
6192 fn map(instructions: @This(), val: Value) Value {
6193 if (val == .none) return .none;
6194 return switch (val.unwrap()) {
6195 .instruction => |instruction| instructions.items[
6196 @intFromEnum(instruction)
6197 ].toValue(),
6198 .constant => |constant| constant.toValue(),
6199 .metadata => |metadata| metadata.toValue(),
6200 };
6201 }
6202 } = .{ .items = try gpa.alloc(Instruction.Index, self.instructions.len) };
6203 defer gpa.free(instructions.items);
6204
6205 const names = try gpa.alloc(String, final_instructions_len);
6206 errdefer gpa.free(names);
6207
6208 const value_indices = try gpa.alloc(u32, final_instructions_len);
6209 errdefer gpa.free(value_indices);
6210
6211 var debug_locations: std.AutoHashMapUnmanaged(Instruction.Index, DebugLocation) = .empty;
6212 errdefer debug_locations.deinit(gpa);
6213 try debug_locations.ensureUnusedCapacity(gpa, @intCast(self.debug_locations.count()));
6214
6215 const debug_values = try gpa.alloc(Instruction.Index, self.debug_values.count());
6216 errdefer gpa.free(debug_values);
6217
6218 var wip_extra: struct {
6219 index: Instruction.ExtraIndex = 0,
6220 items: []u32,
6221
6222 fn addExtra(wip_extra: *@This(), extra: anytype) Instruction.ExtraIndex {
6223 const result = wip_extra.index;
6224 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
6225 const value = @field(extra, field.name);
6226 wip_extra.items[wip_extra.index] = switch (field.type) {
6227 u32 => value,
6228 Alignment,
6229 AtomicOrdering,
6230 Block.Index,
6231 FunctionAttributes,
6232 Type,
6233 Value,
6234 Instruction.BrCond.Weights,
6235 => @intFromEnum(value),
6236 MemoryAccessInfo,
6237 Instruction.Alloca.Info,
6238 Instruction.Call.Info,
6239 => @bitCast(value),
6240 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
6241 };
6242 wip_extra.index += 1;
6243 }
6244 return result;
6245 }
6246
6247 fn appendSlice(wip_extra: *@This(), slice: anytype) void {
6248 if (@typeInfo(@TypeOf(slice)).pointer.child == Value)
6249 @compileError("use appendMappedValues");
6250 const data: []const u32 = @ptrCast(slice);
6251 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
6252 wip_extra.index += @intCast(data.len);
6253 }
6254
6255 fn appendMappedValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
6256 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
6257 extra.* = @intFromEnum(ctx.map(val));
6258 wip_extra.index += @intCast(vals.len);
6259 }
6260
6261 fn finish(wip_extra: *const @This()) []const u32 {
6262 assert(wip_extra.index == wip_extra.items.len);
6263 return wip_extra.items;
6264 }
6265 } = .{ .items = try gpa.alloc(u32, self.extra.items.len) };
6266 errdefer gpa.free(wip_extra.items);
6267
6268 gpa.free(function.blocks);
6269 function.blocks = &.{};
6270 gpa.free(function.names[0..function.instructions.len]);
6271 function.debug_locations.deinit(gpa);
6272 function.debug_locations = .{};
6273 gpa.free(function.debug_values);
6274 function.debug_values = &.{};
6275 gpa.free(function.extra);
6276 function.extra = &.{};
6277
6278 function.instructions.shrinkRetainingCapacity(0);
6279 try function.instructions.setCapacity(gpa, final_instructions_len);
6280 errdefer function.instructions.shrinkRetainingCapacity(0);
6281
6282 {
6283 var final_instruction_index: Instruction.Index = @enumFromInt(0);
6284 for (0..params_len) |param_index| {
6285 instructions.items[param_index] = final_instruction_index;
6286 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
6287 }
6288 for (blocks, self.blocks.items) |*final_block, current_block| {
6289 assert(current_block.incoming == current_block.branches);
6290 final_block.instruction = final_instruction_index;
6291 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
6292 for (current_block.instructions.items) |instruction| {
6293 instructions.items[@intFromEnum(instruction)] = final_instruction_index;
6294 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
6295 }
6296 }
6297 }
6298
6299 var wip_name: struct {
6300 next_name: String = @enumFromInt(0),
6301 next_unique_name: std.AutoHashMap(String, String),
6302 builder: *Builder,
6303
6304 fn map(wip_name: *@This(), name: String, sep: []const u8) Allocator.Error!String {
6305 switch (name) {
6306 .none => return .none,
6307 .empty => {
6308 assert(wip_name.next_name != .none);
6309 defer wip_name.next_name = @enumFromInt(@intFromEnum(wip_name.next_name) + 1);
6310 return wip_name.next_name;
6311 },
6312 _ => {
6313 assert(!name.isAnon());
6314 const gop = try wip_name.next_unique_name.getOrPut(name);
6315 if (!gop.found_existing) {
6316 gop.value_ptr.* = @enumFromInt(0);
6317 return name;
6318 }
6319
6320 while (true) {
6321 gop.value_ptr.* = @enumFromInt(@intFromEnum(gop.value_ptr.*) + 1);
6322 const unique_name = try wip_name.builder.fmt("{r}{s}{r}", .{
6323 name.fmt(wip_name.builder),
6324 sep,
6325 gop.value_ptr.fmt(wip_name.builder),
6326 });
6327 const unique_gop = try wip_name.next_unique_name.getOrPut(unique_name);
6328 if (!unique_gop.found_existing) {
6329 unique_gop.value_ptr.* = @enumFromInt(0);
6330 return unique_name;
6331 }
6332 }
6333 },
6334 }
6335 }
6336 } = .{
6337 .next_unique_name = std.AutoHashMap(String, String).init(gpa),
6338 .builder = self.builder,
6339 };
6340 defer wip_name.next_unique_name.deinit();
6341
6342 var value_index: u32 = 0;
6343 for (0..params_len) |param_index| {
6344 const old_argument_index: Instruction.Index = @enumFromInt(param_index);
6345 const new_argument_index: Instruction.Index = @enumFromInt(function.instructions.len);
6346 const argument = self.instructions.get(@intFromEnum(old_argument_index));
6347 assert(argument.tag == .arg);
6348 assert(argument.data == param_index);
6349 value_indices[function.instructions.len] = value_index;
6350 value_index += 1;
6351 function.instructions.appendAssumeCapacity(argument);
6352 names[@intFromEnum(new_argument_index)] = try wip_name.map(
6353 if (self.strip) .empty else self.names.items[@intFromEnum(old_argument_index)],
6354 ".",
6355 );
6356 if (self.debug_locations.get(old_argument_index)) |location| {
6357 debug_locations.putAssumeCapacity(new_argument_index, location);
6358 }
6359 if (self.debug_values.getIndex(old_argument_index)) |index| {
6360 debug_values[index] = new_argument_index;
6361 }
6362 }
6363 for (self.blocks.items) |current_block| {
6364 const new_block_index: Instruction.Index = @enumFromInt(function.instructions.len);
6365 value_indices[function.instructions.len] = value_index;
6366 function.instructions.appendAssumeCapacity(.{
6367 .tag = .block,
6368 .data = current_block.incoming,
6369 });
6370 names[@intFromEnum(new_block_index)] = try wip_name.map(current_block.name, "");
6371 for (current_block.instructions.items) |old_instruction_index| {
6372 const new_instruction_index: Instruction.Index = @enumFromInt(function.instructions.len);
6373 var instruction = self.instructions.get(@intFromEnum(old_instruction_index));
6374 switch (instruction.tag) {
6375 .add,
6376 .@"add nsw",
6377 .@"add nuw",
6378 .@"add nuw nsw",
6379 .@"and",
6380 .ashr,
6381 .@"ashr exact",
6382 .fadd,
6383 .@"fadd fast",
6384 .@"fcmp false",
6385 .@"fcmp fast false",
6386 .@"fcmp fast oeq",
6387 .@"fcmp fast oge",
6388 .@"fcmp fast ogt",
6389 .@"fcmp fast ole",
6390 .@"fcmp fast olt",
6391 .@"fcmp fast one",
6392 .@"fcmp fast ord",
6393 .@"fcmp fast true",
6394 .@"fcmp fast ueq",
6395 .@"fcmp fast uge",
6396 .@"fcmp fast ugt",
6397 .@"fcmp fast ule",
6398 .@"fcmp fast ult",
6399 .@"fcmp fast une",
6400 .@"fcmp fast uno",
6401 .@"fcmp oeq",
6402 .@"fcmp oge",
6403 .@"fcmp ogt",
6404 .@"fcmp ole",
6405 .@"fcmp olt",
6406 .@"fcmp one",
6407 .@"fcmp ord",
6408 .@"fcmp true",
6409 .@"fcmp ueq",
6410 .@"fcmp uge",
6411 .@"fcmp ugt",
6412 .@"fcmp ule",
6413 .@"fcmp ult",
6414 .@"fcmp une",
6415 .@"fcmp uno",
6416 .fdiv,
6417 .@"fdiv fast",
6418 .fmul,
6419 .@"fmul fast",
6420 .frem,
6421 .@"frem fast",
6422 .fsub,
6423 .@"fsub fast",
6424 .@"icmp eq",
6425 .@"icmp ne",
6426 .@"icmp sge",
6427 .@"icmp sgt",
6428 .@"icmp sle",
6429 .@"icmp slt",
6430 .@"icmp uge",
6431 .@"icmp ugt",
6432 .@"icmp ule",
6433 .@"icmp ult",
6434 .lshr,
6435 .@"lshr exact",
6436 .mul,
6437 .@"mul nsw",
6438 .@"mul nuw",
6439 .@"mul nuw nsw",
6440 .@"or",
6441 .sdiv,
6442 .@"sdiv exact",
6443 .shl,
6444 .@"shl nsw",
6445 .@"shl nuw",
6446 .@"shl nuw nsw",
6447 .srem,
6448 .sub,
6449 .@"sub nsw",
6450 .@"sub nuw",
6451 .@"sub nuw nsw",
6452 .udiv,
6453 .@"udiv exact",
6454 .urem,
6455 .xor,
6456 => {
6457 const extra = self.extraData(Instruction.Binary, instruction.data);
6458 instruction.data = wip_extra.addExtra(Instruction.Binary{
6459 .lhs = instructions.map(extra.lhs),
6460 .rhs = instructions.map(extra.rhs),
6461 });
6462 },
6463 .addrspacecast,
6464 .bitcast,
6465 .fpext,
6466 .fptosi,
6467 .fptoui,
6468 .fptrunc,
6469 .inttoptr,
6470 .ptrtoint,
6471 .sext,
6472 .sitofp,
6473 .trunc,
6474 .uitofp,
6475 .zext,
6476 => {
6477 const extra = self.extraData(Instruction.Cast, instruction.data);
6478 instruction.data = wip_extra.addExtra(Instruction.Cast{
6479 .val = instructions.map(extra.val),
6480 .type = extra.type,
6481 });
6482 },
6483 .alloca,
6484 .@"alloca inalloca",
6485 => {
6486 const extra = self.extraData(Instruction.Alloca, instruction.data);
6487 instruction.data = wip_extra.addExtra(Instruction.Alloca{
6488 .type = extra.type,
6489 .len = instructions.map(extra.len),
6490 .info = extra.info,
6491 });
6492 },
6493 .arg,
6494 .block,
6495 => unreachable,
6496 .atomicrmw => {
6497 const extra = self.extraData(Instruction.AtomicRmw, instruction.data);
6498 instruction.data = wip_extra.addExtra(Instruction.AtomicRmw{
6499 .info = extra.info,
6500 .ptr = instructions.map(extra.ptr),
6501 .val = instructions.map(extra.val),
6502 });
6503 },
6504 .br,
6505 .fence,
6506 .@"ret void",
6507 .@"unreachable",
6508 => {},
6509 .br_cond => {
6510 const extra = self.extraData(Instruction.BrCond, instruction.data);
6511 instruction.data = wip_extra.addExtra(Instruction.BrCond{
6512 .cond = instructions.map(extra.cond),
6513 .then = extra.then,
6514 .@"else" = extra.@"else",
6515 .weights = extra.weights,
6516 });
6517 },
6518 .call,
6519 .@"call fast",
6520 .@"musttail call",
6521 .@"musttail call fast",
6522 .@"notail call",
6523 .@"notail call fast",
6524 .@"tail call",
6525 .@"tail call fast",
6526 => {
6527 var extra = self.extraDataTrail(Instruction.Call, instruction.data);
6528 const args = extra.trail.next(extra.data.args_len, Value, self);
6529 instruction.data = wip_extra.addExtra(Instruction.Call{
6530 .info = extra.data.info,
6531 .attributes = extra.data.attributes,
6532 .ty = extra.data.ty,
6533 .callee = instructions.map(extra.data.callee),
6534 .args_len = extra.data.args_len,
6535 });
6536 wip_extra.appendMappedValues(args, instructions);
6537 },
6538 .cmpxchg,
6539 .@"cmpxchg weak",
6540 => {
6541 const extra = self.extraData(Instruction.CmpXchg, instruction.data);
6542 instruction.data = wip_extra.addExtra(Instruction.CmpXchg{
6543 .info = extra.info,
6544 .ptr = instructions.map(extra.ptr),
6545 .cmp = instructions.map(extra.cmp),
6546 .new = instructions.map(extra.new),
6547 });
6548 },
6549 .extractelement => {
6550 const extra = self.extraData(Instruction.ExtractElement, instruction.data);
6551 instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
6552 .val = instructions.map(extra.val),
6553 .index = instructions.map(extra.index),
6554 });
6555 },
6556 .extractvalue => {
6557 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
6558 const indices = extra.trail.next(extra.data.indices_len, u32, self);
6559 instruction.data = wip_extra.addExtra(Instruction.ExtractValue{
6560 .val = instructions.map(extra.data.val),
6561 .indices_len = extra.data.indices_len,
6562 });
6563 wip_extra.appendSlice(indices);
6564 },
6565 .fneg,
6566 .@"fneg fast",
6567 .ret,
6568 => instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))),
6569 .getelementptr,
6570 .@"getelementptr inbounds",
6571 => {
6572 var extra = self.extraDataTrail(Instruction.GetElementPtr, instruction.data);
6573 const indices = extra.trail.next(extra.data.indices_len, Value, self);
6574 instruction.data = wip_extra.addExtra(Instruction.GetElementPtr{
6575 .type = extra.data.type,
6576 .base = instructions.map(extra.data.base),
6577 .indices_len = extra.data.indices_len,
6578 });
6579 wip_extra.appendMappedValues(indices, instructions);
6580 },
6581 .indirectbr => {
6582 var extra = self.extraDataTrail(Instruction.IndirectBr, instruction.data);
6583 const targets = extra.trail.next(extra.data.targets_len, Block.Index, self);
6584 instruction.data = wip_extra.addExtra(Instruction.IndirectBr{
6585 .addr = instructions.map(extra.data.addr),
6586 .targets_len = extra.data.targets_len,
6587 });
6588 wip_extra.appendSlice(targets);
6589 },
6590 .insertelement => {
6591 const extra = self.extraData(Instruction.InsertElement, instruction.data);
6592 instruction.data = wip_extra.addExtra(Instruction.InsertElement{
6593 .val = instructions.map(extra.val),
6594 .elem = instructions.map(extra.elem),
6595 .index = instructions.map(extra.index),
6596 });
6597 },
6598 .insertvalue => {
6599 var extra = self.extraDataTrail(Instruction.InsertValue, instruction.data);
6600 const indices = extra.trail.next(extra.data.indices_len, u32, self);
6601 instruction.data = wip_extra.addExtra(Instruction.InsertValue{
6602 .val = instructions.map(extra.data.val),
6603 .elem = instructions.map(extra.data.elem),
6604 .indices_len = extra.data.indices_len,
6605 });
6606 wip_extra.appendSlice(indices);
6607 },
6608 .load,
6609 .@"load atomic",
6610 => {
6611 const extra = self.extraData(Instruction.Load, instruction.data);
6612 instruction.data = wip_extra.addExtra(Instruction.Load{
6613 .type = extra.type,
6614 .ptr = instructions.map(extra.ptr),
6615 .info = extra.info,
6616 });
6617 },
6618 .phi,
6619 .@"phi fast",
6620 => {
6621 const incoming_len = current_block.incoming;
6622 var extra = self.extraDataTrail(Instruction.Phi, instruction.data);
6623 const incoming_vals = extra.trail.next(incoming_len, Value, self);
6624 const incoming_blocks = extra.trail.next(incoming_len, Block.Index, self);
6625 instruction.data = wip_extra.addExtra(Instruction.Phi{
6626 .type = extra.data.type,
6627 });
6628 wip_extra.appendMappedValues(incoming_vals, instructions);
6629 wip_extra.appendSlice(incoming_blocks);
6630 },
6631 .select,
6632 .@"select fast",
6633 => {
6634 const extra = self.extraData(Instruction.Select, instruction.data);
6635 instruction.data = wip_extra.addExtra(Instruction.Select{
6636 .cond = instructions.map(extra.cond),
6637 .lhs = instructions.map(extra.lhs),
6638 .rhs = instructions.map(extra.rhs),
6639 });
6640 },
6641 .shufflevector => {
6642 const extra = self.extraData(Instruction.ShuffleVector, instruction.data);
6643 instruction.data = wip_extra.addExtra(Instruction.ShuffleVector{
6644 .lhs = instructions.map(extra.lhs),
6645 .rhs = instructions.map(extra.rhs),
6646 .mask = instructions.map(extra.mask),
6647 });
6648 },
6649 .store,
6650 .@"store atomic",
6651 => {
6652 const extra = self.extraData(Instruction.Store, instruction.data);
6653 instruction.data = wip_extra.addExtra(Instruction.Store{
6654 .val = instructions.map(extra.val),
6655 .ptr = instructions.map(extra.ptr),
6656 .info = extra.info,
6657 });
6658 },
6659 .@"switch" => {
6660 var extra = self.extraDataTrail(Instruction.Switch, instruction.data);
6661 const case_vals = extra.trail.next(extra.data.cases_len, Constant, self);
6662 const case_blocks = extra.trail.next(extra.data.cases_len, Block.Index, self);
6663 instruction.data = wip_extra.addExtra(Instruction.Switch{
6664 .val = instructions.map(extra.data.val),
6665 .default = extra.data.default,
6666 .cases_len = extra.data.cases_len,
6667 .weights = extra.data.weights,
6668 });
6669 wip_extra.appendSlice(case_vals);
6670 wip_extra.appendSlice(case_blocks);
6671 },
6672 .va_arg => {
6673 const extra = self.extraData(Instruction.VaArg, instruction.data);
6674 instruction.data = wip_extra.addExtra(Instruction.VaArg{
6675 .list = instructions.map(extra.list),
6676 .type = extra.type,
6677 });
6678 },
6679 }
6680 function.instructions.appendAssumeCapacity(instruction);
6681 names[@intFromEnum(new_instruction_index)] = try wip_name.map(if (self.strip)
6682 if (old_instruction_index.hasResultWip(self)) .empty else .none
6683 else
6684 self.names.items[@intFromEnum(old_instruction_index)], ".");
6685
6686 if (self.debug_locations.get(old_instruction_index)) |location| {
6687 debug_locations.putAssumeCapacity(new_instruction_index, location);
6688 }
6689
6690 if (self.debug_values.getIndex(old_instruction_index)) |index| {
6691 debug_values[index] = new_instruction_index;
6692 }
6693
6694 value_indices[@intFromEnum(new_instruction_index)] = value_index;
6695 if (old_instruction_index.hasResultWip(self)) value_index += 1;
6696 }
6697 }
6698
6699 assert(function.instructions.len == final_instructions_len);
6700 function.extra = wip_extra.finish();
6701 function.blocks = blocks;
6702 function.names = names.ptr;
6703 function.value_indices = value_indices.ptr;
6704 function.strip = self.strip;
6705 function.debug_locations = debug_locations;
6706 function.debug_values = debug_values;
6707 }
6708
6709 pub fn deinit(self: *WipFunction) void {
6710 self.extra.deinit(self.builder.gpa);
6711 self.debug_values.deinit(self.builder.gpa);
6712 self.debug_locations.deinit(self.builder.gpa);
6713 self.names.deinit(self.builder.gpa);
6714 self.instructions.deinit(self.builder.gpa);
6715 for (self.blocks.items) |*b| b.instructions.deinit(self.builder.gpa);
6716 self.blocks.deinit(self.builder.gpa);
6717 self.* = undefined;
6718 }
6719
6720 fn cmpTag(
6721 self: *WipFunction,
6722 tag: Instruction.Tag,
6723 lhs: Value,
6724 rhs: Value,
6725 name: []const u8,
6726 ) Allocator.Error!Value {
6727 switch (tag) {
6728 .@"fcmp false",
6729 .@"fcmp fast false",
6730 .@"fcmp fast oeq",
6731 .@"fcmp fast oge",
6732 .@"fcmp fast ogt",
6733 .@"fcmp fast ole",
6734 .@"fcmp fast olt",
6735 .@"fcmp fast one",
6736 .@"fcmp fast ord",
6737 .@"fcmp fast true",
6738 .@"fcmp fast ueq",
6739 .@"fcmp fast uge",
6740 .@"fcmp fast ugt",
6741 .@"fcmp fast ule",
6742 .@"fcmp fast ult",
6743 .@"fcmp fast une",
6744 .@"fcmp fast uno",
6745 .@"fcmp oeq",
6746 .@"fcmp oge",
6747 .@"fcmp ogt",
6748 .@"fcmp ole",
6749 .@"fcmp olt",
6750 .@"fcmp one",
6751 .@"fcmp ord",
6752 .@"fcmp true",
6753 .@"fcmp ueq",
6754 .@"fcmp uge",
6755 .@"fcmp ugt",
6756 .@"fcmp ule",
6757 .@"fcmp ult",
6758 .@"fcmp une",
6759 .@"fcmp uno",
6760 .@"icmp eq",
6761 .@"icmp ne",
6762 .@"icmp sge",
6763 .@"icmp sgt",
6764 .@"icmp sle",
6765 .@"icmp slt",
6766 .@"icmp uge",
6767 .@"icmp ugt",
6768 .@"icmp ule",
6769 .@"icmp ult",
6770 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
6771 else => unreachable,
6772 }
6773 _ = try lhs.typeOfWip(self).changeScalar(.i1, self.builder);
6774 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
6775 const instruction = try self.addInst(name, .{
6776 .tag = tag,
6777 .data = self.addExtraAssumeCapacity(Instruction.Binary{
6778 .lhs = lhs,
6779 .rhs = rhs,
6780 }),
6781 });
6782 return instruction.toValue();
6783 }
6784
6785 fn phiTag(
6786 self: *WipFunction,
6787 tag: Instruction.Tag,
6788 ty: Type,
6789 name: []const u8,
6790 ) Allocator.Error!WipPhi {
6791 switch (tag) {
6792 .phi, .@"phi fast" => assert(try ty.isSized(self.builder)),
6793 else => unreachable,
6794 }
6795 const incoming = self.cursor.block.ptrConst(self).incoming;
6796 assert(incoming > 0);
6797 try self.ensureUnusedExtraCapacity(1, Instruction.Phi, incoming * 2);
6798 const instruction = try self.addInst(name, .{
6799 .tag = tag,
6800 .data = self.addExtraAssumeCapacity(Instruction.Phi{ .type = ty }),
6801 });
6802 _ = self.extra.addManyAsSliceAssumeCapacity(incoming * 2);
6803 return .{ .block = self.cursor.block, .instruction = instruction };
6804 }
6805
6806 fn selectTag(
6807 self: *WipFunction,
6808 tag: Instruction.Tag,
6809 cond: Value,
6810 lhs: Value,
6811 rhs: Value,
6812 name: []const u8,
6813 ) Allocator.Error!Value {
6814 switch (tag) {
6815 .select, .@"select fast" => {
6816 assert(cond.typeOfWip(self).scalarType(self.builder) == .i1);
6817 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
6818 },
6819 else => unreachable,
6820 }
6821 try self.ensureUnusedExtraCapacity(1, Instruction.Select, 0);
6822 const instruction = try self.addInst(name, .{
6823 .tag = tag,
6824 .data = self.addExtraAssumeCapacity(Instruction.Select{
6825 .cond = cond,
6826 .lhs = lhs,
6827 .rhs = rhs,
6828 }),
6829 });
6830 return instruction.toValue();
6831 }
6832
6833 fn ensureUnusedExtraCapacity(
6834 self: *WipFunction,
6835 count: usize,
6836 comptime Extra: type,
6837 trail_len: usize,
6838 ) Allocator.Error!void {
6839 try self.extra.ensureUnusedCapacity(
6840 self.builder.gpa,
6841 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
6842 );
6843 }
6844
6845 fn addInst(
6846 self: *WipFunction,
6847 name: ?[]const u8,
6848 instruction: Instruction,
6849 ) Allocator.Error!Instruction.Index {
6850 const block_instructions = &self.cursor.block.ptr(self).instructions;
6851 try self.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
6852 if (!self.strip) {
6853 try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
6854 try self.debug_locations.ensureUnusedCapacity(self.builder.gpa, 1);
6855 }
6856 try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);
6857 const final_name = if (name) |n|
6858 if (self.strip) .empty else try self.builder.string(n)
6859 else
6860 .none;
6861
6862 const index: Instruction.Index = @enumFromInt(self.instructions.len);
6863 self.instructions.appendAssumeCapacity(instruction);
6864 if (!self.strip) {
6865 self.names.appendAssumeCapacity(final_name);
6866 if (block_instructions.items.len == 0 or
6867 !std.meta.eql(self.debug_location, self.prev_debug_location))
6868 {
6869 self.debug_locations.putAssumeCapacity(index, self.debug_location);
6870 self.prev_debug_location = self.debug_location;
6871 }
6872 }
6873 block_instructions.insertAssumeCapacity(self.cursor.instruction, index);
6874 self.cursor.instruction += 1;
6875 return index;
6876 }
6877
6878 fn addExtraAssumeCapacity(self: *WipFunction, extra: anytype) Instruction.ExtraIndex {
6879 const result: Instruction.ExtraIndex = @intCast(self.extra.items.len);
6880 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
6881 const value = @field(extra, field.name);
6882 self.extra.appendAssumeCapacity(switch (field.type) {
6883 u32 => value,
6884 Alignment,
6885 AtomicOrdering,
6886 Block.Index,
6887 FunctionAttributes,
6888 Type,
6889 Value,
6890 Instruction.BrCond.Weights,
6891 => @intFromEnum(value),
6892 MemoryAccessInfo,
6893 Instruction.Alloca.Info,
6894 Instruction.Call.Info,
6895 => @bitCast(value),
6896 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
6897 });
6898 }
6899 return result;
6900 }
6901
6902 const ExtraDataTrail = struct {
6903 index: Instruction.ExtraIndex,
6904
6905 fn nextMut(self: *ExtraDataTrail, len: u32, comptime Item: type, wip: *WipFunction) []Item {
6906 const items: []Item = @ptrCast(wip.extra.items[self.index..][0..len]);
6907 self.index += @intCast(len);
6908 return items;
6909 }
6910
6911 fn next(
6912 self: *ExtraDataTrail,
6913 len: u32,
6914 comptime Item: type,
6915 wip: *const WipFunction,
6916 ) []const Item {
6917 const items: []const Item = @ptrCast(wip.extra.items[self.index..][0..len]);
6918 self.index += @intCast(len);
6919 return items;
6920 }
6921 };
6922
6923 fn extraDataTrail(
6924 self: *const WipFunction,
6925 comptime T: type,
6926 index: Instruction.ExtraIndex,
6927 ) struct { data: T, trail: ExtraDataTrail } {
6928 var result: T = undefined;
6929 const fields = @typeInfo(T).@"struct".fields;
6930 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
6931 @field(result, field.name) = switch (field.type) {
6932 u32 => value,
6933 Alignment,
6934 AtomicOrdering,
6935 Block.Index,
6936 FunctionAttributes,
6937 Type,
6938 Value,
6939 Instruction.BrCond.Weights,
6940 => @enumFromInt(value),
6941 MemoryAccessInfo,
6942 Instruction.Alloca.Info,
6943 Instruction.Call.Info,
6944 => @bitCast(value),
6945 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
6946 };
6947 return .{
6948 .data = result,
6949 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
6950 };
6951 }
6952
6953 fn extraData(self: *const WipFunction, comptime T: type, index: Instruction.ExtraIndex) T {
6954 return self.extraDataTrail(T, index).data;
6955 }
6956};
6957
6958pub const FloatCondition = enum(u4) {
6959 oeq = 1,
6960 ogt = 2,
6961 oge = 3,
6962 olt = 4,
6963 ole = 5,
6964 one = 6,
6965 ord = 7,
6966 uno = 8,
6967 ueq = 9,
6968 ugt = 10,
6969 uge = 11,
6970 ult = 12,
6971 ule = 13,
6972 une = 14,
6973};
6974
6975pub const IntegerCondition = enum(u6) {
6976 eq = 32,
6977 ne = 33,
6978 ugt = 34,
6979 uge = 35,
6980 ult = 36,
6981 ule = 37,
6982 sgt = 38,
6983 sge = 39,
6984 slt = 40,
6985 sle = 41,
6986};
6987
6988pub const MemoryAccessKind = enum(u1) {
6989 normal,
6990 @"volatile",
6991
6992 pub fn format(
6993 self: MemoryAccessKind,
6994 comptime prefix: []const u8,
6995 _: std.fmt.FormatOptions,
6996 writer: anytype,
6997 ) @TypeOf(writer).Error!void {
6998 if (self != .normal) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
6999 }
7000};
7001
7002pub const SyncScope = enum(u1) {
7003 singlethread,
7004 system,
7005
7006 pub fn format(
7007 self: SyncScope,
7008 comptime prefix: []const u8,
7009 _: std.fmt.FormatOptions,
7010 writer: anytype,
7011 ) @TypeOf(writer).Error!void {
7012 if (self != .system) try writer.print(
7013 \\{s}syncscope("{s}")
7014 , .{ prefix, @tagName(self) });
7015 }
7016};
7017
7018pub const AtomicOrdering = enum(u3) {
7019 none = 0,
7020 unordered = 1,
7021 monotonic = 2,
7022 acquire = 3,
7023 release = 4,
7024 acq_rel = 5,
7025 seq_cst = 6,
7026
7027 pub fn format(
7028 self: AtomicOrdering,
7029 comptime prefix: []const u8,
7030 _: std.fmt.FormatOptions,
7031 writer: anytype,
7032 ) @TypeOf(writer).Error!void {
7033 if (self != .none) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
7034 }
7035};
7036
7037const MemoryAccessInfo = packed struct(u32) {
7038 access_kind: MemoryAccessKind = .normal,
7039 atomic_rmw_operation: Function.Instruction.AtomicRmw.Operation = .none,
7040 sync_scope: SyncScope,
7041 success_ordering: AtomicOrdering,
7042 failure_ordering: AtomicOrdering = .none,
7043 alignment: Alignment = .default,
7044 _: u13 = undefined,
7045};
7046
7047pub const FastMath = packed struct(u8) {
7048 unsafe_algebra: bool = false, // Legacy
7049 nnan: bool = false,
7050 ninf: bool = false,
7051 nsz: bool = false,
7052 arcp: bool = false,
7053 contract: bool = false,
7054 afn: bool = false,
7055 reassoc: bool = false,
7056
7057 pub const fast = FastMath{
7058 .nnan = true,
7059 .ninf = true,
7060 .nsz = true,
7061 .arcp = true,
7062 .contract = true,
7063 .afn = true,
7064 .reassoc = true,
7065 };
7066};
7067
7068pub const FastMathKind = enum {
7069 normal,
7070 fast,
7071
7072 pub fn toCallKind(self: FastMathKind) Function.Instruction.Call.Kind {
7073 return switch (self) {
7074 .normal => .normal,
7075 .fast => .fast,
7076 };
7077 }
7078};
7079
7080pub const Constant = enum(u32) {
7081 false,
7082 true,
7083 @"0",
7084 @"1",
7085 none,
7086 no_init = (1 << 30) - 1,
7087 _,
7088
7089 const first_global: Constant = @enumFromInt(1 << 29);
7090
7091 pub const Tag = enum(u7) {
7092 positive_integer,
7093 negative_integer,
7094 half,
7095 bfloat,
7096 float,
7097 double,
7098 fp128,
7099 x86_fp80,
7100 ppc_fp128,
7101 null,
7102 none,
7103 structure,
7104 packed_structure,
7105 array,
7106 string,
7107 vector,
7108 splat,
7109 zeroinitializer,
7110 undef,
7111 poison,
7112 blockaddress,
7113 dso_local_equivalent,
7114 no_cfi,
7115 trunc,
7116 ptrtoint,
7117 inttoptr,
7118 bitcast,
7119 addrspacecast,
7120 getelementptr,
7121 @"getelementptr inbounds",
7122 add,
7123 @"add nsw",
7124 @"add nuw",
7125 sub,
7126 @"sub nsw",
7127 @"sub nuw",
7128 shl,
7129 xor,
7130 @"asm",
7131 @"asm sideeffect",
7132 @"asm alignstack",
7133 @"asm sideeffect alignstack",
7134 @"asm inteldialect",
7135 @"asm sideeffect inteldialect",
7136 @"asm alignstack inteldialect",
7137 @"asm sideeffect alignstack inteldialect",
7138 @"asm unwind",
7139 @"asm sideeffect unwind",
7140 @"asm alignstack unwind",
7141 @"asm sideeffect alignstack unwind",
7142 @"asm inteldialect unwind",
7143 @"asm sideeffect inteldialect unwind",
7144 @"asm alignstack inteldialect unwind",
7145 @"asm sideeffect alignstack inteldialect unwind",
7146
7147 pub fn toBinaryOpcode(self: Tag) BinaryOpcode {
7148 return switch (self) {
7149 .add,
7150 .@"add nsw",
7151 .@"add nuw",
7152 => .add,
7153 .sub,
7154 .@"sub nsw",
7155 .@"sub nuw",
7156 => .sub,
7157 .shl => .shl,
7158 .xor => .xor,
7159 else => unreachable,
7160 };
7161 }
7162
7163 pub fn toCastOpcode(self: Tag) CastOpcode {
7164 return switch (self) {
7165 .trunc => .trunc,
7166 .ptrtoint => .ptrtoint,
7167 .inttoptr => .inttoptr,
7168 .bitcast => .bitcast,
7169 .addrspacecast => .addrspacecast,
7170 else => unreachable,
7171 };
7172 }
7173 };
7174
7175 pub const Item = struct {
7176 tag: Tag,
7177 data: ExtraIndex,
7178
7179 const ExtraIndex = u32;
7180 };
7181
7182 pub const Integer = packed struct(u64) {
7183 type: Type,
7184 limbs_len: u32,
7185
7186 pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
7187 };
7188
7189 pub const Double = struct {
7190 lo: u32,
7191 hi: u32,
7192 };
7193
7194 pub const Fp80 = struct {
7195 lo_lo: u32,
7196 lo_hi: u32,
7197 hi: u32,
7198 };
7199
7200 pub const Fp128 = struct {
7201 lo_lo: u32,
7202 lo_hi: u32,
7203 hi_lo: u32,
7204 hi_hi: u32,
7205 };
7206
7207 pub const Aggregate = struct {
7208 type: Type,
7209 //fields: [type.aggregateLen(builder)]Constant,
7210 };
7211
7212 pub const Splat = extern struct {
7213 type: Type,
7214 value: Constant,
7215 };
7216
7217 pub const BlockAddress = extern struct {
7218 function: Function.Index,
7219 block: Function.Block.Index,
7220 };
7221
7222 pub const Cast = extern struct {
7223 val: Constant,
7224 type: Type,
7225
7226 pub const Signedness = enum { unsigned, signed, unneeded };
7227 };
7228
7229 pub const GetElementPtr = struct {
7230 type: Type,
7231 base: Constant,
7232 info: Info,
7233 //indices: [info.indices_len]Constant,
7234
7235 pub const Kind = enum { normal, inbounds };
7236 pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };
7237 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
7238 };
7239
7240 pub const Binary = extern struct {
7241 lhs: Constant,
7242 rhs: Constant,
7243 };
7244
7245 pub const Assembly = extern struct {
7246 type: Type,
7247 assembly: String,
7248 constraints: String,
7249
7250 pub const Info = packed struct {
7251 sideeffect: bool = false,
7252 alignstack: bool = false,
7253 inteldialect: bool = false,
7254 unwind: bool = false,
7255 };
7256 };
7257
7258 pub fn unwrap(self: Constant) union(enum) {
7259 constant: u30,
7260 global: Global.Index,
7261 } {
7262 return if (@intFromEnum(self) < @intFromEnum(first_global))
7263 .{ .constant = @intCast(@intFromEnum(self)) }
7264 else
7265 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
7266 }
7267
7268 pub fn toValue(self: Constant) Value {
7269 return @enumFromInt(Value.first_constant + @intFromEnum(self));
7270 }
7271
7272 pub fn typeOf(self: Constant, builder: *Builder) Type {
7273 switch (self.unwrap()) {
7274 .constant => |constant| {
7275 const item = builder.constant_items.get(constant);
7276 return switch (item.tag) {
7277 .positive_integer,
7278 .negative_integer,
7279 => @as(
7280 *align(@alignOf(std.math.big.Limb)) Integer,
7281 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
7282 ).type,
7283 .half => .half,
7284 .bfloat => .bfloat,
7285 .float => .float,
7286 .double => .double,
7287 .fp128 => .fp128,
7288 .x86_fp80 => .x86_fp80,
7289 .ppc_fp128 => .ppc_fp128,
7290 .null,
7291 .none,
7292 .zeroinitializer,
7293 .undef,
7294 .poison,
7295 => @enumFromInt(item.data),
7296 .structure,
7297 .packed_structure,
7298 .array,
7299 .vector,
7300 => builder.constantExtraData(Aggregate, item.data).type,
7301 .splat => builder.constantExtraData(Splat, item.data).type,
7302 .string => builder.arrayTypeAssumeCapacity(
7303 @as(String, @enumFromInt(item.data)).slice(builder).?.len,
7304 .i8,
7305 ),
7306 .blockaddress => builder.ptrTypeAssumeCapacity(
7307 builder.constantExtraData(BlockAddress, item.data)
7308 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
7309 ),
7310 .dso_local_equivalent,
7311 .no_cfi,
7312 => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
7313 .ptrConst(builder).global.ptrConst(builder).addr_space),
7314 .trunc,
7315 .ptrtoint,
7316 .inttoptr,
7317 .bitcast,
7318 .addrspacecast,
7319 => builder.constantExtraData(Cast, item.data).type,
7320 .getelementptr,
7321 .@"getelementptr inbounds",
7322 => {
7323 var extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
7324 const indices =
7325 extra.trail.next(extra.data.info.indices_len, Constant, builder);
7326 const base_ty = extra.data.base.typeOf(builder);
7327 if (!base_ty.isVector(builder)) for (indices) |index| {
7328 const index_ty = index.typeOf(builder);
7329 if (!index_ty.isVector(builder)) continue;
7330 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
7331 };
7332 return base_ty;
7333 },
7334 .add,
7335 .@"add nsw",
7336 .@"add nuw",
7337 .sub,
7338 .@"sub nsw",
7339 .@"sub nuw",
7340 .shl,
7341 .xor,
7342 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
7343 .@"asm",
7344 .@"asm sideeffect",
7345 .@"asm alignstack",
7346 .@"asm sideeffect alignstack",
7347 .@"asm inteldialect",
7348 .@"asm sideeffect inteldialect",
7349 .@"asm alignstack inteldialect",
7350 .@"asm sideeffect alignstack inteldialect",
7351 .@"asm unwind",
7352 .@"asm sideeffect unwind",
7353 .@"asm alignstack unwind",
7354 .@"asm sideeffect alignstack unwind",
7355 .@"asm inteldialect unwind",
7356 .@"asm sideeffect inteldialect unwind",
7357 .@"asm alignstack inteldialect unwind",
7358 .@"asm sideeffect alignstack inteldialect unwind",
7359 => .ptr,
7360 };
7361 },
7362 .global => |global| return builder.ptrTypeAssumeCapacity(
7363 global.ptrConst(builder).addr_space,
7364 ),
7365 }
7366 }
7367
7368 pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
7369 switch (self.unwrap()) {
7370 .constant => |constant| {
7371 const item = builder.constant_items.get(constant);
7372 return switch (item.tag) {
7373 .positive_integer => {
7374 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
7375 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
7376 const limbs = builder.constant_limbs
7377 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
7378 return std.mem.eql(std.math.big.Limb, limbs, &.{0});
7379 },
7380 .half, .bfloat, .float => item.data == 0,
7381 .double => {
7382 const extra = builder.constantExtraData(Constant.Double, item.data);
7383 return extra.lo == 0 and extra.hi == 0;
7384 },
7385 .fp128, .ppc_fp128 => {
7386 const extra = builder.constantExtraData(Constant.Fp128, item.data);
7387 return extra.lo_lo == 0 and extra.lo_hi == 0 and
7388 extra.hi_lo == 0 and extra.hi_hi == 0;
7389 },
7390 .x86_fp80 => {
7391 const extra = builder.constantExtraData(Constant.Fp80, item.data);
7392 return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
7393 },
7394 .vector => {
7395 var extra = builder.constantExtraDataTrail(Aggregate, item.data);
7396 const len: u32 = @intCast(extra.data.type.aggregateLen(builder));
7397 const vals = extra.trail.next(len, Constant, builder);
7398 for (vals) |val| if (!val.isZeroInit(builder)) return false;
7399 return true;
7400 },
7401 .null, .zeroinitializer => true,
7402 else => false,
7403 };
7404 },
7405 .global => return false,
7406 }
7407 }
7408
7409 pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
7410 var cur = self;
7411 while (true) switch (cur.unwrap()) {
7412 .constant => |constant| {
7413 const item = builder.constant_items.get(constant);
7414 switch (item.tag) {
7415 .ptrtoint,
7416 .inttoptr,
7417 .bitcast,
7418 => cur = builder.constantExtraData(Cast, item.data).val,
7419 .getelementptr => cur = builder.constantExtraData(GetElementPtr, item.data).base,
7420 .add => {
7421 const extra = builder.constantExtraData(Binary, item.data);
7422 const lhs_base = extra.lhs.getBase(builder);
7423 const rhs_base = extra.rhs.getBase(builder);
7424 return if (lhs_base != .none and rhs_base != .none)
7425 .none
7426 else if (lhs_base != .none) lhs_base else rhs_base;
7427 },
7428 .sub => {
7429 const extra = builder.constantExtraData(Binary, item.data);
7430 if (extra.rhs.getBase(builder) != .none) return .none;
7431 cur = extra.lhs;
7432 },
7433 else => return .none,
7434 }
7435 },
7436 .global => |global| switch (global.ptrConst(builder).kind) {
7437 .alias => |alias| cur = alias.ptrConst(builder).aliasee,
7438 .variable, .function => return global,
7439 .replaced => unreachable,
7440 },
7441 };
7442 }
7443
7444 const FormatData = struct {
7445 constant: Constant,
7446 builder: *Builder,
7447 };
7448 fn format(
7449 data: FormatData,
7450 comptime fmt_str: []const u8,
7451 _: std.fmt.FormatOptions,
7452 writer: anytype,
7453 ) @TypeOf(writer).Error!void {
7454 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
7455 @compileError("invalid format string: '" ++ fmt_str ++ "'");
7456 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
7457 if (data.constant == .no_init) return;
7458 try writer.writeByte(',');
7459 }
7460 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
7461 if (data.constant == .no_init) return;
7462 try writer.writeByte(' ');
7463 }
7464 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
7465 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
7466 assert(data.constant != .no_init);
7467 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
7468 switch (data.constant.unwrap()) {
7469 .constant => |constant| {
7470 const item = data.builder.constant_items.get(constant);
7471 switch (item.tag) {
7472 .positive_integer,
7473 .negative_integer,
7474 => |tag| {
7475 const extra: *align(@alignOf(std.math.big.Limb)) const Integer =
7476 @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
7477 const limbs = data.builder.constant_limbs
7478 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
7479 const bigint: std.math.big.int.Const = .{
7480 .limbs = limbs,
7481 .positive = switch (tag) {
7482 .positive_integer => true,
7483 .negative_integer => false,
7484 else => unreachable,
7485 },
7486 };
7487 const ExpectedContents = extern struct {
7488 const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
7489 string: [
7490 (std.math.big.int.Const{
7491 .limbs = &([1]std.math.big.Limb{
7492 std.math.maxInt(std.math.big.Limb),
7493 } ** expected_limbs),
7494 .positive = false,
7495 }).sizeInBaseUpperBound(10)
7496 ]u8,
7497 limbs: [
7498 std.math.big.int.calcToStringLimbsBufferLen(expected_limbs, 10)
7499 ]std.math.big.Limb,
7500 };
7501 var stack align(@alignOf(ExpectedContents)) =
7502 std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
7503 const allocator = stack.get();
7504 const str = try bigint.toStringAlloc(allocator, 10, undefined);
7505 defer allocator.free(str);
7506 try writer.writeAll(str);
7507 },
7508 .half,
7509 .bfloat,
7510 => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
7511 .half => 'H',
7512 .bfloat => 'R',
7513 else => unreachable,
7514 }), item.data >> switch (tag) {
7515 .half => 0,
7516 .bfloat => 16,
7517 else => unreachable,
7518 } }),
7519 .float => {
7520 const Float = struct {
7521 fn Repr(comptime T: type) type {
7522 return packed struct(std.meta.Int(.unsigned, @bitSizeOf(T))) {
7523 mantissa: std.meta.Int(.unsigned, std.math.floatMantissaBits(T)),
7524 exponent: std.meta.Int(.unsigned, std.math.floatExponentBits(T)),
7525 sign: u1,
7526 };
7527 }
7528 };
7529 const Mantissa64 = std.meta.FieldType(Float.Repr(f64), .mantissa);
7530 const Exponent32 = std.meta.FieldType(Float.Repr(f32), .exponent);
7531 const Exponent64 = std.meta.FieldType(Float.Repr(f64), .exponent);
7532
7533 const repr: Float.Repr(f32) = @bitCast(item.data);
7534 const denormal_shift = switch (repr.exponent) {
7535 std.math.minInt(Exponent32) => @as(
7536 std.math.Log2Int(Mantissa64),
7537 @clz(repr.mantissa),
7538 ) + 1,
7539 else => 0,
7540 };
7541 try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){
7542 .mantissa = std.math.shl(
7543 Mantissa64,
7544 repr.mantissa,
7545 std.math.floatMantissaBits(f64) - std.math.floatMantissaBits(f32) +
7546 denormal_shift,
7547 ),
7548 .exponent = switch (repr.exponent) {
7549 std.math.minInt(Exponent32) => if (repr.mantissa > 0)
7550 @as(Exponent64, std.math.floatExponentMin(f32) +
7551 std.math.floatExponentMax(f64)) - denormal_shift
7552 else
7553 std.math.minInt(Exponent64),
7554 else => @as(Exponent64, repr.exponent) +
7555 (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
7556 std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),
7557 },
7558 .sign = repr.sign,
7559 }))});
7560 },
7561 .double => {
7562 const extra = data.builder.constantExtraData(Double, item.data);
7563 try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
7564 },
7565 .fp128,
7566 .ppc_fp128,
7567 => |tag| {
7568 const extra = data.builder.constantExtraData(Fp128, item.data);
7569 try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
7570 @as(u8, switch (tag) {
7571 .fp128 => 'L',
7572 .ppc_fp128 => 'M',
7573 else => unreachable,
7574 }),
7575 extra.lo_hi,
7576 extra.lo_lo,
7577 extra.hi_hi,
7578 extra.hi_lo,
7579 });
7580 },
7581 .x86_fp80 => {
7582 const extra = data.builder.constantExtraData(Fp80, item.data);
7583 try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
7584 extra.hi, extra.lo_hi, extra.lo_lo,
7585 });
7586 },
7587 .null,
7588 .none,
7589 .zeroinitializer,
7590 .undef,
7591 .poison,
7592 => |tag| try writer.writeAll(@tagName(tag)),
7593 .structure,
7594 .packed_structure,
7595 .array,
7596 .vector,
7597 => |tag| {
7598 var extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
7599 const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder));
7600 const vals = extra.trail.next(len, Constant, data.builder);
7601 try writer.writeAll(switch (tag) {
7602 .structure => "{ ",
7603 .packed_structure => "<{ ",
7604 .array => "[",
7605 .vector => "<",
7606 else => unreachable,
7607 });
7608 for (vals, 0..) |val, index| {
7609 if (index > 0) try writer.writeAll(", ");
7610 try writer.print("{%}", .{val.fmt(data.builder)});
7611 }
7612 try writer.writeAll(switch (tag) {
7613 .structure => " }",
7614 .packed_structure => " }>",
7615 .array => "]",
7616 .vector => ">",
7617 else => unreachable,
7618 });
7619 },
7620 .splat => {
7621 const extra = data.builder.constantExtraData(Splat, item.data);
7622 const len = extra.type.vectorLen(data.builder);
7623 try writer.writeByte('<');
7624 for (0..len) |index| {
7625 if (index > 0) try writer.writeAll(", ");
7626 try writer.print("{%}", .{extra.value.fmt(data.builder)});
7627 }
7628 try writer.writeByte('>');
7629 },
7630 .string => try writer.print("c{\"}", .{
7631 @as(String, @enumFromInt(item.data)).fmt(data.builder),
7632 }),
7633 .blockaddress => |tag| {
7634 const extra = data.builder.constantExtraData(BlockAddress, item.data);
7635 const function = extra.function.ptrConst(data.builder);
7636 try writer.print("{s}({}, {})", .{
7637 @tagName(tag),
7638 function.global.fmt(data.builder),
7639 extra.block.toInst(function).fmt(extra.function, data.builder),
7640 });
7641 },
7642 .dso_local_equivalent,
7643 .no_cfi,
7644 => |tag| {
7645 const function: Function.Index = @enumFromInt(item.data);
7646 try writer.print("{s} {}", .{
7647 @tagName(tag),
7648 function.ptrConst(data.builder).global.fmt(data.builder),
7649 });
7650 },
7651 .trunc,
7652 .ptrtoint,
7653 .inttoptr,
7654 .bitcast,
7655 .addrspacecast,
7656 => |tag| {
7657 const extra = data.builder.constantExtraData(Cast, item.data);
7658 try writer.print("{s} ({%} to {%})", .{
7659 @tagName(tag),
7660 extra.val.fmt(data.builder),
7661 extra.type.fmt(data.builder),
7662 });
7663 },
7664 .getelementptr,
7665 .@"getelementptr inbounds",
7666 => |tag| {
7667 var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
7668 const indices =
7669 extra.trail.next(extra.data.info.indices_len, Constant, data.builder);
7670 try writer.print("{s} ({%}, {%}", .{
7671 @tagName(tag),
7672 extra.data.type.fmt(data.builder),
7673 extra.data.base.fmt(data.builder),
7674 });
7675 for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
7676 try writer.writeByte(')');
7677 },
7678 .add,
7679 .@"add nsw",
7680 .@"add nuw",
7681 .sub,
7682 .@"sub nsw",
7683 .@"sub nuw",
7684 .shl,
7685 .xor,
7686 => |tag| {
7687 const extra = data.builder.constantExtraData(Binary, item.data);
7688 try writer.print("{s} ({%}, {%})", .{
7689 @tagName(tag),
7690 extra.lhs.fmt(data.builder),
7691 extra.rhs.fmt(data.builder),
7692 });
7693 },
7694 .@"asm",
7695 .@"asm sideeffect",
7696 .@"asm alignstack",
7697 .@"asm sideeffect alignstack",
7698 .@"asm inteldialect",
7699 .@"asm sideeffect inteldialect",
7700 .@"asm alignstack inteldialect",
7701 .@"asm sideeffect alignstack inteldialect",
7702 .@"asm unwind",
7703 .@"asm sideeffect unwind",
7704 .@"asm alignstack unwind",
7705 .@"asm sideeffect alignstack unwind",
7706 .@"asm inteldialect unwind",
7707 .@"asm sideeffect inteldialect unwind",
7708 .@"asm alignstack inteldialect unwind",
7709 .@"asm sideeffect alignstack inteldialect unwind",
7710 => |tag| {
7711 const extra = data.builder.constantExtraData(Assembly, item.data);
7712 try writer.print("{s} {\"}, {\"}", .{
7713 @tagName(tag),
7714 extra.assembly.fmt(data.builder),
7715 extra.constraints.fmt(data.builder),
7716 });
7717 },
7718 }
7719 },
7720 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
7721 }
7722 }
7723 pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
7724 return .{ .data = .{ .constant = self, .builder = builder } };
7725 }
7726};
7727
7728pub const Value = enum(u32) {
7729 none = std.math.maxInt(u31),
7730 false = first_constant + @intFromEnum(Constant.false),
7731 true = first_constant + @intFromEnum(Constant.true),
7732 @"0" = first_constant + @intFromEnum(Constant.@"0"),
7733 @"1" = first_constant + @intFromEnum(Constant.@"1"),
7734 _,
7735
7736 const first_constant = 1 << 30;
7737 const first_metadata = 1 << 31;
7738
7739 pub fn unwrap(self: Value) union(enum) {
7740 instruction: Function.Instruction.Index,
7741 constant: Constant,
7742 metadata: Metadata,
7743 } {
7744 return if (@intFromEnum(self) < first_constant)
7745 .{ .instruction = @enumFromInt(@intFromEnum(self)) }
7746 else if (@intFromEnum(self) < first_metadata)
7747 .{ .constant = @enumFromInt(@intFromEnum(self) - first_constant) }
7748 else
7749 .{ .metadata = @enumFromInt(@intFromEnum(self) - first_metadata) };
7750 }
7751
7752 pub fn typeOfWip(self: Value, wip: *const WipFunction) Type {
7753 return switch (self.unwrap()) {
7754 .instruction => |instruction| instruction.typeOfWip(wip),
7755 .constant => |constant| constant.typeOf(wip.builder),
7756 .metadata => .metadata,
7757 };
7758 }
7759
7760 pub fn typeOf(self: Value, function: Function.Index, builder: *Builder) Type {
7761 return switch (self.unwrap()) {
7762 .instruction => |instruction| instruction.typeOf(function, builder),
7763 .constant => |constant| constant.typeOf(builder),
7764 .metadata => .metadata,
7765 };
7766 }
7767
7768 pub fn toConst(self: Value) ?Constant {
7769 return switch (self.unwrap()) {
7770 .instruction, .metadata => null,
7771 .constant => |constant| constant,
7772 };
7773 }
7774
7775 const FormatData = struct {
7776 value: Value,
7777 function: Function.Index,
7778 builder: *Builder,
7779 };
7780 fn format(
7781 data: FormatData,
7782 comptime fmt_str: []const u8,
7783 fmt_opts: std.fmt.FormatOptions,
7784 writer: anytype,
7785 ) @TypeOf(writer).Error!void {
7786 switch (data.value.unwrap()) {
7787 .instruction => |instruction| try Function.Instruction.Index.format(.{
7788 .instruction = instruction,
7789 .function = data.function,
7790 .builder = data.builder,
7791 }, fmt_str, fmt_opts, writer),
7792 .constant => |constant| try Constant.format(.{
7793 .constant = constant,
7794 .builder = data.builder,
7795 }, fmt_str, fmt_opts, writer),
7796 .metadata => unreachable,
7797 }
7798 }
7799 pub fn fmt(self: Value, function: Function.Index, builder: *Builder) std.fmt.Formatter(format) {
7800 return .{ .data = .{ .value = self, .function = function, .builder = builder } };
7801 }
7802};
7803
7804pub const MetadataString = enum(u32) {
7805 none = 0,
7806 _,
7807
7808 pub fn slice(self: MetadataString, builder: *const Builder) []const u8 {
7809 const index = @intFromEnum(self);
7810 const start = builder.metadata_string_indices.items[index];
7811 const end = builder.metadata_string_indices.items[index + 1];
7812 return builder.metadata_string_bytes.items[start..end];
7813 }
7814
7815 const Adapter = struct {
7816 builder: *const Builder,
7817 pub fn hash(_: Adapter, key: []const u8) u32 {
7818 return @truncate(std.hash.Wyhash.hash(0, key));
7819 }
7820 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
7821 const rhs_metadata_string: MetadataString = @enumFromInt(rhs_index);
7822 return std.mem.eql(u8, lhs_key, rhs_metadata_string.slice(ctx.builder));
7823 }
7824 };
7825
7826 const FormatData = struct {
7827 metadata_string: MetadataString,
7828 builder: *const Builder,
7829 };
7830 fn format(
7831 data: FormatData,
7832 comptime _: []const u8,
7833 _: std.fmt.FormatOptions,
7834 writer: anytype,
7835 ) @TypeOf(writer).Error!void {
7836 try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, writer);
7837 }
7838 fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(format) {
7839 return .{ .data = .{ .metadata_string = self, .builder = builder } };
7840 }
7841};
7842
7843pub const Metadata = enum(u32) {
7844 none = 0,
7845 empty_tuple = 1,
7846 _,
7847
7848 const first_forward_reference = 1 << 29;
7849 const first_local_metadata = 1 << 30;
7850
7851 pub const Tag = enum(u6) {
7852 none,
7853 file,
7854 compile_unit,
7855 @"compile_unit optimized",
7856 subprogram,
7857 @"subprogram local",
7858 @"subprogram definition",
7859 @"subprogram local definition",
7860 @"subprogram optimized",
7861 @"subprogram optimized local",
7862 @"subprogram optimized definition",
7863 @"subprogram optimized local definition",
7864 lexical_block,
7865 location,
7866 basic_bool_type,
7867 basic_unsigned_type,
7868 basic_signed_type,
7869 basic_float_type,
7870 composite_struct_type,
7871 composite_union_type,
7872 composite_enumeration_type,
7873 composite_array_type,
7874 composite_vector_type,
7875 derived_pointer_type,
7876 derived_member_type,
7877 subroutine_type,
7878 enumerator_unsigned,
7879 enumerator_signed_positive,
7880 enumerator_signed_negative,
7881 subrange,
7882 tuple,
7883 str_tuple,
7884 module_flag,
7885 expression,
7886 local_var,
7887 parameter,
7888 global_var,
7889 @"global_var local",
7890 global_var_expression,
7891 constant,
7892
7893 pub fn isInline(tag: Tag) bool {
7894 return switch (tag) {
7895 .none,
7896 .expression,
7897 .constant,
7898 => true,
7899 .file,
7900 .compile_unit,
7901 .@"compile_unit optimized",
7902 .subprogram,
7903 .@"subprogram local",
7904 .@"subprogram definition",
7905 .@"subprogram local definition",
7906 .@"subprogram optimized",
7907 .@"subprogram optimized local",
7908 .@"subprogram optimized definition",
7909 .@"subprogram optimized local definition",
7910 .lexical_block,
7911 .location,
7912 .basic_bool_type,
7913 .basic_unsigned_type,
7914 .basic_signed_type,
7915 .basic_float_type,
7916 .composite_struct_type,
7917 .composite_union_type,
7918 .composite_enumeration_type,
7919 .composite_array_type,
7920 .composite_vector_type,
7921 .derived_pointer_type,
7922 .derived_member_type,
7923 .subroutine_type,
7924 .enumerator_unsigned,
7925 .enumerator_signed_positive,
7926 .enumerator_signed_negative,
7927 .subrange,
7928 .tuple,
7929 .str_tuple,
7930 .module_flag,
7931 .local_var,
7932 .parameter,
7933 .global_var,
7934 .@"global_var local",
7935 .global_var_expression,
7936 => false,
7937 };
7938 }
7939 };
7940
7941 pub fn isInline(self: Metadata, builder: *const Builder) bool {
7942 return builder.metadata_items.items(.tag)[@intFromEnum(self)].isInline();
7943 }
7944
7945 pub fn unwrap(self: Metadata, builder: *const Builder) Metadata {
7946 var metadata = self;
7947 while (@intFromEnum(metadata) >= Metadata.first_forward_reference and
7948 @intFromEnum(metadata) < Metadata.first_local_metadata)
7949 {
7950 const index = @intFromEnum(metadata) - Metadata.first_forward_reference;
7951 metadata = builder.metadata_forward_references.items[index];
7952 assert(metadata != .none);
7953 }
7954 return metadata;
7955 }
7956
7957 pub const Item = struct {
7958 tag: Tag,
7959 data: ExtraIndex,
7960
7961 const ExtraIndex = u32;
7962 };
7963
7964 pub const DIFlags = packed struct(u32) {
7965 Visibility: enum(u2) { Zero, Private, Protected, Public } = .Zero,
7966 FwdDecl: bool = false,
7967 AppleBlock: bool = false,
7968 ReservedBit4: u1 = 0,
7969 Virtual: bool = false,
7970 Artificial: bool = false,
7971 Explicit: bool = false,
7972 Prototyped: bool = false,
7973 ObjcClassComplete: bool = false,
7974 ObjectPointer: bool = false,
7975 Vector: bool = false,
7976 StaticMember: bool = false,
7977 LValueReference: bool = false,
7978 RValueReference: bool = false,
7979 ExportSymbols: bool = false,
7980 Inheritance: enum(u2) {
7981 Zero,
7982 SingleInheritance,
7983 MultipleInheritance,
7984 VirtualInheritance,
7985 } = .Zero,
7986 IntroducedVirtual: bool = false,
7987 BitField: bool = false,
7988 NoReturn: bool = false,
7989 ReservedBit21: u1 = 0,
7990 TypePassbyValue: bool = false,
7991 TypePassbyReference: bool = false,
7992 EnumClass: bool = false,
7993 Thunk: bool = false,
7994 NonTrivial: bool = false,
7995 BigEndian: bool = false,
7996 LittleEndian: bool = false,
7997 AllCallsDescribed: bool = false,
7998 Unused: u2 = 0,
7999
8000 pub fn format(
8001 self: DIFlags,
8002 comptime _: []const u8,
8003 _: std.fmt.FormatOptions,
8004 writer: anytype,
8005 ) @TypeOf(writer).Error!void {
8006 var need_pipe = false;
8007 inline for (@typeInfo(DIFlags).@"struct".fields) |field| {
8008 switch (@typeInfo(field.type)) {
8009 .bool => if (@field(self, field.name)) {
8010 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8011 try writer.print("DIFlag{s}", .{field.name});
8012 },
8013 .@"enum" => if (@field(self, field.name) != .Zero) {
8014 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8015 try writer.print("DIFlag{s}", .{@tagName(@field(self, field.name))});
8016 },
8017 .int => assert(@field(self, field.name) == 0),
8018 else => @compileError("bad field type: " ++ field.name ++ ": " ++
8019 @typeName(field.type)),
8020 }
8021 }
8022 if (!need_pipe) try writer.writeByte('0');
8023 }
8024 };
8025
8026 pub const File = struct {
8027 filename: MetadataString,
8028 directory: MetadataString,
8029 };
8030
8031 pub const CompileUnit = struct {
8032 pub const Options = struct {
8033 optimized: bool,
8034 };
8035
8036 file: Metadata,
8037 producer: MetadataString,
8038 enums: Metadata,
8039 globals: Metadata,
8040 };
8041
8042 pub const Subprogram = struct {
8043 pub const Options = struct {
8044 di_flags: DIFlags,
8045 sp_flags: DISPFlags,
8046 };
8047
8048 pub const DISPFlags = packed struct(u32) {
8049 Virtuality: enum(u2) { Zero, Virtual, PureVirtual } = .Zero,
8050 LocalToUnit: bool = false,
8051 Definition: bool = false,
8052 Optimized: bool = false,
8053 Pure: bool = false,
8054 Elemental: bool = false,
8055 Recursive: bool = false,
8056 MainSubprogram: bool = false,
8057 Deleted: bool = false,
8058 ReservedBit10: u1 = 0,
8059 ObjCDirect: bool = false,
8060 Unused: u20 = 0,
8061
8062 pub fn format(
8063 self: DISPFlags,
8064 comptime _: []const u8,
8065 _: std.fmt.FormatOptions,
8066 writer: anytype,
8067 ) @TypeOf(writer).Error!void {
8068 var need_pipe = false;
8069 inline for (@typeInfo(DISPFlags).@"struct".fields) |field| {
8070 switch (@typeInfo(field.type)) {
8071 .bool => if (@field(self, field.name)) {
8072 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8073 try writer.print("DISPFlag{s}", .{field.name});
8074 },
8075 .@"enum" => if (@field(self, field.name) != .Zero) {
8076 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8077 try writer.print("DISPFlag{s}", .{@tagName(@field(self, field.name))});
8078 },
8079 .int => assert(@field(self, field.name) == 0),
8080 else => @compileError("bad field type: " ++ field.name ++ ": " ++
8081 @typeName(field.type)),
8082 }
8083 }
8084 if (!need_pipe) try writer.writeByte('0');
8085 }
8086 };
8087
8088 file: Metadata,
8089 name: MetadataString,
8090 linkage_name: MetadataString,
8091 line: u32,
8092 scope_line: u32,
8093 ty: Metadata,
8094 di_flags: DIFlags,
8095 compile_unit: Metadata,
8096 };
8097
8098 pub const LexicalBlock = struct {
8099 scope: Metadata,
8100 file: Metadata,
8101 line: u32,
8102 column: u32,
8103 };
8104
8105 pub const Location = struct {
8106 line: u32,
8107 column: u32,
8108 scope: Metadata,
8109 inlined_at: Metadata,
8110 };
8111
8112 pub const BasicType = struct {
8113 name: MetadataString,
8114 size_in_bits_lo: u32,
8115 size_in_bits_hi: u32,
8116
8117 pub fn bitSize(self: BasicType) u64 {
8118 return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
8119 }
8120 };
8121
8122 pub const CompositeType = struct {
8123 name: MetadataString,
8124 file: Metadata,
8125 scope: Metadata,
8126 line: u32,
8127 underlying_type: Metadata,
8128 size_in_bits_lo: u32,
8129 size_in_bits_hi: u32,
8130 align_in_bits_lo: u32,
8131 align_in_bits_hi: u32,
8132 fields_tuple: Metadata,
8133
8134 pub fn bitSize(self: CompositeType) u64 {
8135 return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
8136 }
8137 pub fn bitAlign(self: CompositeType) u64 {
8138 return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo;
8139 }
8140 };
8141
8142 pub const DerivedType = struct {
8143 name: MetadataString,
8144 file: Metadata,
8145 scope: Metadata,
8146 line: u32,
8147 underlying_type: Metadata,
8148 size_in_bits_lo: u32,
8149 size_in_bits_hi: u32,
8150 align_in_bits_lo: u32,
8151 align_in_bits_hi: u32,
8152 offset_in_bits_lo: u32,
8153 offset_in_bits_hi: u32,
8154
8155 pub fn bitSize(self: DerivedType) u64 {
8156 return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
8157 }
8158 pub fn bitAlign(self: DerivedType) u64 {
8159 return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo;
8160 }
8161 pub fn bitOffset(self: DerivedType) u64 {
8162 return @as(u64, self.offset_in_bits_hi) << 32 | self.offset_in_bits_lo;
8163 }
8164 };
8165
8166 pub const SubroutineType = struct {
8167 types_tuple: Metadata,
8168 };
8169
8170 pub const Enumerator = struct {
8171 name: MetadataString,
8172 bit_width: u32,
8173 limbs_index: u32,
8174 limbs_len: u32,
8175 };
8176
8177 pub const Subrange = struct {
8178 lower_bound: Metadata,
8179 count: Metadata,
8180 };
8181
8182 pub const Expression = struct {
8183 elements_len: u32,
8184
8185 // elements: [elements_len]u32
8186 };
8187
8188 pub const Tuple = struct {
8189 elements_len: u32,
8190
8191 // elements: [elements_len]Metadata
8192 };
8193
8194 pub const StrTuple = struct {
8195 str: MetadataString,
8196 elements_len: u32,
8197
8198 // elements: [elements_len]Metadata
8199 };
8200
8201 pub const ModuleFlag = struct {
8202 behavior: Metadata,
8203 name: MetadataString,
8204 constant: Metadata,
8205 };
8206
8207 pub const LocalVar = struct {
8208 name: MetadataString,
8209 file: Metadata,
8210 scope: Metadata,
8211 line: u32,
8212 ty: Metadata,
8213 };
8214
8215 pub const Parameter = struct {
8216 name: MetadataString,
8217 file: Metadata,
8218 scope: Metadata,
8219 line: u32,
8220 ty: Metadata,
8221 arg_no: u32,
8222 };
8223
8224 pub const GlobalVar = struct {
8225 pub const Options = struct {
8226 local: bool,
8227 };
8228
8229 name: MetadataString,
8230 linkage_name: MetadataString,
8231 file: Metadata,
8232 scope: Metadata,
8233 line: u32,
8234 ty: Metadata,
8235 variable: Variable.Index,
8236 };
8237
8238 pub const GlobalVarExpression = struct {
8239 variable: Metadata,
8240 expression: Metadata,
8241 };
8242
8243 pub fn toValue(self: Metadata) Value {
8244 return @enumFromInt(Value.first_metadata + @intFromEnum(self));
8245 }
8246
8247 const Formatter = struct {
8248 builder: *Builder,
8249 need_comma: bool,
8250 map: std.AutoArrayHashMapUnmanaged(union(enum) {
8251 metadata: Metadata,
8252 debug_location: DebugLocation.Location,
8253 }, void) = .{},
8254
8255 const FormatData = struct {
8256 formatter: *Formatter,
8257 prefix: []const u8 = "",
8258 node: Node,
8259
8260 const Node = union(enum) {
8261 none,
8262 @"inline": Metadata,
8263 index: u32,
8264
8265 local_value: ValueData,
8266 local_metadata: ValueData,
8267 local_inline: Metadata,
8268 local_index: u32,
8269
8270 string: MetadataString,
8271 bool: bool,
8272 u32: u32,
8273 u64: u64,
8274 di_flags: DIFlags,
8275 sp_flags: Subprogram.DISPFlags,
8276 raw: []const u8,
8277
8278 const ValueData = struct {
8279 value: Value,
8280 function: Function.Index,
8281 };
8282 };
8283 };
8284 fn format(
8285 data: FormatData,
8286 comptime fmt_str: []const u8,
8287 fmt_opts: std.fmt.FormatOptions,
8288 writer: anytype,
8289 ) @TypeOf(writer).Error!void {
8290 if (data.node == .none) return;
8291
8292 const is_specialized = fmt_str.len > 0 and fmt_str[0] == 'S';
8293 const recurse_fmt_str = if (is_specialized) fmt_str[1..] else fmt_str;
8294
8295 if (data.formatter.need_comma) try writer.writeAll(", ");
8296 defer data.formatter.need_comma = true;
8297 try writer.writeAll(data.prefix);
8298
8299 const builder = data.formatter.builder;
8300 switch (data.node) {
8301 .none => unreachable,
8302 .@"inline" => |node| {
8303 const needed_comma = data.formatter.need_comma;
8304 defer data.formatter.need_comma = needed_comma;
8305 data.formatter.need_comma = false;
8306
8307 const item = builder.metadata_items.get(@intFromEnum(node));
8308 switch (item.tag) {
8309 .expression => {
8310 var extra = builder.metadataExtraDataTrail(Expression, item.data);
8311 const elements = extra.trail.next(extra.data.elements_len, u32, builder);
8312 try writer.writeAll("!DIExpression(");
8313 for (elements) |element| try format(.{
8314 .formatter = data.formatter,
8315 .node = .{ .u64 = element },
8316 }, "%", fmt_opts, writer);
8317 try writer.writeByte(')');
8318 },
8319 .constant => try Constant.format(.{
8320 .constant = @enumFromInt(item.data),
8321 .builder = builder,
8322 }, recurse_fmt_str, fmt_opts, writer),
8323 else => unreachable,
8324 }
8325 },
8326 .index => |node| try writer.print("!{d}", .{node}),
8327 inline .local_value, .local_metadata => |node, tag| try Value.format(.{
8328 .value = node.value,
8329 .function = node.function,
8330 .builder = builder,
8331 }, switch (tag) {
8332 .local_value => recurse_fmt_str,
8333 .local_metadata => "%",
8334 else => unreachable,
8335 }, fmt_opts, writer),
8336 inline .local_inline, .local_index => |node, tag| {
8337 if (comptime std.mem.eql(u8, recurse_fmt_str, "%"))
8338 try writer.print("{%} ", .{Type.metadata.fmt(builder)});
8339 try format(.{
8340 .formatter = data.formatter,
8341 .node = @unionInit(FormatData.Node, @tagName(tag)["local_".len..], node),
8342 }, "%", fmt_opts, writer);
8343 },
8344 .string => |node| try writer.print((if (is_specialized) "" else "!") ++ "{}", .{
8345 node.fmt(builder),
8346 }),
8347 inline .bool,
8348 .u32,
8349 .u64,
8350 .di_flags,
8351 .sp_flags,
8352 => |node| try writer.print("{}", .{node}),
8353 .raw => |node| try writer.writeAll(node),
8354 }
8355 }
8356 inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype) switch (@TypeOf(node)) {
8357 Metadata => Allocator.Error,
8358 else => error{},
8359 }!std.fmt.Formatter(format) {
8360 const Node = @TypeOf(node);
8361 const MaybeNode = switch (@typeInfo(Node)) {
8362 .optional => Node,
8363 .null => ?noreturn,
8364 else => ?Node,
8365 };
8366 const Some = @typeInfo(MaybeNode).optional.child;
8367 return .{ .data = .{
8368 .formatter = formatter,
8369 .prefix = prefix,
8370 .node = if (@as(MaybeNode, node)) |some| switch (@typeInfo(Some)) {
8371 .@"enum" => |enum_info| switch (Some) {
8372 Metadata => switch (some) {
8373 .none => .none,
8374 else => try formatter.refUnwrapped(some.unwrap(formatter.builder)),
8375 },
8376 MetadataString => .{ .string = some },
8377 else => if (enum_info.is_exhaustive)
8378 .{ .raw = @tagName(some) }
8379 else
8380 @compileError("unknown type to format: " ++ @typeName(Node)),
8381 },
8382 .enum_literal => .{ .raw = @tagName(some) },
8383 .bool => .{ .bool = some },
8384 .@"struct" => switch (Some) {
8385 DIFlags => .{ .di_flags = some },
8386 Subprogram.DISPFlags => .{ .sp_flags = some },
8387 else => @compileError("unknown type to format: " ++ @typeName(Node)),
8388 },
8389 .int, .comptime_int => .{ .u64 = some },
8390 .pointer => .{ .raw = some },
8391 else => @compileError("unknown type to format: " ++ @typeName(Node)),
8392 } else switch (@typeInfo(Node)) {
8393 .optional, .null => .none,
8394 else => unreachable,
8395 },
8396 } };
8397 }
8398 inline fn fmtLocal(
8399 formatter: *Formatter,
8400 prefix: []const u8,
8401 value: Value,
8402 function: Function.Index,
8403 ) Allocator.Error!std.fmt.Formatter(format) {
8404 return .{ .data = .{
8405 .formatter = formatter,
8406 .prefix = prefix,
8407 .node = switch (value.unwrap()) {
8408 .instruction, .constant => .{ .local_value = .{
8409 .value = value,
8410 .function = function,
8411 } },
8412 .metadata => |metadata| if (value == .none) .none else node: {
8413 const unwrapped = metadata.unwrap(formatter.builder);
8414 break :node if (@intFromEnum(unwrapped) >= first_local_metadata)
8415 .{ .local_metadata = .{
8416 .value = function.ptrConst(formatter.builder).debug_values[
8417 @intFromEnum(unwrapped) - first_local_metadata
8418 ].toValue(),
8419 .function = function,
8420 } }
8421 else switch (try formatter.refUnwrapped(unwrapped)) {
8422 .@"inline" => |node| .{ .local_inline = node },
8423 .index => |node| .{ .local_index = node },
8424 else => unreachable,
8425 };
8426 },
8427 },
8428 } };
8429 }
8430 fn refUnwrapped(formatter: *Formatter, node: Metadata) Allocator.Error!FormatData.Node {
8431 assert(node != .none);
8432 assert(@intFromEnum(node) < first_forward_reference);
8433 const builder = formatter.builder;
8434 const unwrapped_metadata = node.unwrap(builder);
8435 const tag = formatter.builder.metadata_items.items(.tag)[@intFromEnum(unwrapped_metadata)];
8436 switch (tag) {
8437 .none => unreachable,
8438 .expression, .constant => return .{ .@"inline" = unwrapped_metadata },
8439 else => {
8440 assert(!tag.isInline());
8441 const gop = try formatter.map.getOrPut(builder.gpa, .{ .metadata = unwrapped_metadata });
8442 return .{ .index = @intCast(gop.index) };
8443 },
8444 }
8445 }
8446
8447 inline fn specialized(
8448 formatter: *Formatter,
8449 distinct: enum { @"!", @"distinct !" },
8450 node: enum {
8451 DIFile,
8452 DICompileUnit,
8453 DISubprogram,
8454 DILexicalBlock,
8455 DILocation,
8456 DIBasicType,
8457 DICompositeType,
8458 DIDerivedType,
8459 DISubroutineType,
8460 DIEnumerator,
8461 DISubrange,
8462 DILocalVariable,
8463 DIGlobalVariable,
8464 DIGlobalVariableExpression,
8465 },
8466 nodes: anytype,
8467 writer: anytype,
8468 ) !void {
8469 comptime var fmt_str: []const u8 = "";
8470 const names = comptime std.meta.fieldNames(@TypeOf(nodes));
8471 comptime var fields: [2 + names.len]std.builtin.Type.StructField = undefined;
8472 inline for (fields[0..2], .{ "distinct", "node" }) |*field, name| {
8473 fmt_str = fmt_str ++ "{[" ++ name ++ "]s}";
8474 field.* = .{
8475 .name = name,
8476 .type = []const u8,
8477 .default_value_ptr = null,
8478 .is_comptime = false,
8479 .alignment = 0,
8480 };
8481 }
8482 fmt_str = fmt_str ++ "(";
8483 inline for (fields[2..], names) |*field, name| {
8484 fmt_str = fmt_str ++ "{[" ++ name ++ "]S}";
8485 field.* = .{
8486 .name = name,
8487 .type = std.fmt.Formatter(format),
8488 .default_value_ptr = null,
8489 .is_comptime = false,
8490 .alignment = 0,
8491 };
8492 }
8493 fmt_str = fmt_str ++ ")\n";
8494
8495 var fmt_args: @Type(.{ .@"struct" = .{
8496 .layout = .auto,
8497 .fields = &fields,
8498 .decls = &.{},
8499 .is_tuple = false,
8500 } }) = undefined;
8501 fmt_args.distinct = @tagName(distinct);
8502 fmt_args.node = @tagName(node);
8503 inline for (names) |name| @field(fmt_args, name) = try formatter.fmt(
8504 name ++ ": ",
8505 @field(nodes, name),
8506 );
8507 try writer.print(fmt_str, fmt_args);
8508 }
8509 };
8510};
8511
8512pub fn init(options: Options) Allocator.Error!Builder {
8513 var self: Builder = .{
8514 .gpa = options.allocator,
8515 .strip = options.strip,
8516
8517 .source_filename = .none,
8518 .data_layout = .none,
8519 .target_triple = .none,
8520 .module_asm = .{},
8521
8522 .string_map = .{},
8523 .string_indices = .{},
8524 .string_bytes = .{},
8525
8526 .types = .{},
8527 .next_unnamed_type = @enumFromInt(0),
8528 .next_unique_type_id = .{},
8529 .type_map = .{},
8530 .type_items = .{},
8531 .type_extra = .{},
8532
8533 .attributes = .{},
8534 .attributes_map = .{},
8535 .attributes_indices = .{},
8536 .attributes_extra = .{},
8537
8538 .function_attributes_set = .{},
8539
8540 .globals = .{},
8541 .next_unnamed_global = @enumFromInt(0),
8542 .next_replaced_global = .none,
8543 .next_unique_global_id = .{},
8544 .aliases = .{},
8545 .variables = .{},
8546 .functions = .{},
8547
8548 .strtab_string_map = .{},
8549 .strtab_string_indices = .{},
8550 .strtab_string_bytes = .{},
8551
8552 .constant_map = .{},
8553 .constant_items = .{},
8554 .constant_extra = .{},
8555 .constant_limbs = .{},
8556
8557 .metadata_map = .{},
8558 .metadata_items = .{},
8559 .metadata_extra = .{},
8560 .metadata_limbs = .{},
8561 .metadata_forward_references = .{},
8562 .metadata_named = .{},
8563 .metadata_string_map = .{},
8564 .metadata_string_indices = .{},
8565 .metadata_string_bytes = .{},
8566 };
8567 errdefer self.deinit();
8568
8569 try self.string_indices.append(self.gpa, 0);
8570 assert(try self.string("") == .empty);
8571
8572 try self.strtab_string_indices.append(self.gpa, 0);
8573 assert(try self.strtabString("") == .empty);
8574
8575 if (options.name.len > 0) self.source_filename = try self.string(options.name);
8576
8577 if (options.triple.len > 0) {
8578 self.target_triple = try self.string(options.triple);
8579 }
8580
8581 {
8582 const static_len = @typeInfo(Type).@"enum".fields.len - 1;
8583 try self.type_map.ensureTotalCapacity(self.gpa, static_len);
8584 try self.type_items.ensureTotalCapacity(self.gpa, static_len);
8585 inline for (@typeInfo(Type.Simple).@"enum".fields) |simple_field| {
8586 const result = self.getOrPutTypeNoExtraAssumeCapacity(
8587 .{ .tag = .simple, .data = simple_field.value },
8588 );
8589 assert(result.new and result.type == @field(Type, simple_field.name));
8590 }
8591 inline for (.{ 1, 8, 16, 29, 32, 64, 80, 128 }) |bits|
8592 assert(self.intTypeAssumeCapacity(bits) ==
8593 @field(Type, std.fmt.comptimePrint("i{d}", .{bits})));
8594 inline for (.{ 0, 4 }) |addr_space_index| {
8595 const addr_space: AddrSpace = @enumFromInt(addr_space_index);
8596 assert(self.ptrTypeAssumeCapacity(addr_space) ==
8597 @field(Type, std.fmt.comptimePrint("ptr{ }", .{addr_space})));
8598 }
8599 }
8600
8601 {
8602 try self.attributes_indices.append(self.gpa, 0);
8603 assert(try self.attrs(&.{}) == .none);
8604 assert(try self.fnAttrs(&.{}) == .none);
8605 }
8606
8607 assert(try self.intConst(.i1, 0) == .false);
8608 assert(try self.intConst(.i1, 1) == .true);
8609 assert(try self.intConst(.i32, 0) == .@"0");
8610 assert(try self.intConst(.i32, 1) == .@"1");
8611 assert(try self.noneConst(.token) == .none);
8612
8613 assert(try self.metadataNone() == .none);
8614 assert(try self.metadataTuple(&.{}) == .empty_tuple);
8615
8616 try self.metadata_string_indices.append(self.gpa, 0);
8617 assert(try self.metadataString("") == .none);
8618
8619 return self;
8620}
8621
8622pub fn clearAndFree(self: *Builder) void {
8623 self.module_asm.clearAndFree(self.gpa);
8624
8625 self.string_map.clearAndFree(self.gpa);
8626 self.string_indices.clearAndFree(self.gpa);
8627 self.string_bytes.clearAndFree(self.gpa);
8628
8629 self.types.clearAndFree(self.gpa);
8630 self.next_unique_type_id.clearAndFree(self.gpa);
8631 self.type_map.clearAndFree(self.gpa);
8632 self.type_items.clearAndFree(self.gpa);
8633 self.type_extra.clearAndFree(self.gpa);
8634
8635 self.attributes.clearAndFree(self.gpa);
8636 self.attributes_map.clearAndFree(self.gpa);
8637 self.attributes_indices.clearAndFree(self.gpa);
8638 self.attributes_extra.clearAndFree(self.gpa);
8639
8640 self.function_attributes_set.clearAndFree(self.gpa);
8641
8642 self.globals.clearAndFree(self.gpa);
8643 self.next_unique_global_id.clearAndFree(self.gpa);
8644 self.aliases.clearAndFree(self.gpa);
8645 self.variables.clearAndFree(self.gpa);
8646 for (self.functions.items) |*function| function.deinit(self.gpa);
8647 self.functions.clearAndFree(self.gpa);
8648
8649 self.strtab_string_map.clearAndFree(self.gpa);
8650 self.strtab_string_indices.clearAndFree(self.gpa);
8651 self.strtab_string_bytes.clearAndFree(self.gpa);
8652
8653 self.constant_map.clearAndFree(self.gpa);
8654 self.constant_items.shrinkAndFree(self.gpa, 0);
8655 self.constant_extra.clearAndFree(self.gpa);
8656 self.constant_limbs.clearAndFree(self.gpa);
8657
8658 self.metadata_map.clearAndFree(self.gpa);
8659 self.metadata_items.shrinkAndFree(self.gpa, 0);
8660 self.metadata_extra.clearAndFree(self.gpa);
8661 self.metadata_limbs.clearAndFree(self.gpa);
8662 self.metadata_forward_references.clearAndFree(self.gpa);
8663 self.metadata_named.clearAndFree(self.gpa);
8664
8665 self.metadata_string_map.clearAndFree(self.gpa);
8666 self.metadata_string_indices.clearAndFree(self.gpa);
8667 self.metadata_string_bytes.clearAndFree(self.gpa);
8668}
8669
8670pub fn deinit(self: *Builder) void {
8671 self.module_asm.deinit(self.gpa);
8672
8673 self.string_map.deinit(self.gpa);
8674 self.string_indices.deinit(self.gpa);
8675 self.string_bytes.deinit(self.gpa);
8676
8677 self.types.deinit(self.gpa);
8678 self.next_unique_type_id.deinit(self.gpa);
8679 self.type_map.deinit(self.gpa);
8680 self.type_items.deinit(self.gpa);
8681 self.type_extra.deinit(self.gpa);
8682
8683 self.attributes.deinit(self.gpa);
8684 self.attributes_map.deinit(self.gpa);
8685 self.attributes_indices.deinit(self.gpa);
8686 self.attributes_extra.deinit(self.gpa);
8687
8688 self.function_attributes_set.deinit(self.gpa);
8689
8690 self.globals.deinit(self.gpa);
8691 self.next_unique_global_id.deinit(self.gpa);
8692 self.aliases.deinit(self.gpa);
8693 self.variables.deinit(self.gpa);
8694 for (self.functions.items) |*function| function.deinit(self.gpa);
8695 self.functions.deinit(self.gpa);
8696
8697 self.strtab_string_map.deinit(self.gpa);
8698 self.strtab_string_indices.deinit(self.gpa);
8699 self.strtab_string_bytes.deinit(self.gpa);
8700
8701 self.constant_map.deinit(self.gpa);
8702 self.constant_items.deinit(self.gpa);
8703 self.constant_extra.deinit(self.gpa);
8704 self.constant_limbs.deinit(self.gpa);
8705
8706 self.metadata_map.deinit(self.gpa);
8707 self.metadata_items.deinit(self.gpa);
8708 self.metadata_extra.deinit(self.gpa);
8709 self.metadata_limbs.deinit(self.gpa);
8710 self.metadata_forward_references.deinit(self.gpa);
8711 self.metadata_named.deinit(self.gpa);
8712
8713 self.metadata_string_map.deinit(self.gpa);
8714 self.metadata_string_indices.deinit(self.gpa);
8715 self.metadata_string_bytes.deinit(self.gpa);
8716
8717 self.* = undefined;
8718}
8719
8720pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
8721 self.module_asm.clearRetainingCapacity();
8722 return self.appendModuleAsm();
8723}
8724
8725pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
8726 return self.module_asm.writer(self.gpa);
8727}
8728
8729pub fn finishModuleAsm(self: *Builder) Allocator.Error!void {
8730 if (self.module_asm.getLastOrNull()) |last| if (last != '\n')
8731 try self.module_asm.append(self.gpa, '\n');
8732}
8733
8734pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {
8735 try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len);
8736 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8737 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8738
8739 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
8740 if (!gop.found_existing) {
8741 self.string_bytes.appendSliceAssumeCapacity(bytes);
8742 self.string_indices.appendAssumeCapacity(@intCast(self.string_bytes.items.len));
8743 }
8744 return String.fromIndex(gop.index);
8745}
8746
8747pub fn stringNull(self: *Builder, bytes: [:0]const u8) Allocator.Error!String {
8748 return self.string(bytes[0 .. bytes.len + 1]);
8749}
8750
8751pub fn stringIfExists(self: *const Builder, bytes: []const u8) ?String {
8752 return String.fromIndex(
8753 self.string_map.getIndexAdapted(bytes, String.Adapter{ .builder = self }) orelse return null,
8754 );
8755}
8756
8757pub fn fmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allocator.Error!String {
8758 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8759 try self.string_bytes.ensureUnusedCapacity(self.gpa, @intCast(std.fmt.count(fmt_str, fmt_args)));
8760 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8761 return self.fmtAssumeCapacity(fmt_str, fmt_args);
8762}
8763
8764pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) String {
8765 self.string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
8766 return self.trailingStringAssumeCapacity();
8767}
8768
8769pub fn trailingString(self: *Builder) Allocator.Error!String {
8770 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8771 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8772 return self.trailingStringAssumeCapacity();
8773}
8774
8775pub fn trailingStringAssumeCapacity(self: *Builder) String {
8776 const start = self.string_indices.getLast();
8777 const bytes: []const u8 = self.string_bytes.items[start..];
8778 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
8779 if (gop.found_existing) {
8780 self.string_bytes.shrinkRetainingCapacity(start);
8781 } else {
8782 self.string_indices.appendAssumeCapacity(@intCast(self.string_bytes.items.len));
8783 }
8784 return String.fromIndex(gop.index);
8785}
8786
8787pub fn fnType(
8788 self: *Builder,
8789 ret: Type,
8790 params: []const Type,
8791 kind: Type.Function.Kind,
8792) Allocator.Error!Type {
8793 try self.ensureUnusedTypeCapacity(1, Type.Function, params.len);
8794 switch (kind) {
8795 inline else => |comptime_kind| return self.fnTypeAssumeCapacity(ret, params, comptime_kind),
8796 }
8797}
8798
8799pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
8800 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8801 return self.intTypeAssumeCapacity(bits);
8802}
8803
8804pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
8805 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8806 return self.ptrTypeAssumeCapacity(addr_space);
8807}
8808
8809pub fn vectorType(
8810 self: *Builder,
8811 kind: Type.Vector.Kind,
8812 len: u32,
8813 child: Type,
8814) Allocator.Error!Type {
8815 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
8816 switch (kind) {
8817 inline else => |comptime_kind| return self.vectorTypeAssumeCapacity(comptime_kind, len, child),
8818 }
8819}
8820
8821pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {
8822 comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector));
8823 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
8824 return self.arrayTypeAssumeCapacity(len, child);
8825}
8826
8827pub fn structType(
8828 self: *Builder,
8829 kind: Type.Structure.Kind,
8830 fields: []const Type,
8831) Allocator.Error!Type {
8832 try self.ensureUnusedTypeCapacity(1, Type.Structure, fields.len);
8833 switch (kind) {
8834 inline else => |comptime_kind| return self.structTypeAssumeCapacity(comptime_kind, fields),
8835 }
8836}
8837
8838pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
8839 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8840 if (name.slice(self)) |id| {
8841 const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});
8842 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
8843 }
8844 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
8845 try self.types.ensureUnusedCapacity(self.gpa, 1);
8846 try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);
8847 try self.ensureUnusedTypeCapacity(1, Type.NamedStructure, 0);
8848 return self.opaqueTypeAssumeCapacity(name);
8849}
8850
8851pub fn namedTypeSetBody(
8852 self: *Builder,
8853 named_type: Type,
8854 body_type: Type,
8855) void {
8856 const named_item = self.type_items.items[@intFromEnum(named_type)];
8857 self.type_extra.items[named_item.data + std.meta.fieldIndex(Type.NamedStructure, "body").?] =
8858 @intFromEnum(body_type);
8859}
8860
8861pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Index {
8862 try self.attributes.ensureUnusedCapacity(self.gpa, 1);
8863
8864 const gop = self.attributes.getOrPutAssumeCapacity(attribute.toStorage());
8865 if (!gop.found_existing) gop.value_ptr.* = {};
8866 return @enumFromInt(gop.index);
8867}
8868
8869pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attributes {
8870 std.sort.heap(Attribute.Index, attributes, self, struct {
8871 pub fn lessThan(builder: *const Builder, lhs: Attribute.Index, rhs: Attribute.Index) bool {
8872 const lhs_kind = lhs.getKind(builder);
8873 const rhs_kind = rhs.getKind(builder);
8874 assert(lhs_kind != rhs_kind);
8875 return @intFromEnum(lhs_kind) < @intFromEnum(rhs_kind);
8876 }
8877 }.lessThan);
8878 return @enumFromInt(try self.attrGeneric(@ptrCast(attributes)));
8879}
8880
8881pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes {
8882 try self.function_attributes_set.ensureUnusedCapacity(self.gpa, 1);
8883 const function_attributes: FunctionAttributes = @enumFromInt(try self.attrGeneric(@ptrCast(
8884 fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last|
8885 last + 1
8886 else
8887 0],
8888 )));
8889
8890 _ = self.function_attributes_set.getOrPutAssumeCapacity(function_attributes);
8891 return function_attributes;
8892}
8893
8894pub fn addGlobal(self: *Builder, name: StrtabString, global: Global) Allocator.Error!Global.Index {
8895 assert(!name.isAnon());
8896 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8897 try self.ensureUnusedGlobalCapacity(name);
8898 return self.addGlobalAssumeCapacity(name, global);
8899}
8900
8901pub fn addGlobalAssumeCapacity(self: *Builder, name: StrtabString, global: Global) Global.Index {
8902 _ = self.ptrTypeAssumeCapacity(global.addr_space);
8903 var id = name;
8904 if (name == .empty) {
8905 id = self.next_unnamed_global;
8906 assert(id != self.next_replaced_global);
8907 self.next_unnamed_global = @enumFromInt(@intFromEnum(id) + 1);
8908 }
8909 while (true) {
8910 const global_gop = self.globals.getOrPutAssumeCapacity(id);
8911 if (!global_gop.found_existing) {
8912 global_gop.value_ptr.* = global;
8913 const global_index: Global.Index = @enumFromInt(global_gop.index);
8914 global_index.updateDsoLocal(self);
8915 return global_index;
8916 }
8917
8918 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
8919 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
8920 id = self.strtabStringFmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
8921 unique_gop.value_ptr.* += 1;
8922 }
8923}
8924
8925pub fn getGlobal(self: *const Builder, name: StrtabString) ?Global.Index {
8926 return @enumFromInt(self.globals.getIndex(name) orelse return null);
8927}
8928
8929pub fn addAlias(
8930 self: *Builder,
8931 name: StrtabString,
8932 ty: Type,
8933 addr_space: AddrSpace,
8934 aliasee: Constant,
8935) Allocator.Error!Alias.Index {
8936 assert(!name.isAnon());
8937 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8938 try self.ensureUnusedGlobalCapacity(name);
8939 try self.aliases.ensureUnusedCapacity(self.gpa, 1);
8940 return self.addAliasAssumeCapacity(name, ty, addr_space, aliasee);
8941}
8942
8943pub fn addAliasAssumeCapacity(
8944 self: *Builder,
8945 name: StrtabString,
8946 ty: Type,
8947 addr_space: AddrSpace,
8948 aliasee: Constant,
8949) Alias.Index {
8950 const alias_index: Alias.Index = @enumFromInt(self.aliases.items.len);
8951 self.aliases.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
8952 .addr_space = addr_space,
8953 .type = ty,
8954 .kind = .{ .alias = alias_index },
8955 }), .aliasee = aliasee });
8956 return alias_index;
8957}
8958
8959pub fn addVariable(
8960 self: *Builder,
8961 name: StrtabString,
8962 ty: Type,
8963 addr_space: AddrSpace,
8964) Allocator.Error!Variable.Index {
8965 assert(!name.isAnon());
8966 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8967 try self.ensureUnusedGlobalCapacity(name);
8968 try self.variables.ensureUnusedCapacity(self.gpa, 1);
8969 return self.addVariableAssumeCapacity(ty, name, addr_space);
8970}
8971
8972pub fn addVariableAssumeCapacity(
8973 self: *Builder,
8974 ty: Type,
8975 name: StrtabString,
8976 addr_space: AddrSpace,
8977) Variable.Index {
8978 const variable_index: Variable.Index = @enumFromInt(self.variables.items.len);
8979 self.variables.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
8980 .addr_space = addr_space,
8981 .type = ty,
8982 .kind = .{ .variable = variable_index },
8983 }) });
8984 return variable_index;
8985}
8986
8987pub fn addFunction(
8988 self: *Builder,
8989 ty: Type,
8990 name: StrtabString,
8991 addr_space: AddrSpace,
8992) Allocator.Error!Function.Index {
8993 assert(!name.isAnon());
8994 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
8995 try self.ensureUnusedGlobalCapacity(name);
8996 try self.functions.ensureUnusedCapacity(self.gpa, 1);
8997 return self.addFunctionAssumeCapacity(ty, name, addr_space);
8998}
8999
9000pub fn addFunctionAssumeCapacity(
9001 self: *Builder,
9002 ty: Type,
9003 name: StrtabString,
9004 addr_space: AddrSpace,
9005) Function.Index {
9006 assert(ty.isFunction(self));
9007 const function_index: Function.Index = @enumFromInt(self.functions.items.len);
9008 self.functions.appendAssumeCapacity(.{
9009 .global = self.addGlobalAssumeCapacity(name, .{
9010 .addr_space = addr_space,
9011 .type = ty,
9012 .kind = .{ .function = function_index },
9013 }),
9014 .strip = undefined,
9015 });
9016 return function_index;
9017}
9018
9019pub fn getIntrinsic(
9020 self: *Builder,
9021 id: Intrinsic,
9022 overload: []const Type,
9023) Allocator.Error!Function.Index {
9024 const ExpectedContents = extern union {
9025 attrs: extern struct {
9026 params: [expected_args_len]Type,
9027 fn_attrs: [FunctionAttributes.params_index + expected_args_len]Attributes,
9028 attrs: [expected_attrs_len]Attribute.Index,
9029 fields: [expected_fields_len]Type,
9030 },
9031 };
9032 var stack align(@max(@alignOf(std.heap.StackFallbackAllocator(0)), @alignOf(ExpectedContents))) =
9033 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
9034 const allocator = stack.get();
9035
9036 const name = name: {
9037 const writer = self.strtab_string_bytes.writer(self.gpa);
9038 try writer.print("llvm.{s}", .{@tagName(id)});
9039 for (overload) |ty| try writer.print(".{m}", .{ty.fmt(self)});
9040 break :name try self.trailingStrtabString();
9041 };
9042 if (self.getGlobal(name)) |global| return global.ptrConst(self).kind.function;
9043
9044 const signature = Intrinsic.signatures.get(id);
9045 const param_types = try allocator.alloc(Type, signature.params.len);
9046 defer allocator.free(param_types);
9047 const function_attributes = try allocator.alloc(
9048 Attributes,
9049 FunctionAttributes.params_index + (signature.params.len - signature.ret_len),
9050 );
9051 defer allocator.free(function_attributes);
9052
9053 var attributes: struct {
9054 builder: *Builder,
9055 list: std.ArrayList(Attribute.Index),
9056
9057 fn deinit(state: *@This()) void {
9058 state.list.deinit();
9059 state.* = undefined;
9060 }
9061
9062 fn get(state: *@This(), attributes: []const Attribute) Allocator.Error!Attributes {
9063 try state.list.resize(attributes.len);
9064 for (state.list.items, attributes) |*item, attribute|
9065 item.* = try state.builder.attr(attribute);
9066 return state.builder.attrs(state.list.items);
9067 }
9068 } = .{ .builder = self, .list = std.ArrayList(Attribute.Index).init(allocator) };
9069 defer attributes.deinit();
9070
9071 var overload_index: usize = 0;
9072 function_attributes[FunctionAttributes.function_index] = try attributes.get(signature.attrs);
9073 function_attributes[FunctionAttributes.return_index] = .none; // needed for void return
9074 for (0.., param_types, signature.params) |param_index, *param_type, signature_param| {
9075 switch (signature_param.kind) {
9076 .type => |ty| param_type.* = ty,
9077 .overloaded => {
9078 param_type.* = overload[overload_index];
9079 overload_index += 1;
9080 },
9081 .matches, .matches_scalar, .matches_changed_scalar => {},
9082 }
9083 function_attributes[
9084 if (param_index < signature.ret_len)
9085 FunctionAttributes.return_index
9086 else
9087 FunctionAttributes.params_index + (param_index - signature.ret_len)
9088 ] = try attributes.get(signature_param.attrs);
9089 }
9090 assert(overload_index == overload.len);
9091 for (param_types, signature.params) |*param_type, signature_param| {
9092 param_type.* = switch (signature_param.kind) {
9093 .type, .overloaded => continue,
9094 .matches => |param_index| param_types[param_index],
9095 .matches_scalar => |param_index| param_types[param_index].scalarType(self),
9096 .matches_changed_scalar => |info| try param_types[info.index]
9097 .changeScalar(info.scalar, self),
9098 };
9099 }
9100
9101 const function_index = try self.addFunction(try self.fnType(switch (signature.ret_len) {
9102 0 => .void,
9103 1 => param_types[0],
9104 else => try self.structType(.normal, param_types[0..signature.ret_len]),
9105 }, param_types[signature.ret_len..], .normal), name, .default);
9106 function_index.ptr(self).attributes = try self.fnAttrs(function_attributes);
9107 return function_index;
9108}
9109
9110pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Constant {
9111 const int_value = switch (@typeInfo(@TypeOf(value))) {
9112 .int, .comptime_int => value,
9113 .@"enum" => @intFromEnum(value),
9114 else => @compileError("intConst expected an integral value, got " ++ @typeName(@TypeOf(value))),
9115 };
9116 var limbs: [
9117 switch (@typeInfo(@TypeOf(int_value))) {
9118 .int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
9119 .comptime_int => std.math.big.int.calcLimbLen(int_value),
9120 else => unreachable,
9121 }
9122 ]std.math.big.Limb = undefined;
9123 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, int_value).toConst());
9124}
9125
9126pub fn intValue(self: *Builder, ty: Type, value: anytype) Allocator.Error!Value {
9127 return (try self.intConst(ty, value)).toValue();
9128}
9129
9130pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Constant {
9131 try self.constant_map.ensureUnusedCapacity(self.gpa, 1);
9132 try self.constant_items.ensureUnusedCapacity(self.gpa, 1);
9133 try self.constant_limbs.ensureUnusedCapacity(self.gpa, Constant.Integer.limbs + value.limbs.len);
9134 return self.bigIntConstAssumeCapacity(ty, value);
9135}
9136
9137pub fn bigIntValue(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Value {
9138 return (try self.bigIntConst(ty, value)).toValue();
9139}
9140
9141pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {
9142 return switch (ty) {
9143 .half => try self.halfConst(val),
9144 .bfloat => try self.bfloatConst(val),
9145 .float => try self.floatConst(val),
9146 .double => try self.doubleConst(val),
9147 .fp128 => try self.fp128Const(val),
9148 .x86_fp80 => try self.x86_fp80Const(val),
9149 .ppc_fp128 => try self.ppc_fp128Const(.{ val, -0.0 }),
9150 else => unreachable,
9151 };
9152}
9153
9154pub fn fpValue(self: *Builder, ty: Type, comptime value: comptime_float) Allocator.Error!Value {
9155 return (try self.fpConst(ty, value)).toValue();
9156}
9157
9158pub fn nanConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9159 return switch (ty) {
9160 .half => try self.halfConst(std.math.nan(f16)),
9161 .bfloat => try self.bfloatConst(std.math.nan(f32)),
9162 .float => try self.floatConst(std.math.nan(f32)),
9163 .double => try self.doubleConst(std.math.nan(f64)),
9164 .fp128 => try self.fp128Const(std.math.nan(f128)),
9165 .x86_fp80 => try self.x86_fp80Const(std.math.nan(f80)),
9166 .ppc_fp128 => try self.ppc_fp128Const(.{std.math.nan(f64)} ** 2),
9167 else => unreachable,
9168 };
9169}
9170
9171pub fn nanValue(self: *Builder, ty: Type) Allocator.Error!Value {
9172 return (try self.nanConst(ty)).toValue();
9173}
9174
9175pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {
9176 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9177 return self.halfConstAssumeCapacity(val);
9178}
9179
9180pub fn halfValue(self: *Builder, ty: Type, value: f16) Allocator.Error!Value {
9181 return (try self.halfConst(ty, value)).toValue();
9182}
9183
9184pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {
9185 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9186 return self.bfloatConstAssumeCapacity(val);
9187}
9188
9189pub fn bfloatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
9190 return (try self.bfloatConst(ty, value)).toValue();
9191}
9192
9193pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {
9194 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9195 return self.floatConstAssumeCapacity(val);
9196}
9197
9198pub fn floatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
9199 return (try self.floatConst(ty, value)).toValue();
9200}
9201
9202pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {
9203 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);
9204 return self.doubleConstAssumeCapacity(val);
9205}
9206
9207pub fn doubleValue(self: *Builder, ty: Type, value: f64) Allocator.Error!Value {
9208 return (try self.doubleConst(ty, value)).toValue();
9209}
9210
9211pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {
9212 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
9213 return self.fp128ConstAssumeCapacity(val);
9214}
9215
9216pub fn fp128Value(self: *Builder, ty: Type, value: f128) Allocator.Error!Value {
9217 return (try self.fp128Const(ty, value)).toValue();
9218}
9219
9220pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {
9221 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);
9222 return self.x86_fp80ConstAssumeCapacity(val);
9223}
9224
9225pub fn x86_fp80Value(self: *Builder, ty: Type, value: f80) Allocator.Error!Value {
9226 return (try self.x86_fp80Const(ty, value)).toValue();
9227}
9228
9229pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {
9230 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
9231 return self.ppc_fp128ConstAssumeCapacity(val);
9232}
9233
9234pub fn ppc_fp128Value(self: *Builder, ty: Type, value: [2]f64) Allocator.Error!Value {
9235 return (try self.ppc_fp128Const(ty, value)).toValue();
9236}
9237
9238pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9239 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9240 return self.nullConstAssumeCapacity(ty);
9241}
9242
9243pub fn nullValue(self: *Builder, ty: Type) Allocator.Error!Value {
9244 return (try self.nullConst(ty)).toValue();
9245}
9246
9247pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9248 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9249 return self.noneConstAssumeCapacity(ty);
9250}
9251
9252pub fn noneValue(self: *Builder, ty: Type) Allocator.Error!Value {
9253 return (try self.noneConst(ty)).toValue();
9254}
9255
9256pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
9257 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
9258 return self.structConstAssumeCapacity(ty, vals);
9259}
9260
9261pub fn structValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
9262 return (try self.structConst(ty, vals)).toValue();
9263}
9264
9265pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
9266 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
9267 return self.arrayConstAssumeCapacity(ty, vals);
9268}
9269
9270pub fn arrayValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
9271 return (try self.arrayConst(ty, vals)).toValue();
9272}
9273
9274pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {
9275 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
9276 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9277 return self.stringConstAssumeCapacity(val);
9278}
9279
9280pub fn stringValue(self: *Builder, val: String) Allocator.Error!Value {
9281 return (try self.stringConst(val)).toValue();
9282}
9283
9284pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
9285 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
9286 return self.vectorConstAssumeCapacity(ty, vals);
9287}
9288
9289pub fn vectorValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
9290 return (try self.vectorConst(ty, vals)).toValue();
9291}
9292
9293pub fn splatConst(self: *Builder, ty: Type, val: Constant) Allocator.Error!Constant {
9294 try self.ensureUnusedConstantCapacity(1, Constant.Splat, 0);
9295 return self.splatConstAssumeCapacity(ty, val);
9296}
9297
9298pub fn splatValue(self: *Builder, ty: Type, val: Constant) Allocator.Error!Value {
9299 return (try self.splatConst(ty, val)).toValue();
9300}
9301
9302pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9303 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
9304 try self.constant_limbs.ensureUnusedCapacity(
9305 self.gpa,
9306 Constant.Integer.limbs + comptime std.math.big.int.calcLimbLen(0),
9307 );
9308 return self.zeroInitConstAssumeCapacity(ty);
9309}
9310
9311pub fn zeroInitValue(self: *Builder, ty: Type) Allocator.Error!Value {
9312 return (try self.zeroInitConst(ty)).toValue();
9313}
9314
9315pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9316 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9317 return self.undefConstAssumeCapacity(ty);
9318}
9319
9320pub fn undefValue(self: *Builder, ty: Type) Allocator.Error!Value {
9321 return (try self.undefConst(ty)).toValue();
9322}
9323
9324pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {
9325 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9326 return self.poisonConstAssumeCapacity(ty);
9327}
9328
9329pub fn poisonValue(self: *Builder, ty: Type) Allocator.Error!Value {
9330 return (try self.poisonConst(ty)).toValue();
9331}
9332
9333pub fn blockAddrConst(
9334 self: *Builder,
9335 function: Function.Index,
9336 block: Function.Block.Index,
9337) Allocator.Error!Constant {
9338 try self.ensureUnusedConstantCapacity(1, Constant.BlockAddress, 0);
9339 return self.blockAddrConstAssumeCapacity(function, block);
9340}
9341
9342pub fn blockAddrValue(
9343 self: *Builder,
9344 function: Function.Index,
9345 block: Function.Block.Index,
9346) Allocator.Error!Value {
9347 return (try self.blockAddrConst(function, block)).toValue();
9348}
9349
9350pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
9351 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9352 return self.dsoLocalEquivalentConstAssumeCapacity(function);
9353}
9354
9355pub fn dsoLocalEquivalentValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
9356 return (try self.dsoLocalEquivalentConst(function)).toValue();
9357}
9358
9359pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
9360 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
9361 return self.noCfiConstAssumeCapacity(function);
9362}
9363
9364pub fn noCfiValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
9365 return (try self.noCfiConst(function)).toValue();
9366}
9367
9368pub fn convConst(
9369 self: *Builder,
9370 val: Constant,
9371 ty: Type,
9372) Allocator.Error!Constant {
9373 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
9374 return self.convConstAssumeCapacity(val, ty);
9375}
9376
9377pub fn convValue(
9378 self: *Builder,
9379 val: Constant,
9380 ty: Type,
9381) Allocator.Error!Value {
9382 return (try self.convConst(val, ty)).toValue();
9383}
9384
9385pub fn castConst(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Constant {
9386 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
9387 return self.castConstAssumeCapacity(tag, val, ty);
9388}
9389
9390pub fn castValue(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Value {
9391 return (try self.castConst(tag, val, ty)).toValue();
9392}
9393
9394pub fn gepConst(
9395 self: *Builder,
9396 comptime kind: Constant.GetElementPtr.Kind,
9397 ty: Type,
9398 base: Constant,
9399 inrange: ?u16,
9400 indices: []const Constant,
9401) Allocator.Error!Constant {
9402 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
9403 try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len);
9404 return self.gepConstAssumeCapacity(kind, ty, base, inrange, indices);
9405}
9406
9407pub fn gepValue(
9408 self: *Builder,
9409 comptime kind: Constant.GetElementPtr.Kind,
9410 ty: Type,
9411 base: Constant,
9412 inrange: ?u16,
9413 indices: []const Constant,
9414) Allocator.Error!Value {
9415 return (try self.gepConst(kind, ty, base, inrange, indices)).toValue();
9416}
9417
9418pub fn binConst(
9419 self: *Builder,
9420 tag: Constant.Tag,
9421 lhs: Constant,
9422 rhs: Constant,
9423) Allocator.Error!Constant {
9424 try self.ensureUnusedConstantCapacity(1, Constant.Binary, 0);
9425 return self.binConstAssumeCapacity(tag, lhs, rhs);
9426}
9427
9428pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant) Allocator.Error!Value {
9429 return (try self.binConst(tag, lhs, rhs)).toValue();
9430}
9431
9432pub fn asmConst(
9433 self: *Builder,
9434 ty: Type,
9435 info: Constant.Assembly.Info,
9436 assembly: String,
9437 constraints: String,
9438) Allocator.Error!Constant {
9439 try self.ensureUnusedConstantCapacity(1, Constant.Assembly, 0);
9440 return self.asmConstAssumeCapacity(ty, info, assembly, constraints);
9441}
9442
9443pub fn asmValue(
9444 self: *Builder,
9445 ty: Type,
9446 info: Constant.Assembly.Info,
9447 assembly: String,
9448 constraints: String,
9449) Allocator.Error!Value {
9450 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
9451}
9452
9453pub fn dump(self: *Builder) void {
9454 self.print(std.io.getStdErr().writer()) catch {};
9455}
9456
9457pub fn printToFile(self: *Builder, path: []const u8) Allocator.Error!bool {
9458 var file = std.fs.cwd().createFile(path, .{}) catch |err| {
9459 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
9460 return false;
9461 };
9462 defer file.close();
9463 self.print(file.writer()) catch |err| {
9464 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
9465 return false;
9466 };
9467 return true;
9468}
9469
9470pub fn print(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
9471 var bw = std.io.bufferedWriter(writer);
9472 try self.printUnbuffered(bw.writer());
9473 try bw.flush();
9474}
9475
9476fn WriterWithErrors(comptime BackingWriter: type, comptime ExtraErrors: type) type {
9477 return struct {
9478 backing_writer: BackingWriter,
9479
9480 pub const Error = BackingWriter.Error || ExtraErrors;
9481 pub const Writer = std.io.Writer(*const Self, Error, write);
9482
9483 const Self = @This();
9484
9485 pub fn writer(self: *const Self) Writer {
9486 return .{ .context = self };
9487 }
9488
9489 pub fn write(self: *const Self, bytes: []const u8) Error!usize {
9490 return self.backing_writer.write(bytes);
9491 }
9492 };
9493}
9494fn writerWithErrors(
9495 backing_writer: anytype,
9496 comptime ExtraErrors: type,
9497) WriterWithErrors(@TypeOf(backing_writer), ExtraErrors) {
9498 return .{ .backing_writer = backing_writer };
9499}
9500
9501pub fn printUnbuffered(
9502 self: *Builder,
9503 backing_writer: anytype,
9504) (@TypeOf(backing_writer).Error || Allocator.Error)!void {
9505 const writer_with_errors = writerWithErrors(backing_writer, Allocator.Error);
9506 const writer = writer_with_errors.writer();
9507
9508 var need_newline = false;
9509 var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined };
9510 defer metadata_formatter.map.deinit(self.gpa);
9511
9512 if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) {
9513 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9514 if (self.source_filename != .none) try writer.print(
9515 \\; ModuleID = '{s}'
9516 \\source_filename = {"}
9517 \\
9518 , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) });
9519 if (self.data_layout != .none) try writer.print(
9520 \\target datalayout = {"}
9521 \\
9522 , .{self.data_layout.fmt(self)});
9523 if (self.target_triple != .none) try writer.print(
9524 \\target triple = {"}
9525 \\
9526 , .{self.target_triple.fmt(self)});
9527 }
9528
9529 if (self.module_asm.items.len > 0) {
9530 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9531 var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n');
9532 while (line_it.next()) |line| {
9533 try writer.writeAll("module asm ");
9534 try printEscapedString(line, .always_quote, writer);
9535 try writer.writeByte('\n');
9536 }
9537 }
9538
9539 if (self.types.count() > 0) {
9540 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9541 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
9542 \\%{} = type {}
9543 \\
9544 , .{ id.fmt(self), ty.fmt(self) });
9545 }
9546
9547 if (self.variables.items.len > 0) {
9548 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9549 for (self.variables.items) |variable| {
9550 if (variable.global.getReplacement(self) != .none) continue;
9551 const global = variable.global.ptrConst(self);
9552 metadata_formatter.need_comma = true;
9553 defer metadata_formatter.need_comma = undefined;
9554 try writer.print(
9555 \\{} ={}{}{}{}{ }{}{ }{} {s} {%}{ }{, }{}
9556 \\
9557 , .{
9558 variable.global.fmt(self),
9559 Linkage.fmtOptional(if (global.linkage == .external and
9560 variable.init != .no_init) null else global.linkage),
9561 global.preemption,
9562 global.visibility,
9563 global.dll_storage_class,
9564 variable.thread_local,
9565 global.unnamed_addr,
9566 global.addr_space,
9567 global.externally_initialized,
9568 @tagName(variable.mutability),
9569 global.type.fmt(self),
9570 variable.init.fmt(self),
9571 variable.alignment,
9572 try metadata_formatter.fmt("!dbg ", global.dbg),
9573 });
9574 }
9575 }
9576
9577 if (self.aliases.items.len > 0) {
9578 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9579 for (self.aliases.items) |alias| {
9580 if (alias.global.getReplacement(self) != .none) continue;
9581 const global = alias.global.ptrConst(self);
9582 metadata_formatter.need_comma = true;
9583 defer metadata_formatter.need_comma = undefined;
9584 try writer.print(
9585 \\{} ={}{}{}{}{ }{} alias {%}, {%}{}
9586 \\
9587 , .{
9588 alias.global.fmt(self),
9589 global.linkage,
9590 global.preemption,
9591 global.visibility,
9592 global.dll_storage_class,
9593 alias.thread_local,
9594 global.unnamed_addr,
9595 global.type.fmt(self),
9596 alias.aliasee.fmt(self),
9597 try metadata_formatter.fmt("!dbg ", global.dbg),
9598 });
9599 }
9600 }
9601
9602 var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .empty;
9603 defer attribute_groups.deinit(self.gpa);
9604
9605 for (0.., self.functions.items) |function_i, function| {
9606 if (function.global.getReplacement(self) != .none) continue;
9607 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9608 const function_index: Function.Index = @enumFromInt(function_i);
9609 const global = function.global.ptrConst(self);
9610 const params_len = global.type.functionParameters(self).len;
9611 const function_attributes = function.attributes.func(self);
9612 if (function_attributes != .none) try writer.print(
9613 \\; Function Attrs:{}
9614 \\
9615 , .{function_attributes.fmt(self)});
9616 try writer.print(
9617 \\{s}{}{}{}{}{}{"} {%} {}(
9618 , .{
9619 if (function.instructions.len > 0) "define" else "declare",
9620 global.linkage,
9621 global.preemption,
9622 global.visibility,
9623 global.dll_storage_class,
9624 function.call_conv,
9625 function.attributes.ret(self).fmt(self),
9626 global.type.functionReturn(self).fmt(self),
9627 function.global.fmt(self),
9628 });
9629 for (0..params_len) |arg| {
9630 if (arg > 0) try writer.writeAll(", ");
9631 try writer.print(
9632 \\{%}{"}
9633 , .{
9634 global.type.functionParameters(self)[arg].fmt(self),
9635 function.attributes.param(arg, self).fmt(self),
9636 });
9637 if (function.instructions.len > 0)
9638 try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)})
9639 else
9640 try writer.print(" %{d}", .{arg});
9641 }
9642 switch (global.type.functionKind(self)) {
9643 .normal => {},
9644 .vararg => {
9645 if (params_len > 0) try writer.writeAll(", ");
9646 try writer.writeAll("...");
9647 },
9648 }
9649 try writer.print("){}{ }", .{ global.unnamed_addr, global.addr_space });
9650 if (function_attributes != .none) try writer.print(" #{d}", .{
9651 (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
9652 });
9653 {
9654 metadata_formatter.need_comma = false;
9655 defer metadata_formatter.need_comma = undefined;
9656 try writer.print("{ }{}", .{
9657 function.alignment,
9658 try metadata_formatter.fmt(" !dbg ", global.dbg),
9659 });
9660 }
9661 if (function.instructions.len > 0) {
9662 var block_incoming_len: u32 = undefined;
9663 try writer.writeAll(" {\n");
9664 var maybe_dbg_index: ?u32 = null;
9665 for (params_len..function.instructions.len) |instruction_i| {
9666 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
9667 const instruction = function.instructions.get(@intFromEnum(instruction_index));
9668 if (function.debug_locations.get(instruction_index)) |debug_location| switch (debug_location) {
9669 .no_location => maybe_dbg_index = null,
9670 .location => |location| {
9671 const gop = try metadata_formatter.map.getOrPut(self.gpa, .{
9672 .debug_location = location,
9673 });
9674 maybe_dbg_index = @intCast(gop.index);
9675 },
9676 };
9677 switch (instruction.tag) {
9678 .add,
9679 .@"add nsw",
9680 .@"add nuw",
9681 .@"add nuw nsw",
9682 .@"and",
9683 .ashr,
9684 .@"ashr exact",
9685 .fadd,
9686 .@"fadd fast",
9687 .@"fcmp false",
9688 .@"fcmp fast false",
9689 .@"fcmp fast oeq",
9690 .@"fcmp fast oge",
9691 .@"fcmp fast ogt",
9692 .@"fcmp fast ole",
9693 .@"fcmp fast olt",
9694 .@"fcmp fast one",
9695 .@"fcmp fast ord",
9696 .@"fcmp fast true",
9697 .@"fcmp fast ueq",
9698 .@"fcmp fast uge",
9699 .@"fcmp fast ugt",
9700 .@"fcmp fast ule",
9701 .@"fcmp fast ult",
9702 .@"fcmp fast une",
9703 .@"fcmp fast uno",
9704 .@"fcmp oeq",
9705 .@"fcmp oge",
9706 .@"fcmp ogt",
9707 .@"fcmp ole",
9708 .@"fcmp olt",
9709 .@"fcmp one",
9710 .@"fcmp ord",
9711 .@"fcmp true",
9712 .@"fcmp ueq",
9713 .@"fcmp uge",
9714 .@"fcmp ugt",
9715 .@"fcmp ule",
9716 .@"fcmp ult",
9717 .@"fcmp une",
9718 .@"fcmp uno",
9719 .fdiv,
9720 .@"fdiv fast",
9721 .fmul,
9722 .@"fmul fast",
9723 .frem,
9724 .@"frem fast",
9725 .fsub,
9726 .@"fsub fast",
9727 .@"icmp eq",
9728 .@"icmp ne",
9729 .@"icmp sge",
9730 .@"icmp sgt",
9731 .@"icmp sle",
9732 .@"icmp slt",
9733 .@"icmp uge",
9734 .@"icmp ugt",
9735 .@"icmp ule",
9736 .@"icmp ult",
9737 .lshr,
9738 .@"lshr exact",
9739 .mul,
9740 .@"mul nsw",
9741 .@"mul nuw",
9742 .@"mul nuw nsw",
9743 .@"or",
9744 .sdiv,
9745 .@"sdiv exact",
9746 .srem,
9747 .shl,
9748 .@"shl nsw",
9749 .@"shl nuw",
9750 .@"shl nuw nsw",
9751 .sub,
9752 .@"sub nsw",
9753 .@"sub nuw",
9754 .@"sub nuw nsw",
9755 .udiv,
9756 .@"udiv exact",
9757 .urem,
9758 .xor,
9759 => |tag| {
9760 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
9761 try writer.print(" %{} = {s} {%}, {}", .{
9762 instruction_index.name(&function).fmt(self),
9763 @tagName(tag),
9764 extra.lhs.fmt(function_index, self),
9765 extra.rhs.fmt(function_index, self),
9766 });
9767 },
9768 .addrspacecast,
9769 .bitcast,
9770 .fpext,
9771 .fptosi,
9772 .fptoui,
9773 .fptrunc,
9774 .inttoptr,
9775 .ptrtoint,
9776 .sext,
9777 .sitofp,
9778 .trunc,
9779 .uitofp,
9780 .zext,
9781 => |tag| {
9782 const extra = function.extraData(Function.Instruction.Cast, instruction.data);
9783 try writer.print(" %{} = {s} {%} to {%}", .{
9784 instruction_index.name(&function).fmt(self),
9785 @tagName(tag),
9786 extra.val.fmt(function_index, self),
9787 extra.type.fmt(self),
9788 });
9789 },
9790 .alloca,
9791 .@"alloca inalloca",
9792 => |tag| {
9793 const extra = function.extraData(Function.Instruction.Alloca, instruction.data);
9794 try writer.print(" %{} = {s} {%}{,%}{, }{, }", .{
9795 instruction_index.name(&function).fmt(self),
9796 @tagName(tag),
9797 extra.type.fmt(self),
9798 Value.fmt(switch (extra.len) {
9799 .@"1" => .none,
9800 else => extra.len,
9801 }, function_index, self),
9802 extra.info.alignment,
9803 extra.info.addr_space,
9804 });
9805 },
9806 .arg => unreachable,
9807 .atomicrmw => |tag| {
9808 const extra =
9809 function.extraData(Function.Instruction.AtomicRmw, instruction.data);
9810 try writer.print(" %{} = {s}{ } {s} {%}, {%}{ }{ }{, }", .{
9811 instruction_index.name(&function).fmt(self),
9812 @tagName(tag),
9813 extra.info.access_kind,
9814 @tagName(extra.info.atomic_rmw_operation),
9815 extra.ptr.fmt(function_index, self),
9816 extra.val.fmt(function_index, self),
9817 extra.info.sync_scope,
9818 extra.info.success_ordering,
9819 extra.info.alignment,
9820 });
9821 },
9822 .block => {
9823 block_incoming_len = instruction.data;
9824 const name = instruction_index.name(&function);
9825 if (@intFromEnum(instruction_index) > params_len)
9826 try writer.writeByte('\n');
9827 try writer.print("{}:\n", .{name.fmt(self)});
9828 continue;
9829 },
9830 .br => |tag| {
9831 const target: Function.Block.Index = @enumFromInt(instruction.data);
9832 try writer.print(" {s} {%}", .{
9833 @tagName(tag), target.toInst(&function).fmt(function_index, self),
9834 });
9835 },
9836 .br_cond => {
9837 const extra = function.extraData(Function.Instruction.BrCond, instruction.data);
9838 try writer.print(" br {%}, {%}, {%}", .{
9839 extra.cond.fmt(function_index, self),
9840 extra.then.toInst(&function).fmt(function_index, self),
9841 extra.@"else".toInst(&function).fmt(function_index, self),
9842 });
9843 metadata_formatter.need_comma = true;
9844 defer metadata_formatter.need_comma = undefined;
9845 switch (extra.weights) {
9846 .none => {},
9847 .unpredictable => try writer.writeAll("!unpredictable !{}"),
9848 _ => try writer.print("{}", .{
9849 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.weights)))),
9850 }),
9851 }
9852 },
9853 .call,
9854 .@"call fast",
9855 .@"musttail call",
9856 .@"musttail call fast",
9857 .@"notail call",
9858 .@"notail call fast",
9859 .@"tail call",
9860 .@"tail call fast",
9861 => |tag| {
9862 var extra =
9863 function.extraDataTrail(Function.Instruction.Call, instruction.data);
9864 const args = extra.trail.next(extra.data.args_len, Value, &function);
9865 try writer.writeAll(" ");
9866 const ret_ty = extra.data.ty.functionReturn(self);
9867 switch (ret_ty) {
9868 .void => {},
9869 else => try writer.print("%{} = ", .{
9870 instruction_index.name(&function).fmt(self),
9871 }),
9872 .none => unreachable,
9873 }
9874 try writer.print("{s}{}{}{} {%} {}(", .{
9875 @tagName(tag),
9876 extra.data.info.call_conv,
9877 extra.data.attributes.ret(self).fmt(self),
9878 extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
9879 switch (extra.data.ty.functionKind(self)) {
9880 .normal => ret_ty,
9881 .vararg => extra.data.ty,
9882 }.fmt(self),
9883 extra.data.callee.fmt(function_index, self),
9884 });
9885 for (0.., args) |arg_index, arg| {
9886 if (arg_index > 0) try writer.writeAll(", ");
9887 metadata_formatter.need_comma = false;
9888 defer metadata_formatter.need_comma = undefined;
9889 try writer.print("{%}{}{}", .{
9890 arg.typeOf(function_index, self).fmt(self),
9891 extra.data.attributes.param(arg_index, self).fmt(self),
9892 try metadata_formatter.fmtLocal(" ", arg, function_index),
9893 });
9894 }
9895 try writer.writeByte(')');
9896 if (extra.data.info.has_op_bundle_cold) {
9897 try writer.writeAll(" [ \"cold\"() ]");
9898 }
9899 const call_function_attributes = extra.data.attributes.func(self);
9900 if (call_function_attributes != .none) try writer.print(" #{d}", .{
9901 (try attribute_groups.getOrPutValue(
9902 self.gpa,
9903 call_function_attributes,
9904 {},
9905 )).index,
9906 });
9907 },
9908 .cmpxchg,
9909 .@"cmpxchg weak",
9910 => |tag| {
9911 const extra =
9912 function.extraData(Function.Instruction.CmpXchg, instruction.data);
9913 try writer.print(" %{} = {s}{ } {%}, {%}, {%}{ }{ }{ }{, }", .{
9914 instruction_index.name(&function).fmt(self),
9915 @tagName(tag),
9916 extra.info.access_kind,
9917 extra.ptr.fmt(function_index, self),
9918 extra.cmp.fmt(function_index, self),
9919 extra.new.fmt(function_index, self),
9920 extra.info.sync_scope,
9921 extra.info.success_ordering,
9922 extra.info.failure_ordering,
9923 extra.info.alignment,
9924 });
9925 },
9926 .extractelement => |tag| {
9927 const extra =
9928 function.extraData(Function.Instruction.ExtractElement, instruction.data);
9929 try writer.print(" %{} = {s} {%}, {%}", .{
9930 instruction_index.name(&function).fmt(self),
9931 @tagName(tag),
9932 extra.val.fmt(function_index, self),
9933 extra.index.fmt(function_index, self),
9934 });
9935 },
9936 .extractvalue => |tag| {
9937 var extra = function.extraDataTrail(
9938 Function.Instruction.ExtractValue,
9939 instruction.data,
9940 );
9941 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
9942 try writer.print(" %{} = {s} {%}", .{
9943 instruction_index.name(&function).fmt(self),
9944 @tagName(tag),
9945 extra.data.val.fmt(function_index, self),
9946 });
9947 for (indices) |index| try writer.print(", {d}", .{index});
9948 },
9949 .fence => |tag| {
9950 const info: MemoryAccessInfo = @bitCast(instruction.data);
9951 try writer.print(" {s}{ }{ }", .{
9952 @tagName(tag),
9953 info.sync_scope,
9954 info.success_ordering,
9955 });
9956 },
9957 .fneg,
9958 .@"fneg fast",
9959 => |tag| {
9960 const val: Value = @enumFromInt(instruction.data);
9961 try writer.print(" %{} = {s} {%}", .{
9962 instruction_index.name(&function).fmt(self),
9963 @tagName(tag),
9964 val.fmt(function_index, self),
9965 });
9966 },
9967 .getelementptr,
9968 .@"getelementptr inbounds",
9969 => |tag| {
9970 var extra = function.extraDataTrail(
9971 Function.Instruction.GetElementPtr,
9972 instruction.data,
9973 );
9974 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
9975 try writer.print(" %{} = {s} {%}, {%}", .{
9976 instruction_index.name(&function).fmt(self),
9977 @tagName(tag),
9978 extra.data.type.fmt(self),
9979 extra.data.base.fmt(function_index, self),
9980 });
9981 for (indices) |index| try writer.print(", {%}", .{
9982 index.fmt(function_index, self),
9983 });
9984 },
9985 .indirectbr => |tag| {
9986 var extra =
9987 function.extraDataTrail(Function.Instruction.IndirectBr, instruction.data);
9988 const targets =
9989 extra.trail.next(extra.data.targets_len, Function.Block.Index, &function);
9990 try writer.print(" {s} {%}, [", .{
9991 @tagName(tag),
9992 extra.data.addr.fmt(function_index, self),
9993 });
9994 for (0.., targets) |target_index, target| {
9995 if (target_index > 0) try writer.writeAll(", ");
9996 try writer.print("{%}", .{
9997 target.toInst(&function).fmt(function_index, self),
9998 });
9999 }
10000 try writer.writeByte(']');
10001 },
10002 .insertelement => |tag| {
10003 const extra =
10004 function.extraData(Function.Instruction.InsertElement, instruction.data);
10005 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10006 instruction_index.name(&function).fmt(self),
10007 @tagName(tag),
10008 extra.val.fmt(function_index, self),
10009 extra.elem.fmt(function_index, self),
10010 extra.index.fmt(function_index, self),
10011 });
10012 },
10013 .insertvalue => |tag| {
10014 var extra =
10015 function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
10016 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
10017 try writer.print(" %{} = {s} {%}, {%}", .{
10018 instruction_index.name(&function).fmt(self),
10019 @tagName(tag),
10020 extra.data.val.fmt(function_index, self),
10021 extra.data.elem.fmt(function_index, self),
10022 });
10023 for (indices) |index| try writer.print(", {d}", .{index});
10024 },
10025 .load,
10026 .@"load atomic",
10027 => |tag| {
10028 const extra = function.extraData(Function.Instruction.Load, instruction.data);
10029 try writer.print(" %{} = {s}{ } {%}, {%}{ }{ }{, }", .{
10030 instruction_index.name(&function).fmt(self),
10031 @tagName(tag),
10032 extra.info.access_kind,
10033 extra.type.fmt(self),
10034 extra.ptr.fmt(function_index, self),
10035 extra.info.sync_scope,
10036 extra.info.success_ordering,
10037 extra.info.alignment,
10038 });
10039 },
10040 .phi,
10041 .@"phi fast",
10042 => |tag| {
10043 var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data);
10044 const vals = extra.trail.next(block_incoming_len, Value, &function);
10045 const blocks =
10046 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
10047 try writer.print(" %{} = {s} {%} ", .{
10048 instruction_index.name(&function).fmt(self),
10049 @tagName(tag),
10050 vals[0].typeOf(function_index, self).fmt(self),
10051 });
10052 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
10053 if (incoming_index > 0) try writer.writeAll(", ");
10054 try writer.print("[ {}, {} ]", .{
10055 incoming_val.fmt(function_index, self),
10056 incoming_block.toInst(&function).fmt(function_index, self),
10057 });
10058 }
10059 },
10060 .ret => |tag| {
10061 const val: Value = @enumFromInt(instruction.data);
10062 try writer.print(" {s} {%}", .{
10063 @tagName(tag),
10064 val.fmt(function_index, self),
10065 });
10066 },
10067 .@"ret void",
10068 .@"unreachable",
10069 => |tag| try writer.print(" {s}", .{@tagName(tag)}),
10070 .select,
10071 .@"select fast",
10072 => |tag| {
10073 const extra = function.extraData(Function.Instruction.Select, instruction.data);
10074 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10075 instruction_index.name(&function).fmt(self),
10076 @tagName(tag),
10077 extra.cond.fmt(function_index, self),
10078 extra.lhs.fmt(function_index, self),
10079 extra.rhs.fmt(function_index, self),
10080 });
10081 },
10082 .shufflevector => |tag| {
10083 const extra =
10084 function.extraData(Function.Instruction.ShuffleVector, instruction.data);
10085 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10086 instruction_index.name(&function).fmt(self),
10087 @tagName(tag),
10088 extra.lhs.fmt(function_index, self),
10089 extra.rhs.fmt(function_index, self),
10090 extra.mask.fmt(function_index, self),
10091 });
10092 },
10093 .store,
10094 .@"store atomic",
10095 => |tag| {
10096 const extra = function.extraData(Function.Instruction.Store, instruction.data);
10097 try writer.print(" {s}{ } {%}, {%}{ }{ }{, }", .{
10098 @tagName(tag),
10099 extra.info.access_kind,
10100 extra.val.fmt(function_index, self),
10101 extra.ptr.fmt(function_index, self),
10102 extra.info.sync_scope,
10103 extra.info.success_ordering,
10104 extra.info.alignment,
10105 });
10106 },
10107 .@"switch" => |tag| {
10108 var extra =
10109 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
10110 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
10111 const blocks =
10112 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
10113 try writer.print(" {s} {%}, {%} [\n", .{
10114 @tagName(tag),
10115 extra.data.val.fmt(function_index, self),
10116 extra.data.default.toInst(&function).fmt(function_index, self),
10117 });
10118 for (vals, blocks) |case_val, case_block| try writer.print(
10119 " {%}, {%}\n",
10120 .{
10121 case_val.fmt(self),
10122 case_block.toInst(&function).fmt(function_index, self),
10123 },
10124 );
10125 try writer.writeAll(" ]");
10126 metadata_formatter.need_comma = true;
10127 defer metadata_formatter.need_comma = undefined;
10128 switch (extra.data.weights) {
10129 .none => {},
10130 .unpredictable => try writer.writeAll("!unpredictable !{}"),
10131 _ => try writer.print("{}", .{
10132 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.data.weights)))),
10133 }),
10134 }
10135 },
10136 .va_arg => |tag| {
10137 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
10138 try writer.print(" %{} = {s} {%}, {%}", .{
10139 instruction_index.name(&function).fmt(self),
10140 @tagName(tag),
10141 extra.list.fmt(function_index, self),
10142 extra.type.fmt(self),
10143 });
10144 },
10145 }
10146
10147 if (maybe_dbg_index) |dbg_index| {
10148 try writer.print(", !dbg !{}", .{dbg_index});
10149 }
10150 try writer.writeByte('\n');
10151 }
10152 try writer.writeByte('}');
10153 }
10154 try writer.writeByte('\n');
10155 }
10156
10157 if (attribute_groups.count() > 0) {
10158 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10159 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
10160 try writer.print(
10161 \\attributes #{d} = {{{#"} }}
10162 \\
10163 , .{ attribute_group_index, attribute_group.fmt(self) });
10164 }
10165
10166 if (self.metadata_named.count() > 0) {
10167 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10168 for (self.metadata_named.keys(), self.metadata_named.values()) |name, data| {
10169 const elements: []const Metadata =
10170 @ptrCast(self.metadata_extra.items[data.index..][0..data.len]);
10171 try writer.writeByte('!');
10172 try printEscapedString(name.slice(self), .quote_unless_valid_identifier, writer);
10173 try writer.writeAll(" = !{");
10174 metadata_formatter.need_comma = false;
10175 defer metadata_formatter.need_comma = undefined;
10176 for (elements) |element| try writer.print("{}", .{try metadata_formatter.fmt("", element)});
10177 try writer.writeAll("}\n");
10178 }
10179 }
10180
10181 if (metadata_formatter.map.count() > 0) {
10182 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10183 var metadata_index: usize = 0;
10184 while (metadata_index < metadata_formatter.map.count()) : (metadata_index += 1) {
10185 @setEvalBranchQuota(10_000);
10186 try writer.print("!{} = ", .{metadata_index});
10187 metadata_formatter.need_comma = false;
10188 defer metadata_formatter.need_comma = undefined;
10189
10190 const key = metadata_formatter.map.keys()[metadata_index];
10191 const metadata_item = switch (key) {
10192 .debug_location => |location| {
10193 try metadata_formatter.specialized(.@"!", .DILocation, .{
10194 .line = location.line,
10195 .column = location.column,
10196 .scope = location.scope,
10197 .inlinedAt = location.inlined_at,
10198 .isImplicitCode = false,
10199 }, writer);
10200 continue;
10201 },
10202 .metadata => |metadata| self.metadata_items.get(@intFromEnum(metadata)),
10203 };
10204
10205 switch (metadata_item.tag) {
10206 .none, .expression, .constant => unreachable,
10207 .file => {
10208 const extra = self.metadataExtraData(Metadata.File, metadata_item.data);
10209 try metadata_formatter.specialized(.@"!", .DIFile, .{
10210 .filename = extra.filename,
10211 .directory = extra.directory,
10212 .checksumkind = null,
10213 .checksum = null,
10214 .source = null,
10215 }, writer);
10216 },
10217 .compile_unit,
10218 .@"compile_unit optimized",
10219 => |kind| {
10220 const extra = self.metadataExtraData(Metadata.CompileUnit, metadata_item.data);
10221 try metadata_formatter.specialized(.@"distinct !", .DICompileUnit, .{
10222 .language = .DW_LANG_C99,
10223 .file = extra.file,
10224 .producer = extra.producer,
10225 .isOptimized = switch (kind) {
10226 .compile_unit => false,
10227 .@"compile_unit optimized" => true,
10228 else => unreachable,
10229 },
10230 .flags = null,
10231 .runtimeVersion = 0,
10232 .splitDebugFilename = null,
10233 .emissionKind = .FullDebug,
10234 .enums = extra.enums,
10235 .retainedTypes = null,
10236 .globals = extra.globals,
10237 .imports = null,
10238 .macros = null,
10239 .dwoId = null,
10240 .splitDebugInlining = false,
10241 .debugInfoForProfiling = null,
10242 .nameTableKind = null,
10243 .rangesBaseAddress = null,
10244 .sysroot = null,
10245 .sdk = null,
10246 }, writer);
10247 },
10248 .subprogram,
10249 .@"subprogram local",
10250 .@"subprogram definition",
10251 .@"subprogram local definition",
10252 .@"subprogram optimized",
10253 .@"subprogram optimized local",
10254 .@"subprogram optimized definition",
10255 .@"subprogram optimized local definition",
10256 => |kind| {
10257 const extra = self.metadataExtraData(Metadata.Subprogram, metadata_item.data);
10258 try metadata_formatter.specialized(.@"distinct !", .DISubprogram, .{
10259 .name = extra.name,
10260 .linkageName = extra.linkage_name,
10261 .scope = extra.file,
10262 .file = extra.file,
10263 .line = extra.line,
10264 .type = extra.ty,
10265 .scopeLine = extra.scope_line,
10266 .containingType = null,
10267 .virtualIndex = null,
10268 .thisAdjustment = null,
10269 .flags = extra.di_flags,
10270 .spFlags = @as(Metadata.Subprogram.DISPFlags, @bitCast(@as(u32, @as(u3, @intCast(
10271 @intFromEnum(kind) - @intFromEnum(Metadata.Tag.subprogram),
10272 ))) << 2)),
10273 .unit = extra.compile_unit,
10274 .templateParams = null,
10275 .declaration = null,
10276 .retainedNodes = null,
10277 .thrownTypes = null,
10278 .annotations = null,
10279 .targetFuncName = null,
10280 }, writer);
10281 },
10282 .lexical_block => {
10283 const extra = self.metadataExtraData(Metadata.LexicalBlock, metadata_item.data);
10284 try metadata_formatter.specialized(.@"distinct !", .DILexicalBlock, .{
10285 .scope = extra.scope,
10286 .file = extra.file,
10287 .line = extra.line,
10288 .column = extra.column,
10289 }, writer);
10290 },
10291 .location => {
10292 const extra = self.metadataExtraData(Metadata.Location, metadata_item.data);
10293 try metadata_formatter.specialized(.@"!", .DILocation, .{
10294 .line = extra.line,
10295 .column = extra.column,
10296 .scope = extra.scope,
10297 .inlinedAt = extra.inlined_at,
10298 .isImplicitCode = false,
10299 }, writer);
10300 },
10301 .basic_bool_type,
10302 .basic_unsigned_type,
10303 .basic_signed_type,
10304 .basic_float_type,
10305 => |kind| {
10306 const extra = self.metadataExtraData(Metadata.BasicType, metadata_item.data);
10307 try metadata_formatter.specialized(.@"!", .DIBasicType, .{
10308 .tag = null,
10309 .name = switch (extra.name) {
10310 .none => null,
10311 else => extra.name,
10312 },
10313 .size = extra.bitSize(),
10314 .@"align" = null,
10315 .encoding = @as(enum {
10316 DW_ATE_boolean,
10317 DW_ATE_unsigned,
10318 DW_ATE_signed,
10319 DW_ATE_float,
10320 }, switch (kind) {
10321 .basic_bool_type => .DW_ATE_boolean,
10322 .basic_unsigned_type => .DW_ATE_unsigned,
10323 .basic_signed_type => .DW_ATE_signed,
10324 .basic_float_type => .DW_ATE_float,
10325 else => unreachable,
10326 }),
10327 .flags = null,
10328 }, writer);
10329 },
10330 .composite_struct_type,
10331 .composite_union_type,
10332 .composite_enumeration_type,
10333 .composite_array_type,
10334 .composite_vector_type,
10335 => |kind| {
10336 const extra = self.metadataExtraData(Metadata.CompositeType, metadata_item.data);
10337 try metadata_formatter.specialized(.@"!", .DICompositeType, .{
10338 .tag = @as(enum {
10339 DW_TAG_structure_type,
10340 DW_TAG_union_type,
10341 DW_TAG_enumeration_type,
10342 DW_TAG_array_type,
10343 }, switch (kind) {
10344 .composite_struct_type => .DW_TAG_structure_type,
10345 .composite_union_type => .DW_TAG_union_type,
10346 .composite_enumeration_type => .DW_TAG_enumeration_type,
10347 .composite_array_type, .composite_vector_type => .DW_TAG_array_type,
10348 else => unreachable,
10349 }),
10350 .name = switch (extra.name) {
10351 .none => null,
10352 else => extra.name,
10353 },
10354 .scope = extra.scope,
10355 .file = null,
10356 .line = null,
10357 .baseType = extra.underlying_type,
10358 .size = extra.bitSize(),
10359 .@"align" = extra.bitAlign(),
10360 .offset = null,
10361 .flags = null,
10362 .elements = extra.fields_tuple,
10363 .runtimeLang = null,
10364 .vtableHolder = null,
10365 .templateParams = null,
10366 .identifier = null,
10367 .discriminator = null,
10368 .dataLocation = null,
10369 .associated = null,
10370 .allocated = null,
10371 .rank = null,
10372 .annotations = null,
10373 }, writer);
10374 },
10375 .derived_pointer_type,
10376 .derived_member_type,
10377 => |kind| {
10378 const extra = self.metadataExtraData(Metadata.DerivedType, metadata_item.data);
10379 try metadata_formatter.specialized(.@"!", .DIDerivedType, .{
10380 .tag = @as(enum {
10381 DW_TAG_pointer_type,
10382 DW_TAG_member,
10383 }, switch (kind) {
10384 .derived_pointer_type => .DW_TAG_pointer_type,
10385 .derived_member_type => .DW_TAG_member,
10386 else => unreachable,
10387 }),
10388 .name = switch (extra.name) {
10389 .none => null,
10390 else => extra.name,
10391 },
10392 .scope = extra.scope,
10393 .file = null,
10394 .line = null,
10395 .baseType = extra.underlying_type,
10396 .size = extra.bitSize(),
10397 .@"align" = extra.bitAlign(),
10398 .offset = switch (extra.bitOffset()) {
10399 0 => null,
10400 else => |bit_offset| bit_offset,
10401 },
10402 .flags = null,
10403 .extraData = null,
10404 .dwarfAddressSpace = null,
10405 .annotations = null,
10406 }, writer);
10407 },
10408 .subroutine_type => {
10409 const extra = self.metadataExtraData(Metadata.SubroutineType, metadata_item.data);
10410 try metadata_formatter.specialized(.@"!", .DISubroutineType, .{
10411 .flags = null,
10412 .cc = null,
10413 .types = extra.types_tuple,
10414 }, writer);
10415 },
10416 .enumerator_unsigned,
10417 .enumerator_signed_positive,
10418 .enumerator_signed_negative,
10419 => |kind| {
10420 const extra = self.metadataExtraData(Metadata.Enumerator, metadata_item.data);
10421
10422 const ExpectedContents = extern struct {
10423 const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
10424 string: [
10425 (std.math.big.int.Const{
10426 .limbs = &([1]std.math.big.Limb{
10427 std.math.maxInt(std.math.big.Limb),
10428 } ** expected_limbs),
10429 .positive = false,
10430 }).sizeInBaseUpperBound(10)
10431 ]u8,
10432 limbs: [
10433 std.math.big.int.calcToStringLimbsBufferLen(expected_limbs, 10)
10434 ]std.math.big.Limb,
10435 };
10436 var stack align(@alignOf(ExpectedContents)) =
10437 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
10438 const allocator = stack.get();
10439
10440 const limbs = self.metadata_limbs.items[extra.limbs_index..][0..extra.limbs_len];
10441 const bigint: std.math.big.int.Const = .{
10442 .limbs = limbs,
10443 .positive = switch (kind) {
10444 .enumerator_unsigned,
10445 .enumerator_signed_positive,
10446 => true,
10447 .enumerator_signed_negative => false,
10448 else => unreachable,
10449 },
10450 };
10451 const str = try bigint.toStringAlloc(allocator, 10, undefined);
10452 defer allocator.free(str);
10453
10454 try metadata_formatter.specialized(.@"!", .DIEnumerator, .{
10455 .name = extra.name,
10456 .value = str,
10457 .isUnsigned = switch (kind) {
10458 .enumerator_unsigned => true,
10459 .enumerator_signed_positive,
10460 .enumerator_signed_negative,
10461 => false,
10462 else => unreachable,
10463 },
10464 }, writer);
10465 },
10466 .subrange => {
10467 const extra = self.metadataExtraData(Metadata.Subrange, metadata_item.data);
10468 try metadata_formatter.specialized(.@"!", .DISubrange, .{
10469 .count = extra.count,
10470 .lowerBound = extra.lower_bound,
10471 .upperBound = null,
10472 .stride = null,
10473 }, writer);
10474 },
10475 .tuple => {
10476 var extra = self.metadataExtraDataTrail(Metadata.Tuple, metadata_item.data);
10477 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
10478 try writer.writeAll("!{");
10479 for (elements) |element| try writer.print("{[element]%}", .{
10480 .element = try metadata_formatter.fmt("", element),
10481 });
10482 try writer.writeAll("}\n");
10483 },
10484 .str_tuple => {
10485 var extra = self.metadataExtraDataTrail(Metadata.StrTuple, metadata_item.data);
10486 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
10487 try writer.print("!{{{[str]%}", .{
10488 .str = try metadata_formatter.fmt("", extra.data.str),
10489 });
10490 for (elements) |element| try writer.print("{[element]%}", .{
10491 .element = try metadata_formatter.fmt("", element),
10492 });
10493 try writer.writeAll("}\n");
10494 },
10495 .module_flag => {
10496 const extra = self.metadataExtraData(Metadata.ModuleFlag, metadata_item.data);
10497 try writer.print("!{{{[behavior]%}{[name]%}{[constant]%}}}\n", .{
10498 .behavior = try metadata_formatter.fmt("", extra.behavior),
10499 .name = try metadata_formatter.fmt("", extra.name),
10500 .constant = try metadata_formatter.fmt("", extra.constant),
10501 });
10502 },
10503 .local_var => {
10504 const extra = self.metadataExtraData(Metadata.LocalVar, metadata_item.data);
10505 try metadata_formatter.specialized(.@"!", .DILocalVariable, .{
10506 .name = extra.name,
10507 .arg = null,
10508 .scope = extra.scope,
10509 .file = extra.file,
10510 .line = extra.line,
10511 .type = extra.ty,
10512 .flags = null,
10513 .@"align" = null,
10514 .annotations = null,
10515 }, writer);
10516 },
10517 .parameter => {
10518 const extra = self.metadataExtraData(Metadata.Parameter, metadata_item.data);
10519 try metadata_formatter.specialized(.@"!", .DILocalVariable, .{
10520 .name = extra.name,
10521 .arg = extra.arg_no,
10522 .scope = extra.scope,
10523 .file = extra.file,
10524 .line = extra.line,
10525 .type = extra.ty,
10526 .flags = null,
10527 .@"align" = null,
10528 .annotations = null,
10529 }, writer);
10530 },
10531 .global_var,
10532 .@"global_var local",
10533 => |kind| {
10534 const extra = self.metadataExtraData(Metadata.GlobalVar, metadata_item.data);
10535 try metadata_formatter.specialized(.@"distinct !", .DIGlobalVariable, .{
10536 .name = extra.name,
10537 .linkageName = extra.linkage_name,
10538 .scope = extra.scope,
10539 .file = extra.file,
10540 .line = extra.line,
10541 .type = extra.ty,
10542 .isLocal = switch (kind) {
10543 .global_var => false,
10544 .@"global_var local" => true,
10545 else => unreachable,
10546 },
10547 .isDefinition = true,
10548 .declaration = null,
10549 .templateParams = null,
10550 .@"align" = null,
10551 .annotations = null,
10552 }, writer);
10553 },
10554 .global_var_expression => {
10555 const extra =
10556 self.metadataExtraData(Metadata.GlobalVarExpression, metadata_item.data);
10557 try metadata_formatter.specialized(.@"!", .DIGlobalVariableExpression, .{
10558 .@"var" = extra.variable,
10559 .expr = extra.expression,
10560 }, writer);
10561 },
10562 }
10563 }
10564 }
10565}
10566
10567const NoExtra = struct {};
10568
10569fn isValidIdentifier(id: []const u8) bool {
10570 for (id, 0..) |byte, index| switch (byte) {
10571 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
10572 '0'...'9' => if (index == 0) return false,
10573 else => return false,
10574 };
10575 return true;
10576}
10577
10578const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier };
10579fn printEscapedString(
10580 slice: []const u8,
10581 quotes: QuoteBehavior,
10582 writer: anytype,
10583) @TypeOf(writer).Error!void {
10584 const need_quotes = switch (quotes) {
10585 .always_quote => true,
10586 .quote_unless_valid_identifier => !isValidIdentifier(slice),
10587 };
10588 if (need_quotes) try writer.writeByte('"');
10589 for (slice) |byte| switch (byte) {
10590 '\\' => try writer.writeAll("\\\\"),
10591 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte),
10592 else => try writer.print("\\{X:0>2}", .{byte}),
10593 };
10594 if (need_quotes) try writer.writeByte('"');
10595}
10596
10597fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void {
10598 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
10599 if (name.slice(self)) |id| {
10600 const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});
10601 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
10602 }
10603 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
10604 try self.globals.ensureUnusedCapacity(self.gpa, 1);
10605 try self.next_unique_global_id.ensureUnusedCapacity(self.gpa, 1);
10606}
10607
10608fn fnTypeAssumeCapacity(
10609 self: *Builder,
10610 ret: Type,
10611 params: []const Type,
10612 comptime kind: Type.Function.Kind,
10613) Type {
10614 const tag: Type.Tag = switch (kind) {
10615 .normal => .function,
10616 .vararg => .vararg_function,
10617 };
10618 const Key = struct { ret: Type, params: []const Type };
10619 const Adapter = struct {
10620 builder: *const Builder,
10621 pub fn hash(_: @This(), key: Key) u32 {
10622 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
10623 hasher.update(std.mem.asBytes(&key.ret));
10624 hasher.update(std.mem.sliceAsBytes(key.params));
10625 return @truncate(hasher.final());
10626 }
10627 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
10628 const rhs_data = ctx.builder.type_items.items[rhs_index];
10629 if (rhs_data.tag != tag) return false;
10630 var rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data);
10631 const rhs_params = rhs_extra.trail.next(rhs_extra.data.params_len, Type, ctx.builder);
10632 return lhs_key.ret == rhs_extra.data.ret and std.mem.eql(Type, lhs_key.params, rhs_params);
10633 }
10634 };
10635 const gop = self.type_map.getOrPutAssumeCapacityAdapted(
10636 Key{ .ret = ret, .params = params },
10637 Adapter{ .builder = self },
10638 );
10639 if (!gop.found_existing) {
10640 gop.key_ptr.* = {};
10641 gop.value_ptr.* = {};
10642 self.type_items.appendAssumeCapacity(.{
10643 .tag = tag,
10644 .data = self.addTypeExtraAssumeCapacity(Type.Function{
10645 .ret = ret,
10646 .params_len = @intCast(params.len),
10647 }),
10648 });
10649 self.type_extra.appendSliceAssumeCapacity(@ptrCast(params));
10650 }
10651 return @enumFromInt(gop.index);
10652}
10653
10654fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
10655 assert(bits > 0);
10656 const result = self.getOrPutTypeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
10657 return result.type;
10658}
10659
10660fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {
10661 const result = self.getOrPutTypeNoExtraAssumeCapacity(
10662 .{ .tag = .pointer, .data = @intFromEnum(addr_space) },
10663 );
10664 return result.type;
10665}
10666
10667fn vectorTypeAssumeCapacity(
10668 self: *Builder,
10669 comptime kind: Type.Vector.Kind,
10670 len: u32,
10671 child: Type,
10672) Type {
10673 assert(child.isFloatingPoint() or child.isInteger(self) or child.isPointer(self));
10674 const tag: Type.Tag = switch (kind) {
10675 .normal => .vector,
10676 .scalable => .scalable_vector,
10677 };
10678 const Adapter = struct {
10679 builder: *const Builder,
10680 pub fn hash(_: @This(), key: Type.Vector) u32 {
10681 return @truncate(std.hash.Wyhash.hash(
10682 comptime std.hash.uint32(@intFromEnum(tag)),
10683 std.mem.asBytes(&key),
10684 ));
10685 }
10686 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
10687 const rhs_data = ctx.builder.type_items.items[rhs_index];
10688 return rhs_data.tag == tag and
10689 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
10690 }
10691 };
10692 const data = Type.Vector{ .len = len, .child = child };
10693 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10694 if (!gop.found_existing) {
10695 gop.key_ptr.* = {};
10696 gop.value_ptr.* = {};
10697 self.type_items.appendAssumeCapacity(.{
10698 .tag = tag,
10699 .data = self.addTypeExtraAssumeCapacity(data),
10700 });
10701 }
10702 return @enumFromInt(gop.index);
10703}
10704
10705fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
10706 if (std.math.cast(u32, len)) |small_len| {
10707 const Adapter = struct {
10708 builder: *const Builder,
10709 pub fn hash(_: @This(), key: Type.Vector) u32 {
10710 return @truncate(std.hash.Wyhash.hash(
10711 comptime std.hash.uint32(@intFromEnum(Type.Tag.small_array)),
10712 std.mem.asBytes(&key),
10713 ));
10714 }
10715 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
10716 const rhs_data = ctx.builder.type_items.items[rhs_index];
10717 return rhs_data.tag == .small_array and
10718 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
10719 }
10720 };
10721 const data = Type.Vector{ .len = small_len, .child = child };
10722 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10723 if (!gop.found_existing) {
10724 gop.key_ptr.* = {};
10725 gop.value_ptr.* = {};
10726 self.type_items.appendAssumeCapacity(.{
10727 .tag = .small_array,
10728 .data = self.addTypeExtraAssumeCapacity(data),
10729 });
10730 }
10731 return @enumFromInt(gop.index);
10732 } else {
10733 const Adapter = struct {
10734 builder: *const Builder,
10735 pub fn hash(_: @This(), key: Type.Array) u32 {
10736 return @truncate(std.hash.Wyhash.hash(
10737 comptime std.hash.uint32(@intFromEnum(Type.Tag.array)),
10738 std.mem.asBytes(&key),
10739 ));
10740 }
10741 pub fn eql(ctx: @This(), lhs_key: Type.Array, _: void, rhs_index: usize) bool {
10742 const rhs_data = ctx.builder.type_items.items[rhs_index];
10743 return rhs_data.tag == .array and
10744 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Array, rhs_data.data));
10745 }
10746 };
10747 const data = Type.Array{
10748 .len_lo = @truncate(len),
10749 .len_hi = @intCast(len >> 32),
10750 .child = child,
10751 };
10752 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10753 if (!gop.found_existing) {
10754 gop.key_ptr.* = {};
10755 gop.value_ptr.* = {};
10756 self.type_items.appendAssumeCapacity(.{
10757 .tag = .array,
10758 .data = self.addTypeExtraAssumeCapacity(data),
10759 });
10760 }
10761 return @enumFromInt(gop.index);
10762 }
10763}
10764
10765fn structTypeAssumeCapacity(
10766 self: *Builder,
10767 comptime kind: Type.Structure.Kind,
10768 fields: []const Type,
10769) Type {
10770 const tag: Type.Tag = switch (kind) {
10771 .normal => .structure,
10772 .@"packed" => .packed_structure,
10773 };
10774 const Adapter = struct {
10775 builder: *const Builder,
10776 pub fn hash(_: @This(), key: []const Type) u32 {
10777 return @truncate(std.hash.Wyhash.hash(
10778 comptime std.hash.uint32(@intFromEnum(tag)),
10779 std.mem.sliceAsBytes(key),
10780 ));
10781 }
10782 pub fn eql(ctx: @This(), lhs_key: []const Type, _: void, rhs_index: usize) bool {
10783 const rhs_data = ctx.builder.type_items.items[rhs_index];
10784 if (rhs_data.tag != tag) return false;
10785 var rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data);
10786 const rhs_fields = rhs_extra.trail.next(rhs_extra.data.fields_len, Type, ctx.builder);
10787 return std.mem.eql(Type, lhs_key, rhs_fields);
10788 }
10789 };
10790 const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self });
10791 if (!gop.found_existing) {
10792 gop.key_ptr.* = {};
10793 gop.value_ptr.* = {};
10794 self.type_items.appendAssumeCapacity(.{
10795 .tag = tag,
10796 .data = self.addTypeExtraAssumeCapacity(Type.Structure{
10797 .fields_len = @intCast(fields.len),
10798 }),
10799 });
10800 self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
10801 }
10802 return @enumFromInt(gop.index);
10803}
10804
10805fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
10806 const Adapter = struct {
10807 builder: *const Builder,
10808 pub fn hash(_: @This(), key: String) u32 {
10809 return @truncate(std.hash.Wyhash.hash(
10810 comptime std.hash.uint32(@intFromEnum(Type.Tag.named_structure)),
10811 std.mem.asBytes(&key),
10812 ));
10813 }
10814 pub fn eql(ctx: @This(), lhs_key: String, _: void, rhs_index: usize) bool {
10815 const rhs_data = ctx.builder.type_items.items[rhs_index];
10816 return rhs_data.tag == .named_structure and
10817 lhs_key == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
10818 }
10819 };
10820 var id = name;
10821 if (name == .empty) {
10822 id = self.next_unnamed_type;
10823 assert(id != .none);
10824 self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1);
10825 } else assert(!name.isAnon());
10826 while (true) {
10827 const type_gop = self.types.getOrPutAssumeCapacity(id);
10828 if (!type_gop.found_existing) {
10829 const gop = self.type_map.getOrPutAssumeCapacityAdapted(id, Adapter{ .builder = self });
10830 assert(!gop.found_existing);
10831 gop.key_ptr.* = {};
10832 gop.value_ptr.* = {};
10833 self.type_items.appendAssumeCapacity(.{
10834 .tag = .named_structure,
10835 .data = self.addTypeExtraAssumeCapacity(Type.NamedStructure{
10836 .id = id,
10837 .body = .none,
10838 }),
10839 });
10840 const result: Type = @enumFromInt(gop.index);
10841 type_gop.value_ptr.* = result;
10842 return result;
10843 }
10844
10845 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
10846 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
10847 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
10848 unique_gop.value_ptr.* += 1;
10849 }
10850}
10851
10852fn ensureUnusedTypeCapacity(
10853 self: *Builder,
10854 count: usize,
10855 comptime Extra: type,
10856 trail_len: usize,
10857) Allocator.Error!void {
10858 try self.type_map.ensureUnusedCapacity(self.gpa, count);
10859 try self.type_items.ensureUnusedCapacity(self.gpa, count);
10860 try self.type_extra.ensureUnusedCapacity(
10861 self.gpa,
10862 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
10863 );
10864}
10865
10866fn getOrPutTypeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {
10867 const Adapter = struct {
10868 builder: *const Builder,
10869 pub fn hash(_: @This(), key: Type.Item) u32 {
10870 return @truncate(std.hash.Wyhash.hash(
10871 comptime std.hash.uint32(@intFromEnum(Type.Tag.simple)),
10872 std.mem.asBytes(&key),
10873 ));
10874 }
10875 pub fn eql(ctx: @This(), lhs_key: Type.Item, _: void, rhs_index: usize) bool {
10876 const lhs_bits: u32 = @bitCast(lhs_key);
10877 const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]);
10878 return lhs_bits == rhs_bits;
10879 }
10880 };
10881 const gop = self.type_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
10882 if (!gop.found_existing) {
10883 gop.key_ptr.* = {};
10884 gop.value_ptr.* = {};
10885 self.type_items.appendAssumeCapacity(item);
10886 }
10887 return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) };
10888}
10889
10890fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.Item.ExtraIndex {
10891 const result: Type.Item.ExtraIndex = @intCast(self.type_extra.items.len);
10892 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
10893 const value = @field(extra, field.name);
10894 self.type_extra.appendAssumeCapacity(switch (field.type) {
10895 u32 => value,
10896 String, Type => @intFromEnum(value),
10897 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
10898 });
10899 }
10900 return result;
10901}
10902
10903const TypeExtraDataTrail = struct {
10904 index: Type.Item.ExtraIndex,
10905
10906 fn nextMut(self: *TypeExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
10907 const items: []Item = @ptrCast(builder.type_extra.items[self.index..][0..len]);
10908 self.index += @intCast(len);
10909 return items;
10910 }
10911
10912 fn next(
10913 self: *TypeExtraDataTrail,
10914 len: u32,
10915 comptime Item: type,
10916 builder: *const Builder,
10917 ) []const Item {
10918 const items: []const Item = @ptrCast(builder.type_extra.items[self.index..][0..len]);
10919 self.index += @intCast(len);
10920 return items;
10921 }
10922};
10923
10924fn typeExtraDataTrail(
10925 self: *const Builder,
10926 comptime T: type,
10927 index: Type.Item.ExtraIndex,
10928) struct { data: T, trail: TypeExtraDataTrail } {
10929 var result: T = undefined;
10930 const fields = @typeInfo(T).@"struct".fields;
10931 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, value|
10932 @field(result, field.name) = switch (field.type) {
10933 u32 => value,
10934 String, Type => @enumFromInt(value),
10935 else => @compileError("bad field type: " ++ @typeName(field.type)),
10936 };
10937 return .{
10938 .data = result,
10939 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
10940 };
10941}
10942
10943fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraIndex) T {
10944 return self.typeExtraDataTrail(T, index).data;
10945}
10946
10947fn attrGeneric(self: *Builder, data: []const u32) Allocator.Error!u32 {
10948 try self.attributes_map.ensureUnusedCapacity(self.gpa, 1);
10949 try self.attributes_indices.ensureUnusedCapacity(self.gpa, 1);
10950 try self.attributes_extra.ensureUnusedCapacity(self.gpa, data.len);
10951
10952 const Adapter = struct {
10953 builder: *const Builder,
10954 pub fn hash(_: @This(), key: []const u32) u32 {
10955 return @truncate(std.hash.Wyhash.hash(1, std.mem.sliceAsBytes(key)));
10956 }
10957 pub fn eql(ctx: @This(), lhs_key: []const u32, _: void, rhs_index: usize) bool {
10958 const start = ctx.builder.attributes_indices.items[rhs_index];
10959 const end = ctx.builder.attributes_indices.items[rhs_index + 1];
10960 return std.mem.eql(u32, lhs_key, ctx.builder.attributes_extra.items[start..end]);
10961 }
10962 };
10963 const gop = self.attributes_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
10964 if (!gop.found_existing) {
10965 self.attributes_extra.appendSliceAssumeCapacity(data);
10966 self.attributes_indices.appendAssumeCapacity(@intCast(self.attributes_extra.items.len));
10967 }
10968 return @intCast(gop.index);
10969}
10970
10971fn bigIntConstAssumeCapacity(
10972 self: *Builder,
10973 ty: Type,
10974 value: std.math.big.int.Const,
10975) Allocator.Error!Constant {
10976 const type_item = self.type_items.items[@intFromEnum(ty)];
10977 assert(type_item.tag == .integer);
10978 const bits = type_item.data;
10979
10980 const ExpectedContents = [64 / @sizeOf(std.math.big.Limb)]std.math.big.Limb;
10981 var stack align(@alignOf(ExpectedContents)) =
10982 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
10983 const allocator = stack.get();
10984
10985 var limbs: []std.math.big.Limb = &.{};
10986 defer allocator.free(limbs);
10987 const canonical_value = if (value.fitsInTwosComp(.signed, bits)) value else canon: {
10988 assert(value.fitsInTwosComp(.unsigned, bits));
10989 limbs = try allocator.alloc(std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(bits));
10990 var temp_value = std.math.big.int.Mutable.init(limbs, 0);
10991 temp_value.truncate(value, .signed, bits);
10992 break :canon temp_value.toConst();
10993 };
10994 assert(canonical_value.fitsInTwosComp(.signed, bits));
10995
10996 const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer;
10997 const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb };
10998 const tag: Constant.Tag = switch (canonical_value.positive) {
10999 true => .positive_integer,
11000 false => .negative_integer,
11001 };
11002 const Adapter = struct {
11003 builder: *const Builder,
11004 pub fn hash(_: @This(), key: Key) u32 {
11005 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
11006 hasher.update(std.mem.asBytes(&key.type));
11007 hasher.update(std.mem.sliceAsBytes(key.limbs));
11008 return @truncate(hasher.final());
11009 }
11010 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11011 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11012 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11013 const rhs_extra: ExtraPtr =
11014 @ptrCast(ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs]);
11015 const rhs_limbs = ctx.builder.constant_limbs
11016 .items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len];
11017 return lhs_key.type == rhs_extra.type and
11018 std.mem.eql(std.math.big.Limb, lhs_key.limbs, rhs_limbs);
11019 }
11020 };
11021
11022 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
11023 Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs },
11024 Adapter{ .builder = self },
11025 );
11026 if (!gop.found_existing) {
11027 gop.key_ptr.* = {};
11028 gop.value_ptr.* = {};
11029 self.constant_items.appendAssumeCapacity(.{
11030 .tag = tag,
11031 .data = @intCast(self.constant_limbs.items.len),
11032 });
11033 const extra: ExtraPtr =
11034 @ptrCast(self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs));
11035 extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) };
11036 self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs);
11037 }
11038 return @enumFromInt(gop.index);
11039}
11040
11041fn halfConstAssumeCapacity(self: *Builder, val: f16) Constant {
11042 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11043 .{ .tag = .half, .data = @as(u16, @bitCast(val)) },
11044 );
11045 return result.constant;
11046}
11047
11048fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant {
11049 assert(@as(u16, @truncate(@as(u32, @bitCast(val)))) == 0);
11050 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11051 .{ .tag = .bfloat, .data = @bitCast(val) },
11052 );
11053 return result.constant;
11054}
11055
11056fn floatConstAssumeCapacity(self: *Builder, val: f32) Constant {
11057 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11058 .{ .tag = .float, .data = @bitCast(val) },
11059 );
11060 return result.constant;
11061}
11062
11063fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant {
11064 const Adapter = struct {
11065 builder: *const Builder,
11066 pub fn hash(_: @This(), key: f64) u32 {
11067 return @truncate(std.hash.Wyhash.hash(
11068 comptime std.hash.uint32(@intFromEnum(Constant.Tag.double)),
11069 std.mem.asBytes(&key),
11070 ));
11071 }
11072 pub fn eql(ctx: @This(), lhs_key: f64, _: void, rhs_index: usize) bool {
11073 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .double) return false;
11074 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11075 const rhs_extra = ctx.builder.constantExtraData(Constant.Double, rhs_data);
11076 return @as(u64, @bitCast(lhs_key)) == @as(u64, rhs_extra.hi) << 32 | rhs_extra.lo;
11077 }
11078 };
11079 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11080 if (!gop.found_existing) {
11081 gop.key_ptr.* = {};
11082 gop.value_ptr.* = {};
11083 self.constant_items.appendAssumeCapacity(.{
11084 .tag = .double,
11085 .data = self.addConstantExtraAssumeCapacity(Constant.Double{
11086 .lo = @truncate(@as(u64, @bitCast(val))),
11087 .hi = @intCast(@as(u64, @bitCast(val)) >> 32),
11088 }),
11089 });
11090 }
11091 return @enumFromInt(gop.index);
11092}
11093
11094fn fp128ConstAssumeCapacity(self: *Builder, val: f128) Constant {
11095 const Adapter = struct {
11096 builder: *const Builder,
11097 pub fn hash(_: @This(), key: f128) u32 {
11098 return @truncate(std.hash.Wyhash.hash(
11099 comptime std.hash.uint32(@intFromEnum(Constant.Tag.fp128)),
11100 std.mem.asBytes(&key),
11101 ));
11102 }
11103 pub fn eql(ctx: @This(), lhs_key: f128, _: void, rhs_index: usize) bool {
11104 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fp128) return false;
11105 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11106 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
11107 return @as(u128, @bitCast(lhs_key)) == @as(u128, rhs_extra.hi_hi) << 96 |
11108 @as(u128, rhs_extra.hi_lo) << 64 | @as(u128, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
11109 }
11110 };
11111 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11112 if (!gop.found_existing) {
11113 gop.key_ptr.* = {};
11114 gop.value_ptr.* = {};
11115 self.constant_items.appendAssumeCapacity(.{
11116 .tag = .fp128,
11117 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
11118 .lo_lo = @truncate(@as(u128, @bitCast(val))),
11119 .lo_hi = @truncate(@as(u128, @bitCast(val)) >> 32),
11120 .hi_lo = @truncate(@as(u128, @bitCast(val)) >> 64),
11121 .hi_hi = @intCast(@as(u128, @bitCast(val)) >> 96),
11122 }),
11123 });
11124 }
11125 return @enumFromInt(gop.index);
11126}
11127
11128fn x86_fp80ConstAssumeCapacity(self: *Builder, val: f80) Constant {
11129 const Adapter = struct {
11130 builder: *const Builder,
11131 pub fn hash(_: @This(), key: f80) u32 {
11132 return @truncate(std.hash.Wyhash.hash(
11133 comptime std.hash.uint32(@intFromEnum(Constant.Tag.x86_fp80)),
11134 std.mem.asBytes(&key)[0..10],
11135 ));
11136 }
11137 pub fn eql(ctx: @This(), lhs_key: f80, _: void, rhs_index: usize) bool {
11138 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .x86_fp80) return false;
11139 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11140 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp80, rhs_data);
11141 return @as(u80, @bitCast(lhs_key)) == @as(u80, rhs_extra.hi) << 64 |
11142 @as(u80, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
11143 }
11144 };
11145 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11146 if (!gop.found_existing) {
11147 gop.key_ptr.* = {};
11148 gop.value_ptr.* = {};
11149 self.constant_items.appendAssumeCapacity(.{
11150 .tag = .x86_fp80,
11151 .data = self.addConstantExtraAssumeCapacity(Constant.Fp80{
11152 .lo_lo = @truncate(@as(u80, @bitCast(val))),
11153 .lo_hi = @truncate(@as(u80, @bitCast(val)) >> 32),
11154 .hi = @intCast(@as(u80, @bitCast(val)) >> 64),
11155 }),
11156 });
11157 }
11158 return @enumFromInt(gop.index);
11159}
11160
11161fn ppc_fp128ConstAssumeCapacity(self: *Builder, val: [2]f64) Constant {
11162 const Adapter = struct {
11163 builder: *const Builder,
11164 pub fn hash(_: @This(), key: [2]f64) u32 {
11165 return @truncate(std.hash.Wyhash.hash(
11166 comptime std.hash.uint32(@intFromEnum(Constant.Tag.ppc_fp128)),
11167 std.mem.asBytes(&key),
11168 ));
11169 }
11170 pub fn eql(ctx: @This(), lhs_key: [2]f64, _: void, rhs_index: usize) bool {
11171 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .ppc_fp128) return false;
11172 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11173 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
11174 return @as(u64, @bitCast(lhs_key[0])) == @as(u64, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo and
11175 @as(u64, @bitCast(lhs_key[1])) == @as(u64, rhs_extra.hi_hi) << 32 | rhs_extra.hi_lo;
11176 }
11177 };
11178 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
11179 if (!gop.found_existing) {
11180 gop.key_ptr.* = {};
11181 gop.value_ptr.* = {};
11182 self.constant_items.appendAssumeCapacity(.{
11183 .tag = .ppc_fp128,
11184 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
11185 .lo_lo = @truncate(@as(u64, @bitCast(val[0]))),
11186 .lo_hi = @intCast(@as(u64, @bitCast(val[0])) >> 32),
11187 .hi_lo = @truncate(@as(u64, @bitCast(val[1]))),
11188 .hi_hi = @intCast(@as(u64, @bitCast(val[1])) >> 32),
11189 }),
11190 });
11191 }
11192 return @enumFromInt(gop.index);
11193}
11194
11195fn nullConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11196 assert(self.type_items.items[@intFromEnum(ty)].tag == .pointer);
11197 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11198 .{ .tag = .null, .data = @intFromEnum(ty) },
11199 );
11200 return result.constant;
11201}
11202
11203fn noneConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11204 assert(ty == .token);
11205 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11206 .{ .tag = .none, .data = @intFromEnum(ty) },
11207 );
11208 return result.constant;
11209}
11210
11211fn structConstAssumeCapacity(self: *Builder, ty: Type, vals: []const Constant) Constant {
11212 const type_item = self.type_items.items[@intFromEnum(ty)];
11213 var extra = self.typeExtraDataTrail(Type.Structure, switch (type_item.tag) {
11214 .structure, .packed_structure => type_item.data,
11215 .named_structure => data: {
11216 const body_ty = self.typeExtraData(Type.NamedStructure, type_item.data).body;
11217 const body_item = self.type_items.items[@intFromEnum(body_ty)];
11218 switch (body_item.tag) {
11219 .structure, .packed_structure => break :data body_item.data,
11220 else => unreachable,
11221 }
11222 },
11223 else => unreachable,
11224 });
11225 const fields = extra.trail.next(extra.data.fields_len, Type, self);
11226 for (fields, vals) |field, val| assert(field == val.typeOf(self));
11227
11228 for (vals) |val| {
11229 if (!val.isZeroInit(self)) break;
11230 } else return self.zeroInitConstAssumeCapacity(ty);
11231
11232 const tag: Constant.Tag = switch (ty.unnamedTag(self)) {
11233 .structure => .structure,
11234 .packed_structure => .packed_structure,
11235 else => unreachable,
11236 };
11237 const result = self.getOrPutConstantAggregateAssumeCapacity(tag, ty, vals);
11238 return result.constant;
11239}
11240
11241fn arrayConstAssumeCapacity(self: *Builder, ty: Type, vals: []const Constant) Constant {
11242 const type_item = self.type_items.items[@intFromEnum(ty)];
11243 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
11244 inline .small_array, .array => |kind| extra: {
11245 const extra = self.typeExtraData(switch (kind) {
11246 .small_array => Type.Vector,
11247 .array => Type.Array,
11248 else => unreachable,
11249 }, type_item.data);
11250 break :extra .{ .len = extra.length(), .child = extra.child };
11251 },
11252 else => unreachable,
11253 };
11254 assert(type_extra.len == vals.len);
11255 for (vals) |val| assert(type_extra.child == val.typeOf(self));
11256
11257 for (vals) |val| {
11258 if (!val.isZeroInit(self)) break;
11259 } else return self.zeroInitConstAssumeCapacity(ty);
11260
11261 const result = self.getOrPutConstantAggregateAssumeCapacity(.array, ty, vals);
11262 return result.constant;
11263}
11264
11265fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
11266 const slice = val.slice(self).?;
11267 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
11268 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
11269 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11270 .{ .tag = .string, .data = @intFromEnum(val) },
11271 );
11272 return result.constant;
11273}
11274
11275fn vectorConstAssumeCapacity(self: *Builder, ty: Type, vals: []const Constant) Constant {
11276 assert(ty.isVector(self));
11277 assert(ty.vectorLen(self) == vals.len);
11278 for (vals) |val| assert(ty.childType(self) == val.typeOf(self));
11279
11280 for (vals[1..]) |val| {
11281 if (vals[0] != val) break;
11282 } else return self.splatConstAssumeCapacity(ty, vals[0]);
11283 for (vals) |val| {
11284 if (!val.isZeroInit(self)) break;
11285 } else return self.zeroInitConstAssumeCapacity(ty);
11286
11287 const result = self.getOrPutConstantAggregateAssumeCapacity(.vector, ty, vals);
11288 return result.constant;
11289}
11290
11291fn splatConstAssumeCapacity(self: *Builder, ty: Type, val: Constant) Constant {
11292 assert(ty.scalarType(self) == val.typeOf(self));
11293
11294 if (!ty.isVector(self)) return val;
11295 if (val.isZeroInit(self)) return self.zeroInitConstAssumeCapacity(ty);
11296
11297 const Adapter = struct {
11298 builder: *const Builder,
11299 pub fn hash(_: @This(), key: Constant.Splat) u32 {
11300 return @truncate(std.hash.Wyhash.hash(
11301 comptime std.hash.uint32(@intFromEnum(Constant.Tag.splat)),
11302 std.mem.asBytes(&key),
11303 ));
11304 }
11305 pub fn eql(ctx: @This(), lhs_key: Constant.Splat, _: void, rhs_index: usize) bool {
11306 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .splat) return false;
11307 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11308 const rhs_extra = ctx.builder.constantExtraData(Constant.Splat, rhs_data);
11309 return std.meta.eql(lhs_key, rhs_extra);
11310 }
11311 };
11312 const data = Constant.Splat{ .type = ty, .value = val };
11313 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11314 if (!gop.found_existing) {
11315 gop.key_ptr.* = {};
11316 gop.value_ptr.* = {};
11317 self.constant_items.appendAssumeCapacity(.{
11318 .tag = .splat,
11319 .data = self.addConstantExtraAssumeCapacity(data),
11320 });
11321 }
11322 return @enumFromInt(gop.index);
11323}
11324
11325fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11326 switch (ty) {
11327 inline .half,
11328 .bfloat,
11329 .float,
11330 .double,
11331 .fp128,
11332 .x86_fp80,
11333 => |tag| return @field(Builder, @tagName(tag) ++ "ConstAssumeCapacity")(self, 0.0),
11334 .ppc_fp128 => return self.ppc_fp128ConstAssumeCapacity(.{ 0.0, 0.0 }),
11335 .token => return .none,
11336 .i1 => return .false,
11337 else => switch (self.type_items.items[@intFromEnum(ty)].tag) {
11338 .simple,
11339 .function,
11340 .vararg_function,
11341 => unreachable,
11342 .integer => {
11343 var limbs: [std.math.big.int.calcLimbLen(0)]std.math.big.Limb = undefined;
11344 const bigint = std.math.big.int.Mutable.init(&limbs, 0);
11345 return self.bigIntConstAssumeCapacity(ty, bigint.toConst()) catch unreachable;
11346 },
11347 .pointer => return self.nullConstAssumeCapacity(ty),
11348 .target,
11349 .vector,
11350 .scalable_vector,
11351 .small_array,
11352 .array,
11353 .structure,
11354 .packed_structure,
11355 .named_structure,
11356 => {},
11357 },
11358 }
11359 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11360 .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) },
11361 );
11362 return result.constant;
11363}
11364
11365fn undefConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11366 switch (self.type_items.items[@intFromEnum(ty)].tag) {
11367 .simple => switch (ty) {
11368 .void, .label => unreachable,
11369 else => {},
11370 },
11371 .function, .vararg_function => unreachable,
11372 else => {},
11373 }
11374 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11375 .{ .tag = .undef, .data = @intFromEnum(ty) },
11376 );
11377 return result.constant;
11378}
11379
11380fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {
11381 switch (self.type_items.items[@intFromEnum(ty)].tag) {
11382 .simple => switch (ty) {
11383 .void, .label => unreachable,
11384 else => {},
11385 },
11386 .function, .vararg_function => unreachable,
11387 else => {},
11388 }
11389 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11390 .{ .tag = .poison, .data = @intFromEnum(ty) },
11391 );
11392 return result.constant;
11393}
11394
11395fn blockAddrConstAssumeCapacity(
11396 self: *Builder,
11397 function: Function.Index,
11398 block: Function.Block.Index,
11399) Constant {
11400 const Adapter = struct {
11401 builder: *const Builder,
11402 pub fn hash(_: @This(), key: Constant.BlockAddress) u32 {
11403 return @truncate(std.hash.Wyhash.hash(
11404 comptime std.hash.uint32(@intFromEnum(Constant.Tag.blockaddress)),
11405 std.mem.asBytes(&key),
11406 ));
11407 }
11408 pub fn eql(ctx: @This(), lhs_key: Constant.BlockAddress, _: void, rhs_index: usize) bool {
11409 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .blockaddress) return false;
11410 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11411 const rhs_extra = ctx.builder.constantExtraData(Constant.BlockAddress, rhs_data);
11412 return std.meta.eql(lhs_key, rhs_extra);
11413 }
11414 };
11415 const data = Constant.BlockAddress{ .function = function, .block = block };
11416 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11417 if (!gop.found_existing) {
11418 gop.key_ptr.* = {};
11419 gop.value_ptr.* = {};
11420 self.constant_items.appendAssumeCapacity(.{
11421 .tag = .blockaddress,
11422 .data = self.addConstantExtraAssumeCapacity(data),
11423 });
11424 }
11425 return @enumFromInt(gop.index);
11426}
11427
11428fn dsoLocalEquivalentConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
11429 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11430 .{ .tag = .dso_local_equivalent, .data = @intFromEnum(function) },
11431 );
11432 return result.constant;
11433}
11434
11435fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
11436 const result = self.getOrPutConstantNoExtraAssumeCapacity(
11437 .{ .tag = .no_cfi, .data = @intFromEnum(function) },
11438 );
11439 return result.constant;
11440}
11441
11442fn convTag(
11443 self: *Builder,
11444 signedness: Constant.Cast.Signedness,
11445 val_ty: Type,
11446 ty: Type,
11447) Function.Instruction.Tag {
11448 assert(val_ty != ty);
11449 return switch (val_ty.scalarTag(self)) {
11450 .simple => switch (ty.scalarTag(self)) {
11451 .simple => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
11452 .lt => .fpext,
11453 .eq => unreachable,
11454 .gt => .fptrunc,
11455 },
11456 .integer => switch (signedness) {
11457 .unsigned => .fptoui,
11458 .signed => .fptosi,
11459 .unneeded => unreachable,
11460 },
11461 else => unreachable,
11462 },
11463 .integer => switch (ty.scalarTag(self)) {
11464 .simple => switch (signedness) {
11465 .unsigned => .uitofp,
11466 .signed => .sitofp,
11467 .unneeded => unreachable,
11468 },
11469 .integer => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
11470 .lt => switch (signedness) {
11471 .unsigned => .zext,
11472 .signed => .sext,
11473 .unneeded => unreachable,
11474 },
11475 .eq => unreachable,
11476 .gt => .trunc,
11477 },
11478 .pointer => .inttoptr,
11479 else => unreachable,
11480 },
11481 .pointer => switch (ty.scalarTag(self)) {
11482 .integer => .ptrtoint,
11483 .pointer => .addrspacecast,
11484 else => unreachable,
11485 },
11486 else => unreachable,
11487 };
11488}
11489
11490fn convConstTag(
11491 self: *Builder,
11492 val_ty: Type,
11493 ty: Type,
11494) Constant.Tag {
11495 assert(val_ty != ty);
11496 return switch (val_ty.scalarTag(self)) {
11497 .integer => switch (ty.scalarTag(self)) {
11498 .integer => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
11499 .gt => .trunc,
11500 else => unreachable,
11501 },
11502 .pointer => .inttoptr,
11503 else => unreachable,
11504 },
11505 .pointer => switch (ty.scalarTag(self)) {
11506 .integer => .ptrtoint,
11507 .pointer => .addrspacecast,
11508 else => unreachable,
11509 },
11510 else => unreachable,
11511 };
11512}
11513
11514fn convConstAssumeCapacity(
11515 self: *Builder,
11516 val: Constant,
11517 ty: Type,
11518) Constant {
11519 const val_ty = val.typeOf(self);
11520 if (val_ty == ty) return val;
11521 return self.castConstAssumeCapacity(self.convConstTag(val_ty, ty), val, ty);
11522}
11523
11524fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Constant {
11525 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };
11526 const Adapter = struct {
11527 builder: *const Builder,
11528 pub fn hash(_: @This(), key: Key) u32 {
11529 return @truncate(std.hash.Wyhash.hash(
11530 std.hash.uint32(@intFromEnum(key.tag)),
11531 std.mem.asBytes(&key.cast),
11532 ));
11533 }
11534 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11535 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11536 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11537 const rhs_extra = ctx.builder.constantExtraData(Constant.Cast, rhs_data);
11538 return std.meta.eql(lhs_key.cast, rhs_extra);
11539 }
11540 };
11541 const data = Key{ .tag = tag, .cast = .{ .val = val, .type = ty } };
11542 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11543 if (!gop.found_existing) {
11544 gop.key_ptr.* = {};
11545 gop.value_ptr.* = {};
11546 self.constant_items.appendAssumeCapacity(.{
11547 .tag = tag,
11548 .data = self.addConstantExtraAssumeCapacity(data.cast),
11549 });
11550 }
11551 return @enumFromInt(gop.index);
11552}
11553
11554fn gepConstAssumeCapacity(
11555 self: *Builder,
11556 comptime kind: Constant.GetElementPtr.Kind,
11557 ty: Type,
11558 base: Constant,
11559 inrange: ?u16,
11560 indices: []const Constant,
11561) Constant {
11562 const tag: Constant.Tag = switch (kind) {
11563 .normal => .getelementptr,
11564 .inbounds => .@"getelementptr inbounds",
11565 };
11566 const base_ty = base.typeOf(self);
11567 const base_is_vector = base_ty.isVector(self);
11568
11569 const VectorInfo = struct {
11570 kind: Type.Vector.Kind,
11571 len: u32,
11572
11573 fn init(vector_ty: Type, builder: *const Builder) @This() {
11574 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
11575 }
11576 };
11577 var vector_info: ?VectorInfo = if (base_is_vector) VectorInfo.init(base_ty, self) else null;
11578 for (indices) |index| {
11579 const index_ty = index.typeOf(self);
11580 switch (index_ty.tag(self)) {
11581 .integer => {},
11582 .vector, .scalable_vector => {
11583 const index_info = VectorInfo.init(index_ty, self);
11584 if (vector_info) |info|
11585 assert(std.meta.eql(info, index_info))
11586 else
11587 vector_info = index_info;
11588 },
11589 else => unreachable,
11590 }
11591 }
11592 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
11593 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
11594 };
11595
11596 const Key = struct {
11597 type: Type,
11598 base: Constant,
11599 inrange: Constant.GetElementPtr.InRangeIndex,
11600 indices: []const Constant,
11601 };
11602 const Adapter = struct {
11603 builder: *const Builder,
11604 pub fn hash(_: @This(), key: Key) u32 {
11605 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
11606 hasher.update(std.mem.asBytes(&key.type));
11607 hasher.update(std.mem.asBytes(&key.base));
11608 hasher.update(std.mem.asBytes(&key.inrange));
11609 hasher.update(std.mem.sliceAsBytes(key.indices));
11610 return @truncate(hasher.final());
11611 }
11612 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11613 if (ctx.builder.constant_items.items(.tag)[rhs_index] != tag) return false;
11614 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11615 var rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
11616 const rhs_indices =
11617 rhs_extra.trail.next(rhs_extra.data.info.indices_len, Constant, ctx.builder);
11618 return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and
11619 lhs_key.inrange == rhs_extra.data.info.inrange and
11620 std.mem.eql(Constant, lhs_key.indices, rhs_indices);
11621 }
11622 };
11623 const data = Key{
11624 .type = ty,
11625 .base = base,
11626 .inrange = if (inrange) |index| @enumFromInt(index) else .none,
11627 .indices = indices,
11628 };
11629 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11630 if (!gop.found_existing) {
11631 gop.key_ptr.* = {};
11632 gop.value_ptr.* = {};
11633 self.constant_items.appendAssumeCapacity(.{
11634 .tag = tag,
11635 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
11636 .type = ty,
11637 .base = base,
11638 .info = .{ .indices_len = @intCast(indices.len), .inrange = data.inrange },
11639 }),
11640 });
11641 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
11642 }
11643 return @enumFromInt(gop.index);
11644}
11645
11646fn binConstAssumeCapacity(
11647 self: *Builder,
11648 tag: Constant.Tag,
11649 lhs: Constant,
11650 rhs: Constant,
11651) Constant {
11652 switch (tag) {
11653 .add,
11654 .@"add nsw",
11655 .@"add nuw",
11656 .sub,
11657 .@"sub nsw",
11658 .@"sub nuw",
11659 .shl,
11660 .xor,
11661 => {},
11662 else => unreachable,
11663 }
11664 const Key = struct { tag: Constant.Tag, extra: Constant.Binary };
11665 const Adapter = struct {
11666 builder: *const Builder,
11667 pub fn hash(_: @This(), key: Key) u32 {
11668 return @truncate(std.hash.Wyhash.hash(
11669 std.hash.uint32(@intFromEnum(key.tag)),
11670 std.mem.asBytes(&key.extra),
11671 ));
11672 }
11673 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11674 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11675 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11676 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
11677 return std.meta.eql(lhs_key.extra, rhs_extra);
11678 }
11679 };
11680 const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } };
11681 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11682 if (!gop.found_existing) {
11683 gop.key_ptr.* = {};
11684 gop.value_ptr.* = {};
11685 self.constant_items.appendAssumeCapacity(.{
11686 .tag = tag,
11687 .data = self.addConstantExtraAssumeCapacity(data.extra),
11688 });
11689 }
11690 return @enumFromInt(gop.index);
11691}
11692
11693fn asmConstAssumeCapacity(
11694 self: *Builder,
11695 ty: Type,
11696 info: Constant.Assembly.Info,
11697 assembly: String,
11698 constraints: String,
11699) Constant {
11700 assert(ty.functionKind(self) == .normal);
11701
11702 const Key = struct { tag: Constant.Tag, extra: Constant.Assembly };
11703 const Adapter = struct {
11704 builder: *const Builder,
11705 pub fn hash(_: @This(), key: Key) u32 {
11706 return @truncate(std.hash.Wyhash.hash(
11707 std.hash.uint32(@intFromEnum(key.tag)),
11708 std.mem.asBytes(&key.extra),
11709 ));
11710 }
11711 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11712 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11713 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11714 const rhs_extra = ctx.builder.constantExtraData(Constant.Assembly, rhs_data);
11715 return std.meta.eql(lhs_key.extra, rhs_extra);
11716 }
11717 };
11718
11719 const data = Key{
11720 .tag = @enumFromInt(@intFromEnum(Constant.Tag.@"asm") + @as(u4, @bitCast(info))),
11721 .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints },
11722 };
11723 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11724 if (!gop.found_existing) {
11725 gop.key_ptr.* = {};
11726 gop.value_ptr.* = {};
11727 self.constant_items.appendAssumeCapacity(.{
11728 .tag = data.tag,
11729 .data = self.addConstantExtraAssumeCapacity(data.extra),
11730 });
11731 }
11732 return @enumFromInt(gop.index);
11733}
11734
11735fn ensureUnusedConstantCapacity(
11736 self: *Builder,
11737 count: usize,
11738 comptime Extra: type,
11739 trail_len: usize,
11740) Allocator.Error!void {
11741 try self.constant_map.ensureUnusedCapacity(self.gpa, count);
11742 try self.constant_items.ensureUnusedCapacity(self.gpa, count);
11743 try self.constant_extra.ensureUnusedCapacity(
11744 self.gpa,
11745 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
11746 );
11747}
11748
11749fn getOrPutConstantNoExtraAssumeCapacity(
11750 self: *Builder,
11751 item: Constant.Item,
11752) struct { new: bool, constant: Constant } {
11753 const Adapter = struct {
11754 builder: *const Builder,
11755 pub fn hash(_: @This(), key: Constant.Item) u32 {
11756 return @truncate(std.hash.Wyhash.hash(
11757 std.hash.uint32(@intFromEnum(key.tag)),
11758 std.mem.asBytes(&key.data),
11759 ));
11760 }
11761 pub fn eql(ctx: @This(), lhs_key: Constant.Item, _: void, rhs_index: usize) bool {
11762 return std.meta.eql(lhs_key, ctx.builder.constant_items.get(rhs_index));
11763 }
11764 };
11765 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
11766 if (!gop.found_existing) {
11767 gop.key_ptr.* = {};
11768 gop.value_ptr.* = {};
11769 self.constant_items.appendAssumeCapacity(item);
11770 }
11771 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
11772}
11773
11774fn getOrPutConstantAggregateAssumeCapacity(
11775 self: *Builder,
11776 tag: Constant.Tag,
11777 ty: Type,
11778 vals: []const Constant,
11779) struct { new: bool, constant: Constant } {
11780 switch (tag) {
11781 .structure, .packed_structure, .array, .vector => {},
11782 else => unreachable,
11783 }
11784 const Key = struct { tag: Constant.Tag, type: Type, vals: []const Constant };
11785 const Adapter = struct {
11786 builder: *const Builder,
11787 pub fn hash(_: @This(), key: Key) u32 {
11788 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
11789 hasher.update(std.mem.asBytes(&key.type));
11790 hasher.update(std.mem.sliceAsBytes(key.vals));
11791 return @truncate(hasher.final());
11792 }
11793 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
11794 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
11795 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11796 var rhs_extra = ctx.builder.constantExtraDataTrail(Constant.Aggregate, rhs_data);
11797 if (lhs_key.type != rhs_extra.data.type) return false;
11798 const rhs_vals = rhs_extra.trail.next(@intCast(lhs_key.vals.len), Constant, ctx.builder);
11799 return std.mem.eql(Constant, lhs_key.vals, rhs_vals);
11800 }
11801 };
11802 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
11803 Key{ .tag = tag, .type = ty, .vals = vals },
11804 Adapter{ .builder = self },
11805 );
11806 if (!gop.found_existing) {
11807 gop.key_ptr.* = {};
11808 gop.value_ptr.* = {};
11809 self.constant_items.appendAssumeCapacity(.{
11810 .tag = tag,
11811 .data = self.addConstantExtraAssumeCapacity(Constant.Aggregate{ .type = ty }),
11812 });
11813 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(vals));
11814 }
11815 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
11816}
11817
11818fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.ExtraIndex {
11819 const result: Constant.Item.ExtraIndex = @intCast(self.constant_extra.items.len);
11820 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
11821 const value = @field(extra, field.name);
11822 self.constant_extra.appendAssumeCapacity(switch (field.type) {
11823 u32 => value,
11824 String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
11825 Constant.GetElementPtr.Info => @bitCast(value),
11826 else => @compileError("bad field type: " ++ @typeName(field.type)),
11827 });
11828 }
11829 return result;
11830}
11831
11832const ConstantExtraDataTrail = struct {
11833 index: Constant.Item.ExtraIndex,
11834
11835 fn nextMut(self: *ConstantExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
11836 const items: []Item = @ptrCast(builder.constant_extra.items[self.index..][0..len]);
11837 self.index += @intCast(len);
11838 return items;
11839 }
11840
11841 fn next(
11842 self: *ConstantExtraDataTrail,
11843 len: u32,
11844 comptime Item: type,
11845 builder: *const Builder,
11846 ) []const Item {
11847 const items: []const Item = @ptrCast(builder.constant_extra.items[self.index..][0..len]);
11848 self.index += @intCast(len);
11849 return items;
11850 }
11851};
11852
11853fn constantExtraDataTrail(
11854 self: *const Builder,
11855 comptime T: type,
11856 index: Constant.Item.ExtraIndex,
11857) struct { data: T, trail: ConstantExtraDataTrail } {
11858 var result: T = undefined;
11859 const fields = @typeInfo(T).@"struct".fields;
11860 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
11861 @field(result, field.name) = switch (field.type) {
11862 u32 => value,
11863 String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
11864 Constant.GetElementPtr.Info => @bitCast(value),
11865 else => @compileError("bad field type: " ++ @typeName(field.type)),
11866 };
11867 return .{
11868 .data = result,
11869 .trail = .{ .index = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) },
11870 };
11871}
11872
11873fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Item.ExtraIndex) T {
11874 return self.constantExtraDataTrail(T, index).data;
11875}
11876
11877fn ensureUnusedMetadataCapacity(
11878 self: *Builder,
11879 count: usize,
11880 comptime Extra: type,
11881 trail_len: usize,
11882) Allocator.Error!void {
11883 try self.metadata_map.ensureUnusedCapacity(self.gpa, count);
11884 try self.metadata_items.ensureUnusedCapacity(self.gpa, count);
11885 try self.metadata_extra.ensureUnusedCapacity(
11886 self.gpa,
11887 count * (@typeInfo(Extra).@"struct".fields.len + trail_len),
11888 );
11889}
11890
11891fn addMetadataExtraAssumeCapacity(self: *Builder, extra: anytype) Metadata.Item.ExtraIndex {
11892 const result: Metadata.Item.ExtraIndex = @intCast(self.metadata_extra.items.len);
11893 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| {
11894 const value = @field(extra, field.name);
11895 self.metadata_extra.appendAssumeCapacity(switch (field.type) {
11896 u32 => value,
11897 MetadataString, Metadata, Variable.Index, Value => @intFromEnum(value),
11898 Metadata.DIFlags => @bitCast(value),
11899 else => @compileError("bad field type: " ++ @typeName(field.type)),
11900 });
11901 }
11902 return result;
11903}
11904
11905const MetadataExtraDataTrail = struct {
11906 index: Metadata.Item.ExtraIndex,
11907
11908 fn nextMut(self: *MetadataExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
11909 const items: []Item = @ptrCast(builder.metadata_extra.items[self.index..][0..len]);
11910 self.index += @intCast(len);
11911 return items;
11912 }
11913
11914 fn next(
11915 self: *MetadataExtraDataTrail,
11916 len: u32,
11917 comptime Item: type,
11918 builder: *const Builder,
11919 ) []const Item {
11920 const items: []const Item = @ptrCast(builder.metadata_extra.items[self.index..][0..len]);
11921 self.index += @intCast(len);
11922 return items;
11923 }
11924};
11925
11926fn metadataExtraDataTrail(
11927 self: *const Builder,
11928 comptime T: type,
11929 index: Metadata.Item.ExtraIndex,
11930) struct { data: T, trail: MetadataExtraDataTrail } {
11931 var result: T = undefined;
11932 const fields = @typeInfo(T).@"struct".fields;
11933 inline for (fields, self.metadata_extra.items[index..][0..fields.len]) |field, value|
11934 @field(result, field.name) = switch (field.type) {
11935 u32 => value,
11936 MetadataString, Metadata, Variable.Index, Value => @enumFromInt(value),
11937 Metadata.DIFlags => @bitCast(value),
11938 else => @compileError("bad field type: " ++ @typeName(field.type)),
11939 };
11940 return .{
11941 .data = result,
11942 .trail = .{ .index = index + @as(Metadata.Item.ExtraIndex, @intCast(fields.len)) },
11943 };
11944}
11945
11946fn metadataExtraData(self: *const Builder, comptime T: type, index: Metadata.Item.ExtraIndex) T {
11947 return self.metadataExtraDataTrail(T, index).data;
11948}
11949
11950pub fn metadataString(self: *Builder, bytes: []const u8) Allocator.Error!MetadataString {
11951 try self.metadata_string_bytes.ensureUnusedCapacity(self.gpa, bytes.len);
11952 try self.metadata_string_indices.ensureUnusedCapacity(self.gpa, 1);
11953 try self.metadata_string_map.ensureUnusedCapacity(self.gpa, 1);
11954
11955 const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(
11956 bytes,
11957 MetadataString.Adapter{ .builder = self },
11958 );
11959 if (!gop.found_existing) {
11960 self.metadata_string_bytes.appendSliceAssumeCapacity(bytes);
11961 self.metadata_string_indices.appendAssumeCapacity(@intCast(self.metadata_string_bytes.items.len));
11962 }
11963 return @enumFromInt(gop.index);
11964}
11965
11966pub fn metadataStringFromStrtabString(self: *Builder, str: StrtabString) Allocator.Error!MetadataString {
11967 if (str == .none or str == .empty) return MetadataString.none;
11968 return try self.metadataString(str.slice(self).?);
11969}
11970
11971pub fn metadataStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allocator.Error!MetadataString {
11972 try self.metadata_string_map.ensureUnusedCapacity(self.gpa, 1);
11973 try self.metadata_string_bytes.ensureUnusedCapacity(self.gpa, @intCast(std.fmt.count(fmt_str, fmt_args)));
11974 try self.metadata_string_indices.ensureUnusedCapacity(self.gpa, 1);
11975 return self.metadataStringFmtAssumeCapacity(fmt_str, fmt_args);
11976}
11977
11978pub fn metadataStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) MetadataString {
11979 self.metadata_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
11980 return self.trailingMetadataStringAssumeCapacity();
11981}
11982
11983pub fn trailingMetadataString(self: *Builder) Allocator.Error!MetadataString {
11984 try self.metadata_string_indices.ensureUnusedCapacity(self.gpa, 1);
11985 try self.metadata_string_map.ensureUnusedCapacity(self.gpa, 1);
11986 return self.trailingMetadataStringAssumeCapacity();
11987}
11988
11989pub fn trailingMetadataStringAssumeCapacity(self: *Builder) MetadataString {
11990 const start = self.metadata_string_indices.getLast();
11991 const bytes: []const u8 = self.metadata_string_bytes.items[start..];
11992 const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
11993 if (gop.found_existing) {
11994 self.metadata_string_bytes.shrinkRetainingCapacity(start);
11995 } else {
11996 self.metadata_string_indices.appendAssumeCapacity(@intCast(self.metadata_string_bytes.items.len));
11997 }
11998 return @enumFromInt(gop.index);
11999}
12000
12001pub fn metadataNamed(self: *Builder, name: MetadataString, operands: []const Metadata) Allocator.Error!void {
12002 try self.metadata_extra.ensureUnusedCapacity(self.gpa, operands.len);
12003 try self.metadata_named.ensureUnusedCapacity(self.gpa, 1);
12004 self.metadataNamedAssumeCapacity(name, operands);
12005}
12006
12007fn metadataNone(self: *Builder) Allocator.Error!Metadata {
12008 try self.ensureUnusedMetadataCapacity(1, NoExtra, 0);
12009 return self.metadataNoneAssumeCapacity();
12010}
12011
12012pub fn debugFile(
12013 self: *Builder,
12014 filename: MetadataString,
12015 directory: MetadataString,
12016) Allocator.Error!Metadata {
12017 try self.ensureUnusedMetadataCapacity(1, Metadata.File, 0);
12018 return self.debugFileAssumeCapacity(filename, directory);
12019}
12020
12021pub fn debugCompileUnit(
12022 self: *Builder,
12023 file: Metadata,
12024 producer: MetadataString,
12025 enums: Metadata,
12026 globals: Metadata,
12027 options: Metadata.CompileUnit.Options,
12028) Allocator.Error!Metadata {
12029 try self.ensureUnusedMetadataCapacity(1, Metadata.CompileUnit, 0);
12030 return self.debugCompileUnitAssumeCapacity(file, producer, enums, globals, options);
12031}
12032
12033pub fn debugSubprogram(
12034 self: *Builder,
12035 file: Metadata,
12036 name: MetadataString,
12037 linkage_name: MetadataString,
12038 line: u32,
12039 scope_line: u32,
12040 ty: Metadata,
12041 options: Metadata.Subprogram.Options,
12042 compile_unit: Metadata,
12043) Allocator.Error!Metadata {
12044 try self.ensureUnusedMetadataCapacity(1, Metadata.Subprogram, 0);
12045 return self.debugSubprogramAssumeCapacity(
12046 file,
12047 name,
12048 linkage_name,
12049 line,
12050 scope_line,
12051 ty,
12052 options,
12053 compile_unit,
12054 );
12055}
12056
12057pub fn debugLexicalBlock(self: *Builder, scope: Metadata, file: Metadata, line: u32, column: u32) Allocator.Error!Metadata {
12058 try self.ensureUnusedMetadataCapacity(1, Metadata.LexicalBlock, 0);
12059 return self.debugLexicalBlockAssumeCapacity(scope, file, line, column);
12060}
12061
12062pub fn debugLocation(self: *Builder, line: u32, column: u32, scope: Metadata, inlined_at: Metadata) Allocator.Error!Metadata {
12063 try self.ensureUnusedMetadataCapacity(1, Metadata.Location, 0);
12064 return self.debugLocationAssumeCapacity(line, column, scope, inlined_at);
12065}
12066
12067pub fn debugBoolType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12068 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12069 return self.debugBoolTypeAssumeCapacity(name, size_in_bits);
12070}
12071
12072pub fn debugUnsignedType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12073 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12074 return self.debugUnsignedTypeAssumeCapacity(name, size_in_bits);
12075}
12076
12077pub fn debugSignedType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12078 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12079 return self.debugSignedTypeAssumeCapacity(name, size_in_bits);
12080}
12081
12082pub fn debugFloatType(self: *Builder, name: MetadataString, size_in_bits: u64) Allocator.Error!Metadata {
12083 try self.ensureUnusedMetadataCapacity(1, Metadata.BasicType, 0);
12084 return self.debugFloatTypeAssumeCapacity(name, size_in_bits);
12085}
12086
12087pub fn debugForwardReference(self: *Builder) Allocator.Error!Metadata {
12088 try self.metadata_forward_references.ensureUnusedCapacity(self.gpa, 1);
12089 return self.debugForwardReferenceAssumeCapacity();
12090}
12091
12092pub fn debugStructType(
12093 self: *Builder,
12094 name: MetadataString,
12095 file: Metadata,
12096 scope: Metadata,
12097 line: u32,
12098 underlying_type: Metadata,
12099 size_in_bits: u64,
12100 align_in_bits: u64,
12101 fields_tuple: Metadata,
12102) Allocator.Error!Metadata {
12103 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12104 return self.debugStructTypeAssumeCapacity(
12105 name,
12106 file,
12107 scope,
12108 line,
12109 underlying_type,
12110 size_in_bits,
12111 align_in_bits,
12112 fields_tuple,
12113 );
12114}
12115
12116pub fn debugUnionType(
12117 self: *Builder,
12118 name: MetadataString,
12119 file: Metadata,
12120 scope: Metadata,
12121 line: u32,
12122 underlying_type: Metadata,
12123 size_in_bits: u64,
12124 align_in_bits: u64,
12125 fields_tuple: Metadata,
12126) Allocator.Error!Metadata {
12127 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12128 return self.debugUnionTypeAssumeCapacity(
12129 name,
12130 file,
12131 scope,
12132 line,
12133 underlying_type,
12134 size_in_bits,
12135 align_in_bits,
12136 fields_tuple,
12137 );
12138}
12139
12140pub fn debugEnumerationType(
12141 self: *Builder,
12142 name: MetadataString,
12143 file: Metadata,
12144 scope: Metadata,
12145 line: u32,
12146 underlying_type: Metadata,
12147 size_in_bits: u64,
12148 align_in_bits: u64,
12149 fields_tuple: Metadata,
12150) Allocator.Error!Metadata {
12151 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12152 return self.debugEnumerationTypeAssumeCapacity(
12153 name,
12154 file,
12155 scope,
12156 line,
12157 underlying_type,
12158 size_in_bits,
12159 align_in_bits,
12160 fields_tuple,
12161 );
12162}
12163
12164pub fn debugArrayType(
12165 self: *Builder,
12166 name: MetadataString,
12167 file: Metadata,
12168 scope: Metadata,
12169 line: u32,
12170 underlying_type: Metadata,
12171 size_in_bits: u64,
12172 align_in_bits: u64,
12173 fields_tuple: Metadata,
12174) Allocator.Error!Metadata {
12175 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12176 return self.debugArrayTypeAssumeCapacity(
12177 name,
12178 file,
12179 scope,
12180 line,
12181 underlying_type,
12182 size_in_bits,
12183 align_in_bits,
12184 fields_tuple,
12185 );
12186}
12187
12188pub fn debugVectorType(
12189 self: *Builder,
12190 name: MetadataString,
12191 file: Metadata,
12192 scope: Metadata,
12193 line: u32,
12194 underlying_type: Metadata,
12195 size_in_bits: u64,
12196 align_in_bits: u64,
12197 fields_tuple: Metadata,
12198) Allocator.Error!Metadata {
12199 try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0);
12200 return self.debugVectorTypeAssumeCapacity(
12201 name,
12202 file,
12203 scope,
12204 line,
12205 underlying_type,
12206 size_in_bits,
12207 align_in_bits,
12208 fields_tuple,
12209 );
12210}
12211
12212pub fn debugPointerType(
12213 self: *Builder,
12214 name: MetadataString,
12215 file: Metadata,
12216 scope: Metadata,
12217 line: u32,
12218 underlying_type: Metadata,
12219 size_in_bits: u64,
12220 align_in_bits: u64,
12221 offset_in_bits: u64,
12222) Allocator.Error!Metadata {
12223 try self.ensureUnusedMetadataCapacity(1, Metadata.DerivedType, 0);
12224 return self.debugPointerTypeAssumeCapacity(
12225 name,
12226 file,
12227 scope,
12228 line,
12229 underlying_type,
12230 size_in_bits,
12231 align_in_bits,
12232 offset_in_bits,
12233 );
12234}
12235
12236pub fn debugMemberType(
12237 self: *Builder,
12238 name: MetadataString,
12239 file: Metadata,
12240 scope: Metadata,
12241 line: u32,
12242 underlying_type: Metadata,
12243 size_in_bits: u64,
12244 align_in_bits: u64,
12245 offset_in_bits: u64,
12246) Allocator.Error!Metadata {
12247 try self.ensureUnusedMetadataCapacity(1, Metadata.DerivedType, 0);
12248 return self.debugMemberTypeAssumeCapacity(
12249 name,
12250 file,
12251 scope,
12252 line,
12253 underlying_type,
12254 size_in_bits,
12255 align_in_bits,
12256 offset_in_bits,
12257 );
12258}
12259
12260pub fn debugSubroutineType(
12261 self: *Builder,
12262 types_tuple: Metadata,
12263) Allocator.Error!Metadata {
12264 try self.ensureUnusedMetadataCapacity(1, Metadata.SubroutineType, 0);
12265 return self.debugSubroutineTypeAssumeCapacity(types_tuple);
12266}
12267
12268pub fn debugEnumerator(
12269 self: *Builder,
12270 name: MetadataString,
12271 unsigned: bool,
12272 bit_width: u32,
12273 value: std.math.big.int.Const,
12274) Allocator.Error!Metadata {
12275 assert(!(unsigned and !value.positive));
12276 try self.ensureUnusedMetadataCapacity(1, Metadata.Enumerator, 0);
12277 try self.metadata_limbs.ensureUnusedCapacity(self.gpa, value.limbs.len);
12278 return self.debugEnumeratorAssumeCapacity(name, unsigned, bit_width, value);
12279}
12280
12281pub fn debugSubrange(
12282 self: *Builder,
12283 lower_bound: Metadata,
12284 count: Metadata,
12285) Allocator.Error!Metadata {
12286 try self.ensureUnusedMetadataCapacity(1, Metadata.Subrange, 0);
12287 return self.debugSubrangeAssumeCapacity(lower_bound, count);
12288}
12289
12290pub fn debugExpression(
12291 self: *Builder,
12292 elements: []const u32,
12293) Allocator.Error!Metadata {
12294 try self.ensureUnusedMetadataCapacity(1, Metadata.Expression, elements.len);
12295 return self.debugExpressionAssumeCapacity(elements);
12296}
12297
12298pub fn metadataTuple(
12299 self: *Builder,
12300 elements: []const Metadata,
12301) Allocator.Error!Metadata {
12302 try self.ensureUnusedMetadataCapacity(1, Metadata.Tuple, elements.len);
12303 return self.metadataTupleAssumeCapacity(elements);
12304}
12305
12306pub fn strTuple(
12307 self: *Builder,
12308 str: MetadataString,
12309 elements: []const Metadata,
12310) Allocator.Error!Metadata {
12311 try self.ensureUnusedMetadataCapacity(1, Metadata.StrTuple, elements.len);
12312 return self.strTupleAssumeCapacity(str, elements);
12313}
12314
12315pub fn metadataModuleFlag(
12316 self: *Builder,
12317 behavior: Metadata,
12318 name: MetadataString,
12319 constant: Metadata,
12320) Allocator.Error!Metadata {
12321 try self.ensureUnusedMetadataCapacity(1, Metadata.ModuleFlag, 0);
12322 return self.metadataModuleFlagAssumeCapacity(behavior, name, constant);
12323}
12324
12325pub fn debugLocalVar(
12326 self: *Builder,
12327 name: MetadataString,
12328 file: Metadata,
12329 scope: Metadata,
12330 line: u32,
12331 ty: Metadata,
12332) Allocator.Error!Metadata {
12333 try self.ensureUnusedMetadataCapacity(1, Metadata.LocalVar, 0);
12334 return self.debugLocalVarAssumeCapacity(name, file, scope, line, ty);
12335}
12336
12337pub fn debugParameter(
12338 self: *Builder,
12339 name: MetadataString,
12340 file: Metadata,
12341 scope: Metadata,
12342 line: u32,
12343 ty: Metadata,
12344 arg_no: u32,
12345) Allocator.Error!Metadata {
12346 try self.ensureUnusedMetadataCapacity(1, Metadata.Parameter, 0);
12347 return self.debugParameterAssumeCapacity(name, file, scope, line, ty, arg_no);
12348}
12349
12350pub fn debugGlobalVar(
12351 self: *Builder,
12352 name: MetadataString,
12353 linkage_name: MetadataString,
12354 file: Metadata,
12355 scope: Metadata,
12356 line: u32,
12357 ty: Metadata,
12358 variable: Variable.Index,
12359 options: Metadata.GlobalVar.Options,
12360) Allocator.Error!Metadata {
12361 try self.ensureUnusedMetadataCapacity(1, Metadata.GlobalVar, 0);
12362 return self.debugGlobalVarAssumeCapacity(
12363 name,
12364 linkage_name,
12365 file,
12366 scope,
12367 line,
12368 ty,
12369 variable,
12370 options,
12371 );
12372}
12373
12374pub fn debugGlobalVarExpression(
12375 self: *Builder,
12376 variable: Metadata,
12377 expression: Metadata,
12378) Allocator.Error!Metadata {
12379 try self.ensureUnusedMetadataCapacity(1, Metadata.GlobalVarExpression, 0);
12380 return self.debugGlobalVarExpressionAssumeCapacity(variable, expression);
12381}
12382
12383pub fn metadataConstant(self: *Builder, value: Constant) Allocator.Error!Metadata {
12384 try self.ensureUnusedMetadataCapacity(1, NoExtra, 0);
12385 return self.metadataConstantAssumeCapacity(value);
12386}
12387
12388pub fn debugForwardReferenceSetType(self: *Builder, fwd_ref: Metadata, ty: Metadata) void {
12389 assert(
12390 @intFromEnum(fwd_ref) >= Metadata.first_forward_reference and
12391 @intFromEnum(fwd_ref) <= Metadata.first_local_metadata,
12392 );
12393 const index = @intFromEnum(fwd_ref) - Metadata.first_forward_reference;
12394 self.metadata_forward_references.items[index] = ty;
12395}
12396
12397fn metadataSimpleAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytype) Metadata {
12398 const Key = struct {
12399 tag: Metadata.Tag,
12400 value: @TypeOf(value),
12401 };
12402 const Adapter = struct {
12403 builder: *const Builder,
12404 pub fn hash(_: @This(), key: Key) u32 {
12405 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
12406 inline for (std.meta.fields(@TypeOf(value))) |field| {
12407 hasher.update(std.mem.asBytes(&@field(key.value, field.name)));
12408 }
12409 return @truncate(hasher.final());
12410 }
12411
12412 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12413 if (lhs_key.tag != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12414 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12415 const rhs_extra = ctx.builder.metadataExtraData(@TypeOf(value), rhs_data);
12416 return std.meta.eql(lhs_key.value, rhs_extra);
12417 }
12418 };
12419
12420 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12421 Key{ .tag = tag, .value = value },
12422 Adapter{ .builder = self },
12423 );
12424
12425 if (!gop.found_existing) {
12426 gop.key_ptr.* = {};
12427 gop.value_ptr.* = {};
12428 self.metadata_items.appendAssumeCapacity(.{
12429 .tag = tag,
12430 .data = self.addMetadataExtraAssumeCapacity(value),
12431 });
12432 }
12433 return @enumFromInt(gop.index);
12434}
12435
12436fn metadataDistinctAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytype) Metadata {
12437 const Key = struct { tag: Metadata.Tag, index: Metadata };
12438 const Adapter = struct {
12439 pub fn hash(_: @This(), key: Key) u32 {
12440 return @truncate(std.hash.Wyhash.hash(
12441 std.hash.uint32(@intFromEnum(key.tag)),
12442 std.mem.asBytes(&key.index),
12443 ));
12444 }
12445
12446 pub fn eql(_: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12447 return @intFromEnum(lhs_key.index) == rhs_index;
12448 }
12449 };
12450
12451 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12452 Key{ .tag = tag, .index = @enumFromInt(self.metadata_map.count()) },
12453 Adapter{},
12454 );
12455
12456 if (!gop.found_existing) {
12457 gop.key_ptr.* = {};
12458 gop.value_ptr.* = {};
12459 self.metadata_items.appendAssumeCapacity(.{
12460 .tag = tag,
12461 .data = self.addMetadataExtraAssumeCapacity(value),
12462 });
12463 }
12464 return @enumFromInt(gop.index);
12465}
12466
12467fn metadataNamedAssumeCapacity(self: *Builder, name: MetadataString, operands: []const Metadata) void {
12468 assert(name != .none);
12469 const extra_index: u32 = @intCast(self.metadata_extra.items.len);
12470 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(operands));
12471
12472 const gop = self.metadata_named.getOrPutAssumeCapacity(name);
12473 gop.value_ptr.* = .{
12474 .index = extra_index,
12475 .len = @intCast(operands.len),
12476 };
12477}
12478
12479pub fn metadataNoneAssumeCapacity(self: *Builder) Metadata {
12480 return self.metadataSimpleAssumeCapacity(.none, .{});
12481}
12482
12483fn debugFileAssumeCapacity(
12484 self: *Builder,
12485 filename: MetadataString,
12486 directory: MetadataString,
12487) Metadata {
12488 assert(!self.strip);
12489 return self.metadataSimpleAssumeCapacity(.file, Metadata.File{
12490 .filename = filename,
12491 .directory = directory,
12492 });
12493}
12494
12495pub fn debugCompileUnitAssumeCapacity(
12496 self: *Builder,
12497 file: Metadata,
12498 producer: MetadataString,
12499 enums: Metadata,
12500 globals: Metadata,
12501 options: Metadata.CompileUnit.Options,
12502) Metadata {
12503 assert(!self.strip);
12504 return self.metadataDistinctAssumeCapacity(
12505 if (options.optimized) .@"compile_unit optimized" else .compile_unit,
12506 Metadata.CompileUnit{
12507 .file = file,
12508 .producer = producer,
12509 .enums = enums,
12510 .globals = globals,
12511 },
12512 );
12513}
12514
12515fn debugSubprogramAssumeCapacity(
12516 self: *Builder,
12517 file: Metadata,
12518 name: MetadataString,
12519 linkage_name: MetadataString,
12520 line: u32,
12521 scope_line: u32,
12522 ty: Metadata,
12523 options: Metadata.Subprogram.Options,
12524 compile_unit: Metadata,
12525) Metadata {
12526 assert(!self.strip);
12527 const tag: Metadata.Tag = @enumFromInt(@intFromEnum(Metadata.Tag.subprogram) +
12528 @as(u3, @truncate(@as(u32, @bitCast(options.sp_flags)) >> 2)));
12529 return self.metadataDistinctAssumeCapacity(tag, Metadata.Subprogram{
12530 .file = file,
12531 .name = name,
12532 .linkage_name = linkage_name,
12533 .line = line,
12534 .scope_line = scope_line,
12535 .ty = ty,
12536 .di_flags = options.di_flags,
12537 .compile_unit = compile_unit,
12538 });
12539}
12540
12541fn debugLexicalBlockAssumeCapacity(self: *Builder, scope: Metadata, file: Metadata, line: u32, column: u32) Metadata {
12542 assert(!self.strip);
12543 return self.metadataSimpleAssumeCapacity(.lexical_block, Metadata.LexicalBlock{
12544 .scope = scope,
12545 .file = file,
12546 .line = line,
12547 .column = column,
12548 });
12549}
12550
12551fn debugLocationAssumeCapacity(self: *Builder, line: u32, column: u32, scope: Metadata, inlined_at: Metadata) Metadata {
12552 assert(!self.strip);
12553 return self.metadataSimpleAssumeCapacity(.location, Metadata.Location{
12554 .line = line,
12555 .column = column,
12556 .scope = scope,
12557 .inlined_at = inlined_at,
12558 });
12559}
12560
12561fn debugBoolTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12562 assert(!self.strip);
12563 return self.metadataSimpleAssumeCapacity(.basic_bool_type, Metadata.BasicType{
12564 .name = name,
12565 .size_in_bits_lo = @truncate(size_in_bits),
12566 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12567 });
12568}
12569
12570fn debugUnsignedTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12571 assert(!self.strip);
12572 return self.metadataSimpleAssumeCapacity(.basic_unsigned_type, Metadata.BasicType{
12573 .name = name,
12574 .size_in_bits_lo = @truncate(size_in_bits),
12575 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12576 });
12577}
12578
12579fn debugSignedTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12580 assert(!self.strip);
12581 return self.metadataSimpleAssumeCapacity(.basic_signed_type, Metadata.BasicType{
12582 .name = name,
12583 .size_in_bits_lo = @truncate(size_in_bits),
12584 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12585 });
12586}
12587
12588fn debugFloatTypeAssumeCapacity(self: *Builder, name: MetadataString, size_in_bits: u64) Metadata {
12589 assert(!self.strip);
12590 return self.metadataSimpleAssumeCapacity(.basic_float_type, Metadata.BasicType{
12591 .name = name,
12592 .size_in_bits_lo = @truncate(size_in_bits),
12593 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12594 });
12595}
12596
12597fn debugForwardReferenceAssumeCapacity(self: *Builder) Metadata {
12598 assert(!self.strip);
12599 const index = Metadata.first_forward_reference + self.metadata_forward_references.items.len;
12600 self.metadata_forward_references.appendAssumeCapacity(.none);
12601 return @enumFromInt(index);
12602}
12603
12604fn debugStructTypeAssumeCapacity(
12605 self: *Builder,
12606 name: MetadataString,
12607 file: Metadata,
12608 scope: Metadata,
12609 line: u32,
12610 underlying_type: Metadata,
12611 size_in_bits: u64,
12612 align_in_bits: u64,
12613 fields_tuple: Metadata,
12614) Metadata {
12615 assert(!self.strip);
12616 return self.debugCompositeTypeAssumeCapacity(
12617 .composite_struct_type,
12618 name,
12619 file,
12620 scope,
12621 line,
12622 underlying_type,
12623 size_in_bits,
12624 align_in_bits,
12625 fields_tuple,
12626 );
12627}
12628
12629fn debugUnionTypeAssumeCapacity(
12630 self: *Builder,
12631 name: MetadataString,
12632 file: Metadata,
12633 scope: Metadata,
12634 line: u32,
12635 underlying_type: Metadata,
12636 size_in_bits: u64,
12637 align_in_bits: u64,
12638 fields_tuple: Metadata,
12639) Metadata {
12640 assert(!self.strip);
12641 return self.debugCompositeTypeAssumeCapacity(
12642 .composite_union_type,
12643 name,
12644 file,
12645 scope,
12646 line,
12647 underlying_type,
12648 size_in_bits,
12649 align_in_bits,
12650 fields_tuple,
12651 );
12652}
12653
12654fn debugEnumerationTypeAssumeCapacity(
12655 self: *Builder,
12656 name: MetadataString,
12657 file: Metadata,
12658 scope: Metadata,
12659 line: u32,
12660 underlying_type: Metadata,
12661 size_in_bits: u64,
12662 align_in_bits: u64,
12663 fields_tuple: Metadata,
12664) Metadata {
12665 assert(!self.strip);
12666 return self.debugCompositeTypeAssumeCapacity(
12667 .composite_enumeration_type,
12668 name,
12669 file,
12670 scope,
12671 line,
12672 underlying_type,
12673 size_in_bits,
12674 align_in_bits,
12675 fields_tuple,
12676 );
12677}
12678
12679fn debugArrayTypeAssumeCapacity(
12680 self: *Builder,
12681 name: MetadataString,
12682 file: Metadata,
12683 scope: Metadata,
12684 line: u32,
12685 underlying_type: Metadata,
12686 size_in_bits: u64,
12687 align_in_bits: u64,
12688 fields_tuple: Metadata,
12689) Metadata {
12690 assert(!self.strip);
12691 return self.debugCompositeTypeAssumeCapacity(
12692 .composite_array_type,
12693 name,
12694 file,
12695 scope,
12696 line,
12697 underlying_type,
12698 size_in_bits,
12699 align_in_bits,
12700 fields_tuple,
12701 );
12702}
12703
12704fn debugVectorTypeAssumeCapacity(
12705 self: *Builder,
12706 name: MetadataString,
12707 file: Metadata,
12708 scope: Metadata,
12709 line: u32,
12710 underlying_type: Metadata,
12711 size_in_bits: u64,
12712 align_in_bits: u64,
12713 fields_tuple: Metadata,
12714) Metadata {
12715 assert(!self.strip);
12716 return self.debugCompositeTypeAssumeCapacity(
12717 .composite_vector_type,
12718 name,
12719 file,
12720 scope,
12721 line,
12722 underlying_type,
12723 size_in_bits,
12724 align_in_bits,
12725 fields_tuple,
12726 );
12727}
12728
12729fn debugCompositeTypeAssumeCapacity(
12730 self: *Builder,
12731 tag: Metadata.Tag,
12732 name: MetadataString,
12733 file: Metadata,
12734 scope: Metadata,
12735 line: u32,
12736 underlying_type: Metadata,
12737 size_in_bits: u64,
12738 align_in_bits: u64,
12739 fields_tuple: Metadata,
12740) Metadata {
12741 assert(!self.strip);
12742 return self.metadataSimpleAssumeCapacity(tag, Metadata.CompositeType{
12743 .name = name,
12744 .file = file,
12745 .scope = scope,
12746 .line = line,
12747 .underlying_type = underlying_type,
12748 .size_in_bits_lo = @truncate(size_in_bits),
12749 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12750 .align_in_bits_lo = @truncate(align_in_bits),
12751 .align_in_bits_hi = @truncate(align_in_bits >> 32),
12752 .fields_tuple = fields_tuple,
12753 });
12754}
12755
12756fn debugPointerTypeAssumeCapacity(
12757 self: *Builder,
12758 name: MetadataString,
12759 file: Metadata,
12760 scope: Metadata,
12761 line: u32,
12762 underlying_type: Metadata,
12763 size_in_bits: u64,
12764 align_in_bits: u64,
12765 offset_in_bits: u64,
12766) Metadata {
12767 assert(!self.strip);
12768 return self.metadataSimpleAssumeCapacity(.derived_pointer_type, Metadata.DerivedType{
12769 .name = name,
12770 .file = file,
12771 .scope = scope,
12772 .line = line,
12773 .underlying_type = underlying_type,
12774 .size_in_bits_lo = @truncate(size_in_bits),
12775 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12776 .align_in_bits_lo = @truncate(align_in_bits),
12777 .align_in_bits_hi = @truncate(align_in_bits >> 32),
12778 .offset_in_bits_lo = @truncate(offset_in_bits),
12779 .offset_in_bits_hi = @truncate(offset_in_bits >> 32),
12780 });
12781}
12782
12783fn debugMemberTypeAssumeCapacity(
12784 self: *Builder,
12785 name: MetadataString,
12786 file: Metadata,
12787 scope: Metadata,
12788 line: u32,
12789 underlying_type: Metadata,
12790 size_in_bits: u64,
12791 align_in_bits: u64,
12792 offset_in_bits: u64,
12793) Metadata {
12794 assert(!self.strip);
12795 return self.metadataSimpleAssumeCapacity(.derived_member_type, Metadata.DerivedType{
12796 .name = name,
12797 .file = file,
12798 .scope = scope,
12799 .line = line,
12800 .underlying_type = underlying_type,
12801 .size_in_bits_lo = @truncate(size_in_bits),
12802 .size_in_bits_hi = @truncate(size_in_bits >> 32),
12803 .align_in_bits_lo = @truncate(align_in_bits),
12804 .align_in_bits_hi = @truncate(align_in_bits >> 32),
12805 .offset_in_bits_lo = @truncate(offset_in_bits),
12806 .offset_in_bits_hi = @truncate(offset_in_bits >> 32),
12807 });
12808}
12809
12810fn debugSubroutineTypeAssumeCapacity(
12811 self: *Builder,
12812 types_tuple: Metadata,
12813) Metadata {
12814 assert(!self.strip);
12815 return self.metadataSimpleAssumeCapacity(.subroutine_type, Metadata.SubroutineType{
12816 .types_tuple = types_tuple,
12817 });
12818}
12819
12820fn debugEnumeratorAssumeCapacity(
12821 self: *Builder,
12822 name: MetadataString,
12823 unsigned: bool,
12824 bit_width: u32,
12825 value: std.math.big.int.Const,
12826) Metadata {
12827 assert(!self.strip);
12828 const Key = struct {
12829 tag: Metadata.Tag,
12830 name: MetadataString,
12831 bit_width: u32,
12832 value: std.math.big.int.Const,
12833 };
12834 const Adapter = struct {
12835 builder: *const Builder,
12836 pub fn hash(_: @This(), key: Key) u32 {
12837 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
12838 hasher.update(std.mem.asBytes(&key.name));
12839 hasher.update(std.mem.asBytes(&key.bit_width));
12840 hasher.update(std.mem.sliceAsBytes(key.value.limbs));
12841 return @truncate(hasher.final());
12842 }
12843
12844 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12845 if (lhs_key.tag != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12846 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12847 const rhs_extra = ctx.builder.metadataExtraData(Metadata.Enumerator, rhs_data);
12848 const limbs = ctx.builder.metadata_limbs
12849 .items[rhs_extra.limbs_index..][0..rhs_extra.limbs_len];
12850 const rhs_value = std.math.big.int.Const{
12851 .limbs = limbs,
12852 .positive = lhs_key.value.positive,
12853 };
12854 return lhs_key.name == rhs_extra.name and
12855 lhs_key.bit_width == rhs_extra.bit_width and
12856 lhs_key.value.eql(rhs_value);
12857 }
12858 };
12859
12860 const tag: Metadata.Tag = if (unsigned)
12861 .enumerator_unsigned
12862 else if (value.positive)
12863 .enumerator_signed_positive
12864 else
12865 .enumerator_signed_negative;
12866
12867 assert(!(tag == .enumerator_unsigned and !value.positive));
12868
12869 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12870 Key{
12871 .tag = tag,
12872 .name = name,
12873 .bit_width = bit_width,
12874 .value = value,
12875 },
12876 Adapter{ .builder = self },
12877 );
12878
12879 if (!gop.found_existing) {
12880 gop.key_ptr.* = {};
12881 gop.value_ptr.* = {};
12882 self.metadata_items.appendAssumeCapacity(.{
12883 .tag = tag,
12884 .data = self.addMetadataExtraAssumeCapacity(Metadata.Enumerator{
12885 .name = name,
12886 .bit_width = bit_width,
12887 .limbs_index = @intCast(self.metadata_limbs.items.len),
12888 .limbs_len = @intCast(value.limbs.len),
12889 }),
12890 });
12891 self.metadata_limbs.appendSliceAssumeCapacity(value.limbs);
12892 }
12893 return @enumFromInt(gop.index);
12894}
12895
12896fn debugSubrangeAssumeCapacity(
12897 self: *Builder,
12898 lower_bound: Metadata,
12899 count: Metadata,
12900) Metadata {
12901 assert(!self.strip);
12902 return self.metadataSimpleAssumeCapacity(.subrange, Metadata.Subrange{
12903 .lower_bound = lower_bound,
12904 .count = count,
12905 });
12906}
12907
12908fn debugExpressionAssumeCapacity(
12909 self: *Builder,
12910 elements: []const u32,
12911) Metadata {
12912 assert(!self.strip);
12913 const Key = struct {
12914 elements: []const u32,
12915 };
12916 const Adapter = struct {
12917 builder: *const Builder,
12918 pub fn hash(_: @This(), key: Key) u32 {
12919 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.expression)));
12920 hasher.update(std.mem.sliceAsBytes(key.elements));
12921 return @truncate(hasher.final());
12922 }
12923
12924 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12925 if (Metadata.Tag.expression != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12926 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12927 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.Expression, rhs_data);
12928 return std.mem.eql(
12929 u32,
12930 lhs_key.elements,
12931 rhs_extra.trail.next(rhs_extra.data.elements_len, u32, ctx.builder),
12932 );
12933 }
12934 };
12935
12936 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12937 Key{ .elements = elements },
12938 Adapter{ .builder = self },
12939 );
12940
12941 if (!gop.found_existing) {
12942 gop.key_ptr.* = {};
12943 gop.value_ptr.* = {};
12944 self.metadata_items.appendAssumeCapacity(.{
12945 .tag = .expression,
12946 .data = self.addMetadataExtraAssumeCapacity(Metadata.Expression{
12947 .elements_len = @intCast(elements.len),
12948 }),
12949 });
12950 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(elements));
12951 }
12952 return @enumFromInt(gop.index);
12953}
12954
12955fn metadataTupleAssumeCapacity(
12956 self: *Builder,
12957 elements: []const Metadata,
12958) Metadata {
12959 const Key = struct {
12960 elements: []const Metadata,
12961 };
12962 const Adapter = struct {
12963 builder: *const Builder,
12964 pub fn hash(_: @This(), key: Key) u32 {
12965 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.tuple)));
12966 hasher.update(std.mem.sliceAsBytes(key.elements));
12967 return @truncate(hasher.final());
12968 }
12969
12970 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
12971 if (Metadata.Tag.tuple != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
12972 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
12973 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.Tuple, rhs_data);
12974 return std.mem.eql(
12975 Metadata,
12976 lhs_key.elements,
12977 rhs_extra.trail.next(rhs_extra.data.elements_len, Metadata, ctx.builder),
12978 );
12979 }
12980 };
12981
12982 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
12983 Key{ .elements = elements },
12984 Adapter{ .builder = self },
12985 );
12986
12987 if (!gop.found_existing) {
12988 gop.key_ptr.* = {};
12989 gop.value_ptr.* = {};
12990 self.metadata_items.appendAssumeCapacity(.{
12991 .tag = .tuple,
12992 .data = self.addMetadataExtraAssumeCapacity(Metadata.Tuple{
12993 .elements_len = @intCast(elements.len),
12994 }),
12995 });
12996 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(elements));
12997 }
12998 return @enumFromInt(gop.index);
12999}
13000
13001fn strTupleAssumeCapacity(
13002 self: *Builder,
13003 str: MetadataString,
13004 elements: []const Metadata,
13005) Metadata {
13006 const Key = struct {
13007 str: MetadataString,
13008 elements: []const Metadata,
13009 };
13010 const Adapter = struct {
13011 builder: *const Builder,
13012 pub fn hash(_: @This(), key: Key) u32 {
13013 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.tuple)));
13014 hasher.update(std.mem.sliceAsBytes(key.elements));
13015 return @truncate(hasher.final());
13016 }
13017
13018 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
13019 if (.str_tuple != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
13020 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
13021 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.StrTuple, rhs_data);
13022 return rhs_extra.data.str == lhs_key.str and std.mem.eql(
13023 Metadata,
13024 lhs_key.elements,
13025 rhs_extra.trail.next(rhs_extra.data.elements_len, Metadata, ctx.builder),
13026 );
13027 }
13028 };
13029
13030 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
13031 Key{ .str = str, .elements = elements },
13032 Adapter{ .builder = self },
13033 );
13034
13035 if (!gop.found_existing) {
13036 gop.key_ptr.* = {};
13037 gop.value_ptr.* = {};
13038 self.metadata_items.appendAssumeCapacity(.{
13039 .tag = .str_tuple,
13040 .data = self.addMetadataExtraAssumeCapacity(Metadata.StrTuple{
13041 .str = str,
13042 .elements_len = @intCast(elements.len),
13043 }),
13044 });
13045 self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(elements));
13046 }
13047 return @enumFromInt(gop.index);
13048}
13049
13050fn metadataModuleFlagAssumeCapacity(
13051 self: *Builder,
13052 behavior: Metadata,
13053 name: MetadataString,
13054 constant: Metadata,
13055) Metadata {
13056 return self.metadataSimpleAssumeCapacity(.module_flag, Metadata.ModuleFlag{
13057 .behavior = behavior,
13058 .name = name,
13059 .constant = constant,
13060 });
13061}
13062
13063fn debugLocalVarAssumeCapacity(
13064 self: *Builder,
13065 name: MetadataString,
13066 file: Metadata,
13067 scope: Metadata,
13068 line: u32,
13069 ty: Metadata,
13070) Metadata {
13071 assert(!self.strip);
13072 return self.metadataSimpleAssumeCapacity(.local_var, Metadata.LocalVar{
13073 .name = name,
13074 .file = file,
13075 .scope = scope,
13076 .line = line,
13077 .ty = ty,
13078 });
13079}
13080
13081fn debugParameterAssumeCapacity(
13082 self: *Builder,
13083 name: MetadataString,
13084 file: Metadata,
13085 scope: Metadata,
13086 line: u32,
13087 ty: Metadata,
13088 arg_no: u32,
13089) Metadata {
13090 assert(!self.strip);
13091 return self.metadataSimpleAssumeCapacity(.parameter, Metadata.Parameter{
13092 .name = name,
13093 .file = file,
13094 .scope = scope,
13095 .line = line,
13096 .ty = ty,
13097 .arg_no = arg_no,
13098 });
13099}
13100
13101fn debugGlobalVarAssumeCapacity(
13102 self: *Builder,
13103 name: MetadataString,
13104 linkage_name: MetadataString,
13105 file: Metadata,
13106 scope: Metadata,
13107 line: u32,
13108 ty: Metadata,
13109 variable: Variable.Index,
13110 options: Metadata.GlobalVar.Options,
13111) Metadata {
13112 assert(!self.strip);
13113 return self.metadataDistinctAssumeCapacity(
13114 if (options.local) .@"global_var local" else .global_var,
13115 Metadata.GlobalVar{
13116 .name = name,
13117 .linkage_name = linkage_name,
13118 .file = file,
13119 .scope = scope,
13120 .line = line,
13121 .ty = ty,
13122 .variable = variable,
13123 },
13124 );
13125}
13126
13127fn debugGlobalVarExpressionAssumeCapacity(
13128 self: *Builder,
13129 variable: Metadata,
13130 expression: Metadata,
13131) Metadata {
13132 assert(!self.strip);
13133 return self.metadataSimpleAssumeCapacity(.global_var_expression, Metadata.GlobalVarExpression{
13134 .variable = variable,
13135 .expression = expression,
13136 });
13137}
13138
13139fn metadataConstantAssumeCapacity(self: *Builder, constant: Constant) Metadata {
13140 const Adapter = struct {
13141 builder: *const Builder,
13142 pub fn hash(_: @This(), key: Constant) u32 {
13143 var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.constant)));
13144 hasher.update(std.mem.asBytes(&key));
13145 return @truncate(hasher.final());
13146 }
13147
13148 pub fn eql(ctx: @This(), lhs_key: Constant, _: void, rhs_index: usize) bool {
13149 if (Metadata.Tag.constant != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
13150 const rhs_data: Constant = @enumFromInt(ctx.builder.metadata_items.items(.data)[rhs_index]);
13151 return rhs_data == lhs_key;
13152 }
13153 };
13154
13155 const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
13156 constant,
13157 Adapter{ .builder = self },
13158 );
13159
13160 if (!gop.found_existing) {
13161 gop.key_ptr.* = {};
13162 gop.value_ptr.* = {};
13163 self.metadata_items.appendAssumeCapacity(.{
13164 .tag = .constant,
13165 .data = @intFromEnum(constant),
13166 });
13167 }
13168 return @enumFromInt(gop.index);
13169}
13170
13171pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]const u32 {
13172 const BitcodeWriter = bitcode_writer.BitcodeWriter(&.{ Type, FunctionAttributes });
13173 var bitcode = BitcodeWriter.init(allocator, .{
13174 std.math.log2_int_ceil(usize, self.type_items.items.len),
13175 std.math.log2_int_ceil(usize, 1 + self.function_attributes_set.count()),
13176 });
13177 errdefer bitcode.deinit();
13178
13179 // Write LLVM IR magic
13180 try bitcode.writeBits(ir.MAGIC, 32);
13181
13182 var record: std.ArrayListUnmanaged(u64) = .empty;
13183 defer record.deinit(self.gpa);
13184
13185 // IDENTIFICATION_BLOCK
13186 {
13187 const Identification = ir.Identification;
13188 var identification_block = try bitcode.enterTopBlock(Identification);
13189
13190 const producer = try std.fmt.allocPrint(self.gpa, "zig {d}.{d}.{d}", .{
13191 build_options.semver.major,
13192 build_options.semver.minor,
13193 build_options.semver.patch,
13194 });
13195 defer self.gpa.free(producer);
13196
13197 try identification_block.writeAbbrev(Identification.Version{ .string = producer });
13198 try identification_block.writeAbbrev(Identification.Epoch{ .epoch = 0 });
13199
13200 try identification_block.end();
13201 }
13202
13203 // MODULE_BLOCK
13204 {
13205 const Module = ir.Module;
13206 var module_block = try bitcode.enterTopBlock(Module);
13207
13208 try module_block.writeAbbrev(Module.Version{});
13209
13210 if (self.target_triple.slice(self)) |triple| {
13211 try module_block.writeAbbrev(Module.String{
13212 .code = 2,
13213 .string = triple,
13214 });
13215 }
13216
13217 if (self.data_layout.slice(self)) |data_layout| {
13218 try module_block.writeAbbrev(Module.String{
13219 .code = 3,
13220 .string = data_layout,
13221 });
13222 }
13223
13224 if (self.source_filename.slice(self)) |source_filename| {
13225 try module_block.writeAbbrev(Module.String{
13226 .code = 16,
13227 .string = source_filename,
13228 });
13229 }
13230
13231 if (self.module_asm.items.len != 0) {
13232 try module_block.writeAbbrev(Module.String{
13233 .code = 4,
13234 .string = self.module_asm.items,
13235 });
13236 }
13237
13238 // TYPE_BLOCK
13239 {
13240 var type_block = try module_block.enterSubBlock(ir.Type, true);
13241
13242 try type_block.writeAbbrev(ir.Type.NumEntry{ .num = @intCast(self.type_items.items.len) });
13243
13244 for (self.type_items.items, 0..) |item, i| {
13245 const ty: Type = @enumFromInt(i);
13246
13247 switch (item.tag) {
13248 .simple => try type_block.writeAbbrev(ir.Type.Simple{ .code = @truncate(item.data) }),
13249 .integer => try type_block.writeAbbrev(ir.Type.Integer{ .width = item.data }),
13250 .structure,
13251 .packed_structure,
13252 => |kind| {
13253 const is_packed = switch (kind) {
13254 .structure => false,
13255 .packed_structure => true,
13256 else => unreachable,
13257 };
13258 var extra = self.typeExtraDataTrail(Type.Structure, item.data);
13259 try type_block.writeAbbrev(ir.Type.StructAnon{
13260 .is_packed = is_packed,
13261 .types = extra.trail.next(extra.data.fields_len, Type, self),
13262 });
13263 },
13264 .named_structure => {
13265 const extra = self.typeExtraData(Type.NamedStructure, item.data);
13266 try type_block.writeAbbrev(ir.Type.StructName{
13267 .string = extra.id.slice(self).?,
13268 });
13269
13270 switch (extra.body) {
13271 .none => try type_block.writeAbbrev(ir.Type.Opaque{}),
13272 else => {
13273 const real_struct = self.type_items.items[@intFromEnum(extra.body)];
13274 const is_packed: bool = switch (real_struct.tag) {
13275 .structure => false,
13276 .packed_structure => true,
13277 else => unreachable,
13278 };
13279
13280 var real_extra = self.typeExtraDataTrail(Type.Structure, real_struct.data);
13281 try type_block.writeAbbrev(ir.Type.StructNamed{
13282 .is_packed = is_packed,
13283 .types = real_extra.trail.next(real_extra.data.fields_len, Type, self),
13284 });
13285 },
13286 }
13287 },
13288 .array,
13289 .small_array,
13290 => try type_block.writeAbbrev(ir.Type.Array{
13291 .len = ty.aggregateLen(self),
13292 .child = ty.childType(self),
13293 }),
13294 .vector,
13295 .scalable_vector,
13296 => try type_block.writeAbbrev(ir.Type.Vector{
13297 .len = ty.aggregateLen(self),
13298 .child = ty.childType(self),
13299 }),
13300 .pointer => try type_block.writeAbbrev(ir.Type.Pointer{
13301 .addr_space = ty.pointerAddrSpace(self),
13302 }),
13303 .target => {
13304 var extra = self.typeExtraDataTrail(Type.Target, item.data);
13305 try type_block.writeAbbrev(ir.Type.StructName{
13306 .string = extra.data.name.slice(self).?,
13307 });
13308
13309 const types = extra.trail.next(extra.data.types_len, Type, self);
13310 const ints = extra.trail.next(extra.data.ints_len, u32, self);
13311
13312 try type_block.writeAbbrev(ir.Type.Target{
13313 .num_types = extra.data.types_len,
13314 .types = types,
13315 .ints = ints,
13316 });
13317 },
13318 .function, .vararg_function => |kind| {
13319 const is_vararg = switch (kind) {
13320 .function => false,
13321 .vararg_function => true,
13322 else => unreachable,
13323 };
13324 var extra = self.typeExtraDataTrail(Type.Function, item.data);
13325 try type_block.writeAbbrev(ir.Type.Function{
13326 .is_vararg = is_vararg,
13327 .return_type = extra.data.ret,
13328 .param_types = extra.trail.next(extra.data.params_len, Type, self),
13329 });
13330 },
13331 }
13332 }
13333
13334 try type_block.end();
13335 }
13336
13337 var attributes_set: std.AutoArrayHashMapUnmanaged(struct {
13338 attributes: Attributes,
13339 index: u32,
13340 }, void) = .{};
13341 defer attributes_set.deinit(self.gpa);
13342
13343 // PARAMATTR_GROUP_BLOCK
13344 {
13345 const ParamattrGroup = ir.ParamattrGroup;
13346
13347 var paramattr_group_block = try module_block.enterSubBlock(ParamattrGroup, true);
13348
13349 for (self.function_attributes_set.keys()) |func_attributes| {
13350 for (func_attributes.slice(self), 0..) |attributes, i| {
13351 const attributes_slice = attributes.slice(self);
13352 if (attributes_slice.len == 0) continue;
13353
13354 const attr_gop = try attributes_set.getOrPut(self.gpa, .{
13355 .attributes = attributes,
13356 .index = @intCast(i),
13357 });
13358
13359 if (attr_gop.found_existing) continue;
13360
13361 record.clearRetainingCapacity();
13362 try record.ensureUnusedCapacity(self.gpa, 2);
13363
13364 record.appendAssumeCapacity(attr_gop.index);
13365 record.appendAssumeCapacity(switch (i) {
13366 0 => 0xffffffff,
13367 else => i - 1,
13368 });
13369
13370 for (attributes_slice) |attr_index| {
13371 const kind = attr_index.getKind(self);
13372 switch (attr_index.toAttribute(self)) {
13373 .zeroext,
13374 .signext,
13375 .inreg,
13376 .@"noalias",
13377 .nocapture,
13378 .nofree,
13379 .nest,
13380 .returned,
13381 .nonnull,
13382 .swiftself,
13383 .swiftasync,
13384 .swifterror,
13385 .immarg,
13386 .noundef,
13387 .allocalign,
13388 .allocptr,
13389 .readnone,
13390 .readonly,
13391 .writeonly,
13392 .alwaysinline,
13393 .builtin,
13394 .cold,
13395 .convergent,
13396 .disable_sanitizer_information,
13397 .fn_ret_thunk_extern,
13398 .hot,
13399 .inlinehint,
13400 .jumptable,
13401 .minsize,
13402 .naked,
13403 .nobuiltin,
13404 .nocallback,
13405 .noduplicate,
13406 .noimplicitfloat,
13407 .@"noinline",
13408 .nomerge,
13409 .nonlazybind,
13410 .noprofile,
13411 .skipprofile,
13412 .noredzone,
13413 .noreturn,
13414 .norecurse,
13415 .willreturn,
13416 .nosync,
13417 .nounwind,
13418 .nosanitize_bounds,
13419 .nosanitize_coverage,
13420 .null_pointer_is_valid,
13421 .optforfuzzing,
13422 .optnone,
13423 .optsize,
13424 .returns_twice,
13425 .safestack,
13426 .sanitize_address,
13427 .sanitize_memory,
13428 .sanitize_thread,
13429 .sanitize_hwaddress,
13430 .sanitize_memtag,
13431 .speculative_load_hardening,
13432 .speculatable,
13433 .ssp,
13434 .sspstrong,
13435 .sspreq,
13436 .strictfp,
13437 .nocf_check,
13438 .shadowcallstack,
13439 .mustprogress,
13440 .no_sanitize_address,
13441 .no_sanitize_hwaddress,
13442 .sanitize_address_dyninit,
13443 => {
13444 try record.ensureUnusedCapacity(self.gpa, 2);
13445 record.appendAssumeCapacity(0);
13446 record.appendAssumeCapacity(@intFromEnum(kind));
13447 },
13448 .byval,
13449 .byref,
13450 .preallocated,
13451 .inalloca,
13452 .sret,
13453 .elementtype,
13454 => |ty| {
13455 try record.ensureUnusedCapacity(self.gpa, 3);
13456 record.appendAssumeCapacity(6);
13457 record.appendAssumeCapacity(@intFromEnum(kind));
13458 record.appendAssumeCapacity(@intFromEnum(ty));
13459 },
13460 .@"align",
13461 .alignstack,
13462 => |alignment| {
13463 try record.ensureUnusedCapacity(self.gpa, 3);
13464 record.appendAssumeCapacity(1);
13465 record.appendAssumeCapacity(@intFromEnum(kind));
13466 record.appendAssumeCapacity(alignment.toByteUnits() orelse 0);
13467 },
13468 .dereferenceable,
13469 .dereferenceable_or_null,
13470 => |size| {
13471 try record.ensureUnusedCapacity(self.gpa, 3);
13472 record.appendAssumeCapacity(1);
13473 record.appendAssumeCapacity(@intFromEnum(kind));
13474 record.appendAssumeCapacity(size);
13475 },
13476 .nofpclass => |fpclass| {
13477 try record.ensureUnusedCapacity(self.gpa, 3);
13478 record.appendAssumeCapacity(1);
13479 record.appendAssumeCapacity(@intFromEnum(kind));
13480 record.appendAssumeCapacity(@as(u32, @bitCast(fpclass)));
13481 },
13482 .allockind => |allockind| {
13483 try record.ensureUnusedCapacity(self.gpa, 3);
13484 record.appendAssumeCapacity(1);
13485 record.appendAssumeCapacity(@intFromEnum(kind));
13486 record.appendAssumeCapacity(@as(u32, @bitCast(allockind)));
13487 },
13488
13489 .allocsize => |allocsize| {
13490 try record.ensureUnusedCapacity(self.gpa, 3);
13491 record.appendAssumeCapacity(1);
13492 record.appendAssumeCapacity(@intFromEnum(kind));
13493 record.appendAssumeCapacity(@bitCast(allocsize.toLlvm()));
13494 },
13495 .memory => |memory| {
13496 try record.ensureUnusedCapacity(self.gpa, 3);
13497 record.appendAssumeCapacity(1);
13498 record.appendAssumeCapacity(@intFromEnum(kind));
13499 record.appendAssumeCapacity(@as(u32, @bitCast(memory)));
13500 },
13501 .uwtable => |uwtable| if (uwtable != .none) {
13502 try record.ensureUnusedCapacity(self.gpa, 3);
13503 record.appendAssumeCapacity(1);
13504 record.appendAssumeCapacity(@intFromEnum(kind));
13505 record.appendAssumeCapacity(@intFromEnum(uwtable));
13506 },
13507 .vscale_range => |vscale_range| {
13508 try record.ensureUnusedCapacity(self.gpa, 3);
13509 record.appendAssumeCapacity(1);
13510 record.appendAssumeCapacity(@intFromEnum(kind));
13511 record.appendAssumeCapacity(@bitCast(vscale_range.toLlvm()));
13512 },
13513 .string => |string_attr| {
13514 const string_attr_kind_slice = string_attr.kind.slice(self).?;
13515 const string_attr_value_slice = if (string_attr.value != .none)
13516 string_attr.value.slice(self).?
13517 else
13518 null;
13519
13520 try record.ensureUnusedCapacity(
13521 self.gpa,
13522 2 + string_attr_kind_slice.len + if (string_attr_value_slice) |slice| slice.len + 1 else 0,
13523 );
13524 record.appendAssumeCapacity(if (string_attr.value == .none) 3 else 4);
13525 for (string_attr.kind.slice(self).?) |c| {
13526 record.appendAssumeCapacity(c);
13527 }
13528 record.appendAssumeCapacity(0);
13529 if (string_attr_value_slice) |slice| {
13530 for (slice) |c| {
13531 record.appendAssumeCapacity(c);
13532 }
13533 record.appendAssumeCapacity(0);
13534 }
13535 },
13536 .none => unreachable,
13537 }
13538 }
13539
13540 try paramattr_group_block.writeUnabbrev(3, record.items);
13541 }
13542 }
13543
13544 try paramattr_group_block.end();
13545 }
13546
13547 // PARAMATTR_BLOCK
13548 {
13549 const Paramattr = ir.Paramattr;
13550 var paramattr_block = try module_block.enterSubBlock(Paramattr, true);
13551
13552 for (self.function_attributes_set.keys()) |func_attributes| {
13553 const func_attributes_slice = func_attributes.slice(self);
13554 record.clearRetainingCapacity();
13555 try record.ensureUnusedCapacity(self.gpa, func_attributes_slice.len);
13556 for (func_attributes_slice, 0..) |attributes, i| {
13557 const attributes_slice = attributes.slice(self);
13558 if (attributes_slice.len == 0) continue;
13559
13560 const group_index = attributes_set.getIndex(.{
13561 .attributes = attributes,
13562 .index = @intCast(i),
13563 }).?;
13564 record.appendAssumeCapacity(@intCast(group_index));
13565 }
13566
13567 try paramattr_block.writeAbbrev(Paramattr.Entry{ .group_indices = record.items });
13568 }
13569
13570 try paramattr_block.end();
13571 }
13572
13573 var globals: std.AutoArrayHashMapUnmanaged(Global.Index, void) = .empty;
13574 defer globals.deinit(self.gpa);
13575 try globals.ensureUnusedCapacity(
13576 self.gpa,
13577 self.variables.items.len +
13578 self.functions.items.len +
13579 self.aliases.items.len,
13580 );
13581
13582 for (self.variables.items) |variable| {
13583 if (variable.global.getReplacement(self) != .none) continue;
13584
13585 globals.putAssumeCapacity(variable.global, {});
13586 }
13587
13588 for (self.functions.items) |function| {
13589 if (function.global.getReplacement(self) != .none) continue;
13590
13591 globals.putAssumeCapacity(function.global, {});
13592 }
13593
13594 for (self.aliases.items) |alias| {
13595 if (alias.global.getReplacement(self) != .none) continue;
13596
13597 globals.putAssumeCapacity(alias.global, {});
13598 }
13599
13600 const ConstantAdapter = struct {
13601 const ConstantAdapter = @This();
13602 builder: *const Builder,
13603 globals: *const std.AutoArrayHashMapUnmanaged(Global.Index, void),
13604
13605 pub fn get(adapter: @This(), param: anytype, comptime field_name: []const u8) @TypeOf(param) {
13606 _ = field_name;
13607 return switch (@TypeOf(param)) {
13608 Constant => @enumFromInt(adapter.getConstantIndex(param)),
13609 else => param,
13610 };
13611 }
13612
13613 pub fn getConstantIndex(adapter: ConstantAdapter, constant: Constant) u32 {
13614 return switch (constant.unwrap()) {
13615 .constant => |c| c + adapter.numGlobals(),
13616 .global => |global| @intCast(adapter.globals.getIndex(global.unwrap(adapter.builder)).?),
13617 };
13618 }
13619
13620 pub fn numConstants(adapter: ConstantAdapter) u32 {
13621 return @intCast(adapter.globals.count() + adapter.builder.constant_items.len);
13622 }
13623
13624 pub fn numGlobals(adapter: ConstantAdapter) u32 {
13625 return @intCast(adapter.globals.count());
13626 }
13627 };
13628
13629 const constant_adapter = ConstantAdapter{
13630 .builder = self,
13631 .globals = &globals,
13632 };
13633
13634 // Globals
13635 {
13636 var section_map: std.AutoArrayHashMapUnmanaged(String, void) = .empty;
13637 defer section_map.deinit(self.gpa);
13638 try section_map.ensureUnusedCapacity(self.gpa, globals.count());
13639
13640 for (self.variables.items) |variable| {
13641 if (variable.global.getReplacement(self) != .none) continue;
13642
13643 const section = blk: {
13644 if (variable.section == .none) break :blk 0;
13645 const gop = section_map.getOrPutAssumeCapacity(variable.section);
13646 if (!gop.found_existing) {
13647 try module_block.writeAbbrev(Module.String{
13648 .code = 5,
13649 .string = variable.section.slice(self).?,
13650 });
13651 }
13652 break :blk gop.index + 1;
13653 };
13654
13655 const initid = if (variable.init == .no_init)
13656 0
13657 else
13658 (constant_adapter.getConstantIndex(variable.init) + 1);
13659
13660 const strtab = variable.global.strtab(self);
13661
13662 const global = variable.global.ptrConst(self);
13663 try module_block.writeAbbrev(Module.Variable{
13664 .strtab_offset = strtab.offset,
13665 .strtab_size = strtab.size,
13666 .type_index = global.type,
13667 .is_const = .{
13668 .is_const = switch (variable.mutability) {
13669 .global => false,
13670 .constant => true,
13671 },
13672 .addr_space = global.addr_space,
13673 },
13674 .initid = initid,
13675 .linkage = global.linkage,
13676 .alignment = variable.alignment.toLlvm(),
13677 .section = section,
13678 .visibility = global.visibility,
13679 .thread_local = variable.thread_local,
13680 .unnamed_addr = global.unnamed_addr,
13681 .externally_initialized = global.externally_initialized,
13682 .dllstorageclass = global.dll_storage_class,
13683 .preemption = global.preemption,
13684 });
13685 }
13686
13687 for (self.functions.items) |func| {
13688 if (func.global.getReplacement(self) != .none) continue;
13689
13690 const section = blk: {
13691 if (func.section == .none) break :blk 0;
13692 const gop = section_map.getOrPutAssumeCapacity(func.section);
13693 if (!gop.found_existing) {
13694 try module_block.writeAbbrev(Module.String{
13695 .code = 5,
13696 .string = func.section.slice(self).?,
13697 });
13698 }
13699 break :blk gop.index + 1;
13700 };
13701
13702 const paramattr_index = if (self.function_attributes_set.getIndex(func.attributes)) |index|
13703 index + 1
13704 else
13705 0;
13706
13707 const strtab = func.global.strtab(self);
13708
13709 const global = func.global.ptrConst(self);
13710 try module_block.writeAbbrev(Module.Function{
13711 .strtab_offset = strtab.offset,
13712 .strtab_size = strtab.size,
13713 .type_index = global.type,
13714 .call_conv = func.call_conv,
13715 .is_proto = func.instructions.len == 0,
13716 .linkage = global.linkage,
13717 .paramattr = paramattr_index,
13718 .alignment = func.alignment.toLlvm(),
13719 .section = section,
13720 .visibility = global.visibility,
13721 .unnamed_addr = global.unnamed_addr,
13722 .dllstorageclass = global.dll_storage_class,
13723 .preemption = global.preemption,
13724 .addr_space = global.addr_space,
13725 });
13726 }
13727
13728 for (self.aliases.items) |alias| {
13729 if (alias.global.getReplacement(self) != .none) continue;
13730
13731 const strtab = alias.global.strtab(self);
13732
13733 const global = alias.global.ptrConst(self);
13734 try module_block.writeAbbrev(Module.Alias{
13735 .strtab_offset = strtab.offset,
13736 .strtab_size = strtab.size,
13737 .type_index = global.type,
13738 .addr_space = global.addr_space,
13739 .aliasee = constant_adapter.getConstantIndex(alias.aliasee),
13740 .linkage = global.linkage,
13741 .visibility = global.visibility,
13742 .thread_local = alias.thread_local,
13743 .unnamed_addr = global.unnamed_addr,
13744 .dllstorageclass = global.dll_storage_class,
13745 .preemption = global.preemption,
13746 });
13747 }
13748 }
13749
13750 // CONSTANTS_BLOCK
13751 {
13752 const Constants = ir.Constants;
13753 var constants_block = try module_block.enterSubBlock(Constants, true);
13754
13755 var current_type: Type = .none;
13756 const tags = self.constant_items.items(.tag);
13757 const datas = self.constant_items.items(.data);
13758 for (0..self.constant_items.len) |index| {
13759 record.clearRetainingCapacity();
13760 const constant: Constant = @enumFromInt(index);
13761 const constant_type = constant.typeOf(self);
13762 if (constant_type != current_type) {
13763 try constants_block.writeAbbrev(Constants.SetType{ .type_id = constant_type });
13764 current_type = constant_type;
13765 }
13766 const data = datas[index];
13767 switch (tags[index]) {
13768 .null,
13769 .zeroinitializer,
13770 .none,
13771 => try constants_block.writeAbbrev(Constants.Null{}),
13772 .undef => try constants_block.writeAbbrev(Constants.Undef{}),
13773 .poison => try constants_block.writeAbbrev(Constants.Poison{}),
13774 .positive_integer,
13775 .negative_integer,
13776 => |tag| {
13777 const extra: *align(@alignOf(std.math.big.Limb)) Constant.Integer =
13778 @ptrCast(self.constant_limbs.items[data..][0..Constant.Integer.limbs]);
13779 const bigint: std.math.big.int.Const = .{
13780 .limbs = self.constant_limbs
13781 .items[data + Constant.Integer.limbs ..][0..extra.limbs_len],
13782 .positive = switch (tag) {
13783 .positive_integer => true,
13784 .negative_integer => false,
13785 else => unreachable,
13786 },
13787 };
13788 const bit_count = extra.type.scalarBits(self);
13789 const val: i64 = if (bit_count <= 64)
13790 bigint.toInt(i64) catch unreachable
13791 else if (bigint.toInt(u64)) |val|
13792 @bitCast(val)
13793 else |_| {
13794 const limbs = try record.addManyAsSlice(
13795 self.gpa,
13796 std.math.divCeil(u24, bit_count, 64) catch unreachable,
13797 );
13798 bigint.writeTwosComplement(std.mem.sliceAsBytes(limbs), .little);
13799 for (limbs) |*limb| {
13800 const val = std.mem.littleToNative(i64, @bitCast(limb.*));
13801 limb.* = @bitCast(if (val >= 0)
13802 val << 1 | 0
13803 else
13804 -%val << 1 | 1);
13805 }
13806 try constants_block.writeUnabbrev(5, record.items);
13807 continue;
13808 };
13809 try constants_block.writeAbbrev(Constants.Integer{
13810 .value = @bitCast(if (val >= 0)
13811 val << 1 | 0
13812 else
13813 -%val << 1 | 1),
13814 });
13815 },
13816 .half,
13817 .bfloat,
13818 => try constants_block.writeAbbrev(Constants.Half{ .value = @truncate(data) }),
13819 .float => try constants_block.writeAbbrev(Constants.Float{ .value = data }),
13820 .double => {
13821 const extra = self.constantExtraData(Constant.Double, data);
13822 try constants_block.writeAbbrev(Constants.Double{
13823 .value = (@as(u64, extra.hi) << 32) | extra.lo,
13824 });
13825 },
13826 .x86_fp80 => {
13827 const extra = self.constantExtraData(Constant.Fp80, data);
13828 try constants_block.writeAbbrev(Constants.Fp80{
13829 .hi = @as(u64, extra.hi) << 48 | @as(u64, extra.lo_hi) << 16 |
13830 extra.lo_lo >> 16,
13831 .lo = @truncate(extra.lo_lo),
13832 });
13833 },
13834 .fp128,
13835 .ppc_fp128,
13836 => {
13837 const extra = self.constantExtraData(Constant.Fp128, data);
13838 try constants_block.writeAbbrev(Constants.Fp128{
13839 .lo = @as(u64, extra.lo_hi) << 32 | @as(u64, extra.lo_lo),
13840 .hi = @as(u64, extra.hi_hi) << 32 | @as(u64, extra.hi_lo),
13841 });
13842 },
13843 .array,
13844 .vector,
13845 .structure,
13846 .packed_structure,
13847 => {
13848 var extra = self.constantExtraDataTrail(Constant.Aggregate, data);
13849 const len: u32 = @intCast(extra.data.type.aggregateLen(self));
13850 const values = extra.trail.next(len, Constant, self);
13851
13852 try constants_block.writeAbbrevAdapted(
13853 Constants.Aggregate{ .values = values },
13854 constant_adapter,
13855 );
13856 },
13857 .splat => {
13858 const ConstantsWriter = @TypeOf(constants_block);
13859 const extra = self.constantExtraData(Constant.Splat, data);
13860 const vector_len = extra.type.vectorLen(self);
13861 const c = constant_adapter.getConstantIndex(extra.value);
13862
13863 try bitcode.writeBits(
13864 ConstantsWriter.abbrevId(Constants.Aggregate),
13865 ConstantsWriter.abbrev_len,
13866 );
13867 try bitcode.writeVBR(vector_len, 6);
13868 for (0..vector_len) |_| {
13869 try bitcode.writeBits(c, Constants.Aggregate.ops[1].array_fixed);
13870 }
13871 },
13872 .string => {
13873 const str: String = @enumFromInt(data);
13874 if (str == .none) {
13875 try constants_block.writeAbbrev(Constants.Null{});
13876 } else {
13877 const slice = str.slice(self).?;
13878 if (slice.len > 0 and slice[slice.len - 1] == 0)
13879 try constants_block.writeAbbrev(Constants.CString{ .string = slice[0 .. slice.len - 1] })
13880 else
13881 try constants_block.writeAbbrev(Constants.String{ .string = slice });
13882 }
13883 },
13884 .bitcast,
13885 .inttoptr,
13886 .ptrtoint,
13887 .addrspacecast,
13888 .trunc,
13889 => |tag| {
13890 const extra = self.constantExtraData(Constant.Cast, data);
13891 try constants_block.writeAbbrevAdapted(Constants.Cast{
13892 .type_index = extra.type,
13893 .val = extra.val,
13894 .opcode = tag.toCastOpcode(),
13895 }, constant_adapter);
13896 },
13897 .add,
13898 .@"add nsw",
13899 .@"add nuw",
13900 .sub,
13901 .@"sub nsw",
13902 .@"sub nuw",
13903 .shl,
13904 .xor,
13905 => |tag| {
13906 const extra = self.constantExtraData(Constant.Binary, data);
13907 try constants_block.writeAbbrevAdapted(Constants.Binary{
13908 .opcode = tag.toBinaryOpcode(),
13909 .lhs = extra.lhs,
13910 .rhs = extra.rhs,
13911 }, constant_adapter);
13912 },
13913 .getelementptr,
13914 .@"getelementptr inbounds",
13915 => |tag| {
13916 var extra = self.constantExtraDataTrail(Constant.GetElementPtr, data);
13917 const indices = extra.trail.next(extra.data.info.indices_len, Constant, self);
13918 try record.ensureUnusedCapacity(self.gpa, 1 + 2 + 2 * indices.len);
13919
13920 record.appendAssumeCapacity(@intFromEnum(extra.data.type));
13921
13922 record.appendAssumeCapacity(@intFromEnum(extra.data.base.typeOf(self)));
13923 record.appendAssumeCapacity(constant_adapter.getConstantIndex(extra.data.base));
13924
13925 for (indices) |i| {
13926 record.appendAssumeCapacity(@intFromEnum(i.typeOf(self)));
13927 record.appendAssumeCapacity(constant_adapter.getConstantIndex(i));
13928 }
13929
13930 try constants_block.writeUnabbrev(switch (tag) {
13931 .getelementptr => 12,
13932 .@"getelementptr inbounds" => 20,
13933 else => unreachable,
13934 }, record.items);
13935 },
13936 .@"asm",
13937 .@"asm sideeffect",
13938 .@"asm alignstack",
13939 .@"asm sideeffect alignstack",
13940 .@"asm inteldialect",
13941 .@"asm sideeffect inteldialect",
13942 .@"asm alignstack inteldialect",
13943 .@"asm sideeffect alignstack inteldialect",
13944 .@"asm unwind",
13945 .@"asm sideeffect unwind",
13946 .@"asm alignstack unwind",
13947 .@"asm sideeffect alignstack unwind",
13948 .@"asm inteldialect unwind",
13949 .@"asm sideeffect inteldialect unwind",
13950 .@"asm alignstack inteldialect unwind",
13951 .@"asm sideeffect alignstack inteldialect unwind",
13952 => |tag| {
13953 const extra = self.constantExtraData(Constant.Assembly, data);
13954
13955 const assembly_slice = extra.assembly.slice(self).?;
13956 const constraints_slice = extra.constraints.slice(self).?;
13957
13958 try record.ensureUnusedCapacity(self.gpa, 4 + assembly_slice.len + constraints_slice.len);
13959
13960 record.appendAssumeCapacity(@intFromEnum(extra.type));
13961 record.appendAssumeCapacity(switch (tag) {
13962 .@"asm" => 0,
13963 .@"asm sideeffect" => 0b0001,
13964 .@"asm sideeffect alignstack" => 0b0011,
13965 .@"asm sideeffect inteldialect" => 0b0101,
13966 .@"asm sideeffect alignstack inteldialect" => 0b0111,
13967 .@"asm sideeffect unwind" => 0b1001,
13968 .@"asm sideeffect alignstack unwind" => 0b1011,
13969 .@"asm sideeffect inteldialect unwind" => 0b1101,
13970 .@"asm sideeffect alignstack inteldialect unwind" => 0b1111,
13971 .@"asm alignstack" => 0b0010,
13972 .@"asm inteldialect" => 0b0100,
13973 .@"asm alignstack inteldialect" => 0b0110,
13974 .@"asm unwind" => 0b1000,
13975 .@"asm alignstack unwind" => 0b1010,
13976 .@"asm inteldialect unwind" => 0b1100,
13977 .@"asm alignstack inteldialect unwind" => 0b1110,
13978 else => unreachable,
13979 });
13980
13981 record.appendAssumeCapacity(assembly_slice.len);
13982 for (assembly_slice) |c| record.appendAssumeCapacity(c);
13983
13984 record.appendAssumeCapacity(constraints_slice.len);
13985 for (constraints_slice) |c| record.appendAssumeCapacity(c);
13986
13987 try constants_block.writeUnabbrev(30, record.items);
13988 },
13989 .blockaddress => {
13990 const extra = self.constantExtraData(Constant.BlockAddress, data);
13991 try constants_block.writeAbbrev(Constants.BlockAddress{
13992 .type_id = extra.function.typeOf(self),
13993 .function = constant_adapter.getConstantIndex(extra.function.toConst(self)),
13994 .block = @intFromEnum(extra.block),
13995 });
13996 },
13997 .dso_local_equivalent,
13998 .no_cfi,
13999 => |tag| {
14000 const function: Function.Index = @enumFromInt(data);
14001 try constants_block.writeAbbrev(Constants.DsoLocalEquivalentOrNoCfi{
14002 .code = switch (tag) {
14003 .dso_local_equivalent => 27,
14004 .no_cfi => 29,
14005 else => unreachable,
14006 },
14007 .type_id = function.typeOf(self),
14008 .function = constant_adapter.getConstantIndex(function.toConst(self)),
14009 });
14010 },
14011 }
14012 }
14013
14014 try constants_block.end();
14015 }
14016
14017 // METADATA_KIND_BLOCK
14018 {
14019 const MetadataKindBlock = ir.MetadataKindBlock;
14020 var metadata_kind_block = try module_block.enterSubBlock(MetadataKindBlock, true);
14021
14022 inline for (@typeInfo(ir.FixedMetadataKind).@"enum".fields) |field| {
14023 // don't include `dbg` in stripped functions
14024 if (!(self.strip and std.mem.eql(u8, field.name, "dbg"))) {
14025 try metadata_kind_block.writeAbbrev(MetadataKindBlock.Kind{
14026 .id = field.value,
14027 .name = field.name,
14028 });
14029 }
14030 }
14031
14032 try metadata_kind_block.end();
14033 }
14034
14035 const MetadataAdapter = struct {
14036 builder: *const Builder,
14037 constant_adapter: ConstantAdapter,
14038
14039 pub fn init(
14040 builder: *const Builder,
14041 const_adapter: ConstantAdapter,
14042 ) @This() {
14043 return .{
14044 .builder = builder,
14045 .constant_adapter = const_adapter,
14046 };
14047 }
14048
14049 pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) {
14050 _ = field_name;
14051 const Ty = @TypeOf(value);
14052 return switch (Ty) {
14053 Metadata => @enumFromInt(adapter.getMetadataIndex(value)),
14054 MetadataString => @enumFromInt(adapter.getMetadataStringIndex(value)),
14055 Constant => @enumFromInt(adapter.constant_adapter.getConstantIndex(value)),
14056 else => value,
14057 };
14058 }
14059
14060 pub fn getMetadataIndex(adapter: @This(), metadata: Metadata) u32 {
14061 if (metadata == .none) return 0;
14062 return @intCast(adapter.builder.metadata_string_map.count() +
14063 @intFromEnum(metadata.unwrap(adapter.builder)) - 1);
14064 }
14065
14066 pub fn getMetadataStringIndex(_: @This(), metadata_string: MetadataString) u32 {
14067 return @intFromEnum(metadata_string);
14068 }
14069 };
14070
14071 const metadata_adapter = MetadataAdapter.init(self, constant_adapter);
14072
14073 // METADATA_BLOCK
14074 {
14075 const MetadataBlock = ir.MetadataBlock;
14076 var metadata_block = try module_block.enterSubBlock(MetadataBlock, true);
14077
14078 const MetadataBlockWriter = @TypeOf(metadata_block);
14079
14080 // Emit all MetadataStrings
14081 if (self.metadata_string_map.count() > 1) {
14082 const strings_offset, const strings_size = blk: {
14083 var strings_offset: u32 = 0;
14084 var strings_size: u32 = 0;
14085 for (1..self.metadata_string_map.count()) |metadata_string_index| {
14086 const metadata_string: MetadataString = @enumFromInt(metadata_string_index);
14087 const slice = metadata_string.slice(self);
14088 strings_offset += bitcode.bitsVBR(@as(u32, @intCast(slice.len)), 6);
14089 strings_size += @intCast(slice.len * 8);
14090 }
14091 break :blk .{
14092 std.mem.alignForward(u32, strings_offset, 32) / 8,
14093 std.mem.alignForward(u32, strings_size, 32) / 8,
14094 };
14095 };
14096
14097 try bitcode.writeBits(
14098 comptime MetadataBlockWriter.abbrevId(MetadataBlock.Strings),
14099 MetadataBlockWriter.abbrev_len,
14100 );
14101
14102 try bitcode.writeVBR(@as(u32, @intCast(self.metadata_string_map.count() - 1)), 6);
14103 try bitcode.writeVBR(strings_offset, 6);
14104
14105 try bitcode.writeVBR(strings_size + strings_offset, 6);
14106
14107 try bitcode.alignTo32();
14108
14109 for (1..self.metadata_string_map.count()) |metadata_string_index| {
14110 const metadata_string: MetadataString = @enumFromInt(metadata_string_index);
14111 const slice = metadata_string.slice(self);
14112 try bitcode.writeVBR(@as(u32, @intCast(slice.len)), 6);
14113 }
14114
14115 try bitcode.writeBlob(self.metadata_string_bytes.items);
14116 }
14117
14118 for (
14119 self.metadata_items.items(.tag)[1..],
14120 self.metadata_items.items(.data)[1..],
14121 ) |tag, data| {
14122 record.clearRetainingCapacity();
14123 switch (tag) {
14124 .none => unreachable,
14125 .file => {
14126 const extra = self.metadataExtraData(Metadata.File, data);
14127
14128 try metadata_block.writeAbbrevAdapted(MetadataBlock.File{
14129 .filename = extra.filename,
14130 .directory = extra.directory,
14131 }, metadata_adapter);
14132 },
14133 .compile_unit,
14134 .@"compile_unit optimized",
14135 => |kind| {
14136 const extra = self.metadataExtraData(Metadata.CompileUnit, data);
14137 try metadata_block.writeAbbrevAdapted(MetadataBlock.CompileUnit{
14138 .file = extra.file,
14139 .producer = extra.producer,
14140 .is_optimized = switch (kind) {
14141 .compile_unit => false,
14142 .@"compile_unit optimized" => true,
14143 else => unreachable,
14144 },
14145 .enums = extra.enums,
14146 .globals = extra.globals,
14147 }, metadata_adapter);
14148 },
14149 .subprogram,
14150 .@"subprogram local",
14151 .@"subprogram definition",
14152 .@"subprogram local definition",
14153 .@"subprogram optimized",
14154 .@"subprogram optimized local",
14155 .@"subprogram optimized definition",
14156 .@"subprogram optimized local definition",
14157 => |kind| {
14158 const extra = self.metadataExtraData(Metadata.Subprogram, data);
14159
14160 try metadata_block.writeAbbrevAdapted(MetadataBlock.Subprogram{
14161 .scope = extra.file,
14162 .name = extra.name,
14163 .linkage_name = extra.linkage_name,
14164 .file = extra.file,
14165 .line = extra.line,
14166 .ty = extra.ty,
14167 .scope_line = extra.scope_line,
14168 .sp_flags = @bitCast(@as(u32, @as(u3, @intCast(
14169 @intFromEnum(kind) - @intFromEnum(Metadata.Tag.subprogram),
14170 ))) << 2),
14171 .flags = extra.di_flags,
14172 .compile_unit = extra.compile_unit,
14173 }, metadata_adapter);
14174 },
14175 .lexical_block => {
14176 const extra = self.metadataExtraData(Metadata.LexicalBlock, data);
14177 try metadata_block.writeAbbrevAdapted(MetadataBlock.LexicalBlock{
14178 .scope = extra.scope,
14179 .file = extra.file,
14180 .line = extra.line,
14181 .column = extra.column,
14182 }, metadata_adapter);
14183 },
14184 .location => {
14185 const extra = self.metadataExtraData(Metadata.Location, data);
14186 assert(extra.scope != .none);
14187 try metadata_block.writeAbbrev(MetadataBlock.Location{
14188 .line = extra.line,
14189 .column = extra.column,
14190 .scope = metadata_adapter.getMetadataIndex(extra.scope) - 1,
14191 .inlined_at = @enumFromInt(metadata_adapter.getMetadataIndex(extra.inlined_at)),
14192 });
14193 },
14194 .basic_bool_type,
14195 .basic_unsigned_type,
14196 .basic_signed_type,
14197 .basic_float_type,
14198 => |kind| {
14199 const extra = self.metadataExtraData(Metadata.BasicType, data);
14200 try metadata_block.writeAbbrevAdapted(MetadataBlock.BasicType{
14201 .name = extra.name,
14202 .size_in_bits = extra.bitSize(),
14203 .encoding = switch (kind) {
14204 .basic_bool_type => DW.ATE.boolean,
14205 .basic_unsigned_type => DW.ATE.unsigned,
14206 .basic_signed_type => DW.ATE.signed,
14207 .basic_float_type => DW.ATE.float,
14208 else => unreachable,
14209 },
14210 }, metadata_adapter);
14211 },
14212 .composite_struct_type,
14213 .composite_union_type,
14214 .composite_enumeration_type,
14215 .composite_array_type,
14216 .composite_vector_type,
14217 => |kind| {
14218 const extra = self.metadataExtraData(Metadata.CompositeType, data);
14219
14220 try metadata_block.writeAbbrevAdapted(MetadataBlock.CompositeType{
14221 .tag = switch (kind) {
14222 .composite_struct_type => DW.TAG.structure_type,
14223 .composite_union_type => DW.TAG.union_type,
14224 .composite_enumeration_type => DW.TAG.enumeration_type,
14225 .composite_array_type, .composite_vector_type => DW.TAG.array_type,
14226 else => unreachable,
14227 },
14228 .name = extra.name,
14229 .file = extra.file,
14230 .line = extra.line,
14231 .scope = extra.scope,
14232 .underlying_type = extra.underlying_type,
14233 .size_in_bits = extra.bitSize(),
14234 .align_in_bits = extra.bitAlign(),
14235 .flags = if (kind == .composite_vector_type) .{ .Vector = true } else .{},
14236 .elements = extra.fields_tuple,
14237 }, metadata_adapter);
14238 },
14239 .derived_pointer_type,
14240 .derived_member_type,
14241 => |kind| {
14242 const extra = self.metadataExtraData(Metadata.DerivedType, data);
14243 try metadata_block.writeAbbrevAdapted(MetadataBlock.DerivedType{
14244 .tag = switch (kind) {
14245 .derived_pointer_type => DW.TAG.pointer_type,
14246 .derived_member_type => DW.TAG.member,
14247 else => unreachable,
14248 },
14249 .name = extra.name,
14250 .file = extra.file,
14251 .line = extra.line,
14252 .scope = extra.scope,
14253 .underlying_type = extra.underlying_type,
14254 .size_in_bits = extra.bitSize(),
14255 .align_in_bits = extra.bitAlign(),
14256 .offset_in_bits = extra.bitOffset(),
14257 }, metadata_adapter);
14258 },
14259 .subroutine_type => {
14260 const extra = self.metadataExtraData(Metadata.SubroutineType, data);
14261
14262 try metadata_block.writeAbbrevAdapted(MetadataBlock.SubroutineType{
14263 .types = extra.types_tuple,
14264 }, metadata_adapter);
14265 },
14266 .enumerator_unsigned,
14267 .enumerator_signed_positive,
14268 .enumerator_signed_negative,
14269 => |kind| {
14270 const extra = self.metadataExtraData(Metadata.Enumerator, data);
14271 const bigint: std.math.big.int.Const = .{
14272 .limbs = self.metadata_limbs.items[extra.limbs_index..][0..extra.limbs_len],
14273 .positive = switch (kind) {
14274 .enumerator_unsigned,
14275 .enumerator_signed_positive,
14276 => true,
14277 .enumerator_signed_negative => false,
14278 else => unreachable,
14279 },
14280 };
14281 const flags: MetadataBlock.Enumerator.Flags = .{
14282 .unsigned = switch (kind) {
14283 .enumerator_unsigned => true,
14284 .enumerator_signed_positive,
14285 .enumerator_signed_negative,
14286 => false,
14287 else => unreachable,
14288 },
14289 };
14290 const val: i64 = if (bigint.toInt(i64)) |val|
14291 val
14292 else |_| if (bigint.toInt(u64)) |val|
14293 @bitCast(val)
14294 else |_| {
14295 const limbs_len = std.math.divCeil(u32, extra.bit_width, 64) catch unreachable;
14296 try record.ensureTotalCapacity(self.gpa, 3 + limbs_len);
14297 record.appendAssumeCapacity(@as(
14298 @typeInfo(MetadataBlock.Enumerator.Flags).@"struct".backing_integer.?,
14299 @bitCast(flags),
14300 ));
14301 record.appendAssumeCapacity(extra.bit_width);
14302 record.appendAssumeCapacity(metadata_adapter.getMetadataStringIndex(extra.name));
14303 const limbs = record.addManyAsSliceAssumeCapacity(limbs_len);
14304 bigint.writeTwosComplement(std.mem.sliceAsBytes(limbs), .little);
14305 for (limbs) |*limb| {
14306 const val = std.mem.littleToNative(i64, @bitCast(limb.*));
14307 limb.* = @bitCast(if (val >= 0)
14308 val << 1 | 0
14309 else
14310 -%val << 1 | 1);
14311 }
14312 try metadata_block.writeUnabbrev(@intFromEnum(MetadataBlock.Enumerator.id), record.items);
14313 continue;
14314 };
14315 try metadata_block.writeAbbrevAdapted(MetadataBlock.Enumerator{
14316 .flags = flags,
14317 .bit_width = extra.bit_width,
14318 .name = extra.name,
14319 .value = @bitCast(if (val >= 0)
14320 val << 1 | 0
14321 else
14322 -%val << 1 | 1),
14323 }, metadata_adapter);
14324 },
14325 .subrange => {
14326 const extra = self.metadataExtraData(Metadata.Subrange, data);
14327
14328 try metadata_block.writeAbbrevAdapted(MetadataBlock.Subrange{
14329 .count = extra.count,
14330 .lower_bound = extra.lower_bound,
14331 }, metadata_adapter);
14332 },
14333 .expression => {
14334 var extra = self.metadataExtraDataTrail(Metadata.Expression, data);
14335
14336 const elements = extra.trail.next(extra.data.elements_len, u32, self);
14337
14338 try metadata_block.writeAbbrevAdapted(MetadataBlock.Expression{
14339 .elements = elements,
14340 }, metadata_adapter);
14341 },
14342 .tuple => {
14343 var extra = self.metadataExtraDataTrail(Metadata.Tuple, data);
14344
14345 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
14346
14347 try metadata_block.writeAbbrevAdapted(MetadataBlock.Node{
14348 .elements = elements,
14349 }, metadata_adapter);
14350 },
14351 .str_tuple => {
14352 var extra = self.metadataExtraDataTrail(Metadata.StrTuple, data);
14353
14354 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
14355
14356 const all_elems = try self.gpa.alloc(Metadata, elements.len + 1);
14357 defer self.gpa.free(all_elems);
14358 all_elems[0] = @enumFromInt(metadata_adapter.getMetadataStringIndex(extra.data.str));
14359 for (elements, all_elems[1..]) |elem, *out_elem| {
14360 out_elem.* = @enumFromInt(metadata_adapter.getMetadataIndex(elem));
14361 }
14362
14363 try metadata_block.writeAbbrev(MetadataBlock.Node{
14364 .elements = all_elems,
14365 });
14366 },
14367 .module_flag => {
14368 const extra = self.metadataExtraData(Metadata.ModuleFlag, data);
14369 try metadata_block.writeAbbrev(MetadataBlock.Node{
14370 .elements = &.{
14371 @enumFromInt(metadata_adapter.getMetadataIndex(extra.behavior)),
14372 @enumFromInt(metadata_adapter.getMetadataStringIndex(extra.name)),
14373 @enumFromInt(metadata_adapter.getMetadataIndex(extra.constant)),
14374 },
14375 });
14376 },
14377 .local_var => {
14378 const extra = self.metadataExtraData(Metadata.LocalVar, data);
14379 try metadata_block.writeAbbrevAdapted(MetadataBlock.LocalVar{
14380 .scope = extra.scope,
14381 .name = extra.name,
14382 .file = extra.file,
14383 .line = extra.line,
14384 .ty = extra.ty,
14385 }, metadata_adapter);
14386 },
14387 .parameter => {
14388 const extra = self.metadataExtraData(Metadata.Parameter, data);
14389 try metadata_block.writeAbbrevAdapted(MetadataBlock.Parameter{
14390 .scope = extra.scope,
14391 .name = extra.name,
14392 .file = extra.file,
14393 .line = extra.line,
14394 .ty = extra.ty,
14395 .arg = extra.arg_no,
14396 }, metadata_adapter);
14397 },
14398 .global_var,
14399 .@"global_var local",
14400 => |kind| {
14401 const extra = self.metadataExtraData(Metadata.GlobalVar, data);
14402 try metadata_block.writeAbbrevAdapted(MetadataBlock.GlobalVar{
14403 .scope = extra.scope,
14404 .name = extra.name,
14405 .linkage_name = extra.linkage_name,
14406 .file = extra.file,
14407 .line = extra.line,
14408 .ty = extra.ty,
14409 .local = kind == .@"global_var local",
14410 }, metadata_adapter);
14411 },
14412 .global_var_expression => {
14413 const extra = self.metadataExtraData(Metadata.GlobalVarExpression, data);
14414 try metadata_block.writeAbbrevAdapted(MetadataBlock.GlobalVarExpression{
14415 .variable = extra.variable,
14416 .expression = extra.expression,
14417 }, metadata_adapter);
14418 },
14419 .constant => {
14420 const constant: Constant = @enumFromInt(data);
14421 try metadata_block.writeAbbrevAdapted(MetadataBlock.Constant{
14422 .ty = constant.typeOf(self),
14423 .constant = constant,
14424 }, metadata_adapter);
14425 },
14426 }
14427 }
14428
14429 // Write named metadata
14430 for (self.metadata_named.keys(), self.metadata_named.values()) |name, operands| {
14431 const slice = name.slice(self);
14432 try metadata_block.writeAbbrev(MetadataBlock.Name{
14433 .name = slice,
14434 });
14435
14436 const elements = self.metadata_extra.items[operands.index..][0..operands.len];
14437 for (elements) |*e| {
14438 e.* = metadata_adapter.getMetadataIndex(@enumFromInt(e.*)) - 1;
14439 }
14440
14441 try metadata_block.writeAbbrev(MetadataBlock.NamedNode{
14442 .elements = @ptrCast(elements),
14443 });
14444 }
14445
14446 // Write global attached metadata
14447 {
14448 for (globals.keys()) |global| {
14449 const global_ptr = global.ptrConst(self);
14450 if (global_ptr.dbg == .none) continue;
14451
14452 switch (global_ptr.kind) {
14453 .function => |f| if (f.ptrConst(self).instructions.len != 0) continue,
14454 else => {},
14455 }
14456
14457 try metadata_block.writeAbbrev(MetadataBlock.GlobalDeclAttachment{
14458 .value = @enumFromInt(constant_adapter.getConstantIndex(global.toConst())),
14459 .kind = .dbg,
14460 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(global_ptr.dbg) - 1),
14461 });
14462 }
14463 }
14464
14465 try metadata_block.end();
14466 }
14467
14468 // OPERAND_BUNDLE_TAGS_BLOCK
14469 {
14470 const OperandBundleTags = ir.OperandBundleTags;
14471 var operand_bundle_tags_block = try module_block.enterSubBlock(OperandBundleTags, true);
14472
14473 try operand_bundle_tags_block.writeAbbrev(OperandBundleTags.OperandBundleTag{
14474 .tag = "cold",
14475 });
14476
14477 try operand_bundle_tags_block.end();
14478 }
14479
14480 // Block info
14481 {
14482 const BlockInfo = ir.BlockInfo;
14483 var block_info_block = try module_block.enterSubBlock(BlockInfo, true);
14484
14485 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.FunctionBlock.id});
14486 inline for (ir.FunctionBlock.abbrevs) |abbrev| {
14487 try block_info_block.defineAbbrev(&abbrev.ops);
14488 }
14489
14490 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.FunctionValueSymbolTable.id});
14491 inline for (ir.FunctionValueSymbolTable.abbrevs) |abbrev| {
14492 try block_info_block.defineAbbrev(&abbrev.ops);
14493 }
14494
14495 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.FunctionMetadataBlock.id});
14496 inline for (ir.FunctionMetadataBlock.abbrevs) |abbrev| {
14497 try block_info_block.defineAbbrev(&abbrev.ops);
14498 }
14499
14500 try block_info_block.writeUnabbrev(BlockInfo.set_block_id, &.{ir.MetadataAttachmentBlock.id});
14501 inline for (ir.MetadataAttachmentBlock.abbrevs) |abbrev| {
14502 try block_info_block.defineAbbrev(&abbrev.ops);
14503 }
14504
14505 try block_info_block.end();
14506 }
14507
14508 // FUNCTION_BLOCKS
14509 {
14510 const FunctionAdapter = struct {
14511 constant_adapter: ConstantAdapter,
14512 metadata_adapter: MetadataAdapter,
14513 func: *const Function,
14514 instruction_index: Function.Instruction.Index,
14515
14516 pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) {
14517 _ = field_name;
14518 const Ty = @TypeOf(value);
14519 return switch (Ty) {
14520 Value => @enumFromInt(adapter.getOffsetValueIndex(value)),
14521 Constant => @enumFromInt(adapter.getOffsetConstantIndex(value)),
14522 FunctionAttributes => @enumFromInt(switch (value) {
14523 .none => 0,
14524 else => 1 + adapter.constant_adapter.builder.function_attributes_set.getIndex(value).?,
14525 }),
14526 else => value,
14527 };
14528 }
14529
14530 pub fn getValueIndex(adapter: @This(), value: Value) u32 {
14531 return @intCast(switch (value.unwrap()) {
14532 .instruction => |instruction| instruction.valueIndex(adapter.func) + adapter.firstInstr(),
14533 .constant => |constant| adapter.constant_adapter.getConstantIndex(constant),
14534 .metadata => |metadata| {
14535 const real_metadata = metadata.unwrap(adapter.metadata_adapter.builder);
14536 if (@intFromEnum(real_metadata) < Metadata.first_local_metadata)
14537 return adapter.metadata_adapter.getMetadataIndex(real_metadata) - 1;
14538
14539 return @intCast(@intFromEnum(metadata) -
14540 Metadata.first_local_metadata +
14541 adapter.metadata_adapter.builder.metadata_string_map.count() - 1 +
14542 adapter.metadata_adapter.builder.metadata_map.count() - 1);
14543 },
14544 });
14545 }
14546
14547 pub fn getOffsetValueIndex(adapter: @This(), value: Value) u32 {
14548 return adapter.offset() -% adapter.getValueIndex(value);
14549 }
14550
14551 pub fn getOffsetValueSignedIndex(adapter: @This(), value: Value) i32 {
14552 const signed_offset: i32 = @intCast(adapter.offset());
14553 const signed_value: i32 = @intCast(adapter.getValueIndex(value));
14554 return signed_offset - signed_value;
14555 }
14556
14557 pub fn getOffsetConstantIndex(adapter: @This(), constant: Constant) u32 {
14558 return adapter.offset() - adapter.constant_adapter.getConstantIndex(constant);
14559 }
14560
14561 pub fn offset(adapter: @This()) u32 {
14562 return adapter.instruction_index.valueIndex(adapter.func) + adapter.firstInstr();
14563 }
14564
14565 fn firstInstr(adapter: @This()) u32 {
14566 return adapter.constant_adapter.numConstants();
14567 }
14568 };
14569
14570 for (self.functions.items, 0..) |func, func_index| {
14571 const FunctionBlock = ir.FunctionBlock;
14572 if (func.global.getReplacement(self) != .none) continue;
14573
14574 if (func.instructions.len == 0) continue;
14575
14576 var function_block = try module_block.enterSubBlock(FunctionBlock, false);
14577
14578 try function_block.writeAbbrev(FunctionBlock.DeclareBlocks{ .num_blocks = func.blocks.len });
14579
14580 var adapter: FunctionAdapter = .{
14581 .constant_adapter = constant_adapter,
14582 .metadata_adapter = metadata_adapter,
14583 .func = &func,
14584 .instruction_index = @enumFromInt(0),
14585 };
14586
14587 // Emit function level metadata block
14588 if (!func.strip and func.debug_values.len > 0) {
14589 const MetadataBlock = ir.FunctionMetadataBlock;
14590 var metadata_block = try function_block.enterSubBlock(MetadataBlock, false);
14591
14592 for (func.debug_values) |value| {
14593 try metadata_block.writeAbbrev(MetadataBlock.Value{
14594 .ty = value.typeOf(@enumFromInt(func_index), self),
14595 .value = @enumFromInt(adapter.getValueIndex(value.toValue())),
14596 });
14597 }
14598
14599 try metadata_block.end();
14600 }
14601
14602 const tags = func.instructions.items(.tag);
14603 const datas = func.instructions.items(.data);
14604
14605 var has_location = false;
14606
14607 var block_incoming_len: u32 = undefined;
14608 for (tags, datas, 0..) |tag, data, instr_index| {
14609 adapter.instruction_index = @enumFromInt(instr_index);
14610 record.clearRetainingCapacity();
14611
14612 switch (tag) {
14613 .arg => continue,
14614 .block => {
14615 block_incoming_len = data;
14616 continue;
14617 },
14618 .@"unreachable" => try function_block.writeAbbrev(FunctionBlock.Unreachable{}),
14619 .call,
14620 .@"musttail call",
14621 .@"notail call",
14622 .@"tail call",
14623 => |kind| {
14624 var extra = func.extraDataTrail(Function.Instruction.Call, data);
14625
14626 if (extra.data.info.has_op_bundle_cold) {
14627 try function_block.writeAbbrev(FunctionBlock.ColdOperandBundle{});
14628 }
14629
14630 const call_conv = extra.data.info.call_conv;
14631 const args = extra.trail.next(extra.data.args_len, Value, &func);
14632 try function_block.writeAbbrevAdapted(FunctionBlock.Call{
14633 .attributes = extra.data.attributes,
14634 .call_type = switch (kind) {
14635 .call => .{ .call_conv = call_conv },
14636 .@"tail call" => .{ .tail = true, .call_conv = call_conv },
14637 .@"musttail call" => .{ .must_tail = true, .call_conv = call_conv },
14638 .@"notail call" => .{ .no_tail = true, .call_conv = call_conv },
14639 else => unreachable,
14640 },
14641 .type_id = extra.data.ty,
14642 .callee = extra.data.callee,
14643 .args = args,
14644 }, adapter);
14645 },
14646 .@"call fast",
14647 .@"musttail call fast",
14648 .@"notail call fast",
14649 .@"tail call fast",
14650 => |kind| {
14651 var extra = func.extraDataTrail(Function.Instruction.Call, data);
14652
14653 if (extra.data.info.has_op_bundle_cold) {
14654 try function_block.writeAbbrev(FunctionBlock.ColdOperandBundle{});
14655 }
14656
14657 const call_conv = extra.data.info.call_conv;
14658 const args = extra.trail.next(extra.data.args_len, Value, &func);
14659 try function_block.writeAbbrevAdapted(FunctionBlock.CallFast{
14660 .attributes = extra.data.attributes,
14661 .call_type = switch (kind) {
14662 .@"call fast" => .{ .call_conv = call_conv },
14663 .@"tail call fast" => .{ .tail = true, .call_conv = call_conv },
14664 .@"musttail call fast" => .{ .must_tail = true, .call_conv = call_conv },
14665 .@"notail call fast" => .{ .no_tail = true, .call_conv = call_conv },
14666 else => unreachable,
14667 },
14668 .fast_math = FastMath.fast,
14669 .type_id = extra.data.ty,
14670 .callee = extra.data.callee,
14671 .args = args,
14672 }, adapter);
14673 },
14674 .add,
14675 .@"and",
14676 .fadd,
14677 .fdiv,
14678 .fmul,
14679 .mul,
14680 .frem,
14681 .fsub,
14682 .sdiv,
14683 .sub,
14684 .udiv,
14685 .xor,
14686 .shl,
14687 .lshr,
14688 .@"or",
14689 .urem,
14690 .srem,
14691 .ashr,
14692 => |kind| {
14693 const extra = func.extraData(Function.Instruction.Binary, data);
14694 try function_block.writeAbbrev(FunctionBlock.Binary{
14695 .opcode = kind.toBinaryOpcode(),
14696 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14697 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14698 });
14699 },
14700 .@"sdiv exact",
14701 .@"udiv exact",
14702 .@"lshr exact",
14703 .@"ashr exact",
14704 => |kind| {
14705 const extra = func.extraData(Function.Instruction.Binary, data);
14706 try function_block.writeAbbrev(FunctionBlock.BinaryExact{
14707 .opcode = kind.toBinaryOpcode(),
14708 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14709 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14710 });
14711 },
14712 .@"add nsw",
14713 .@"add nuw",
14714 .@"add nuw nsw",
14715 .@"mul nsw",
14716 .@"mul nuw",
14717 .@"mul nuw nsw",
14718 .@"sub nsw",
14719 .@"sub nuw",
14720 .@"sub nuw nsw",
14721 .@"shl nsw",
14722 .@"shl nuw",
14723 .@"shl nuw nsw",
14724 => |kind| {
14725 const extra = func.extraData(Function.Instruction.Binary, data);
14726 try function_block.writeAbbrev(FunctionBlock.BinaryNoWrap{
14727 .opcode = kind.toBinaryOpcode(),
14728 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14729 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14730 .flags = switch (kind) {
14731 .@"add nsw",
14732 .@"mul nsw",
14733 .@"sub nsw",
14734 .@"shl nsw",
14735 => .{ .no_unsigned_wrap = false, .no_signed_wrap = true },
14736 .@"add nuw",
14737 .@"mul nuw",
14738 .@"sub nuw",
14739 .@"shl nuw",
14740 => .{ .no_unsigned_wrap = true, .no_signed_wrap = false },
14741 .@"add nuw nsw",
14742 .@"mul nuw nsw",
14743 .@"sub nuw nsw",
14744 .@"shl nuw nsw",
14745 => .{ .no_unsigned_wrap = true, .no_signed_wrap = true },
14746 else => unreachable,
14747 },
14748 });
14749 },
14750 .@"fadd fast",
14751 .@"fdiv fast",
14752 .@"fmul fast",
14753 .@"frem fast",
14754 .@"fsub fast",
14755 => |kind| {
14756 const extra = func.extraData(Function.Instruction.Binary, data);
14757 try function_block.writeAbbrev(FunctionBlock.BinaryFast{
14758 .opcode = kind.toBinaryOpcode(),
14759 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14760 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14761 .fast_math = FastMath.fast,
14762 });
14763 },
14764 .alloca,
14765 .@"alloca inalloca",
14766 => |kind| {
14767 const extra = func.extraData(Function.Instruction.Alloca, data);
14768 const alignment = extra.info.alignment.toLlvm();
14769 try function_block.writeAbbrev(FunctionBlock.Alloca{
14770 .inst_type = extra.type,
14771 .len_type = extra.len.typeOf(@enumFromInt(func_index), self),
14772 .len_value = adapter.getValueIndex(extra.len),
14773 .flags = .{
14774 .align_lower = @truncate(alignment),
14775 .inalloca = kind == .@"alloca inalloca",
14776 .explicit_type = true,
14777 .swift_error = false,
14778 .align_upper = @truncate(alignment << 5),
14779 },
14780 });
14781 },
14782 .bitcast,
14783 .inttoptr,
14784 .ptrtoint,
14785 .fptosi,
14786 .fptoui,
14787 .sitofp,
14788 .uitofp,
14789 .addrspacecast,
14790 .fptrunc,
14791 .trunc,
14792 .fpext,
14793 .sext,
14794 .zext,
14795 => |kind| {
14796 const extra = func.extraData(Function.Instruction.Cast, data);
14797 try function_block.writeAbbrev(FunctionBlock.Cast{
14798 .val = adapter.getOffsetValueIndex(extra.val),
14799 .type_index = extra.type,
14800 .opcode = kind.toCastOpcode(),
14801 });
14802 },
14803 .@"fcmp false",
14804 .@"fcmp oeq",
14805 .@"fcmp oge",
14806 .@"fcmp ogt",
14807 .@"fcmp ole",
14808 .@"fcmp olt",
14809 .@"fcmp one",
14810 .@"fcmp ord",
14811 .@"fcmp true",
14812 .@"fcmp ueq",
14813 .@"fcmp uge",
14814 .@"fcmp ugt",
14815 .@"fcmp ule",
14816 .@"fcmp ult",
14817 .@"fcmp une",
14818 .@"fcmp uno",
14819 .@"icmp eq",
14820 .@"icmp ne",
14821 .@"icmp sge",
14822 .@"icmp sgt",
14823 .@"icmp sle",
14824 .@"icmp slt",
14825 .@"icmp uge",
14826 .@"icmp ugt",
14827 .@"icmp ule",
14828 .@"icmp ult",
14829 => |kind| {
14830 const extra = func.extraData(Function.Instruction.Binary, data);
14831 try function_block.writeAbbrev(FunctionBlock.Cmp{
14832 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14833 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14834 .pred = kind.toCmpPredicate(),
14835 });
14836 },
14837 .@"fcmp fast false",
14838 .@"fcmp fast oeq",
14839 .@"fcmp fast oge",
14840 .@"fcmp fast ogt",
14841 .@"fcmp fast ole",
14842 .@"fcmp fast olt",
14843 .@"fcmp fast one",
14844 .@"fcmp fast ord",
14845 .@"fcmp fast true",
14846 .@"fcmp fast ueq",
14847 .@"fcmp fast uge",
14848 .@"fcmp fast ugt",
14849 .@"fcmp fast ule",
14850 .@"fcmp fast ult",
14851 .@"fcmp fast une",
14852 .@"fcmp fast uno",
14853 => |kind| {
14854 const extra = func.extraData(Function.Instruction.Binary, data);
14855 try function_block.writeAbbrev(FunctionBlock.CmpFast{
14856 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14857 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14858 .pred = kind.toCmpPredicate(),
14859 .fast_math = FastMath.fast,
14860 });
14861 },
14862 .fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{
14863 .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
14864 }),
14865 .@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{
14866 .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
14867 .fast_math = FastMath.fast,
14868 }),
14869 .extractvalue => {
14870 var extra = func.extraDataTrail(Function.Instruction.ExtractValue, data);
14871 const indices = extra.trail.next(extra.data.indices_len, u32, &func);
14872 try function_block.writeAbbrev(FunctionBlock.ExtractValue{
14873 .val = adapter.getOffsetValueIndex(extra.data.val),
14874 .indices = indices,
14875 });
14876 },
14877 .extractelement => {
14878 const extra = func.extraData(Function.Instruction.ExtractElement, data);
14879 try function_block.writeAbbrev(FunctionBlock.ExtractElement{
14880 .val = adapter.getOffsetValueIndex(extra.val),
14881 .index = adapter.getOffsetValueIndex(extra.index),
14882 });
14883 },
14884 .indirectbr => {
14885 var extra =
14886 func.extraDataTrail(Function.Instruction.IndirectBr, datas[instr_index]);
14887 const targets =
14888 extra.trail.next(extra.data.targets_len, Function.Block.Index, &func);
14889 try function_block.writeAbbrevAdapted(
14890 FunctionBlock.IndirectBr{
14891 .ty = extra.data.addr.typeOf(@enumFromInt(func_index), self),
14892 .addr = extra.data.addr,
14893 .targets = targets,
14894 },
14895 adapter,
14896 );
14897 },
14898 .insertelement => {
14899 const extra = func.extraData(Function.Instruction.InsertElement, data);
14900 try function_block.writeAbbrev(FunctionBlock.InsertElement{
14901 .val = adapter.getOffsetValueIndex(extra.val),
14902 .elem = adapter.getOffsetValueIndex(extra.elem),
14903 .index = adapter.getOffsetValueIndex(extra.index),
14904 });
14905 },
14906 .insertvalue => {
14907 var extra = func.extraDataTrail(Function.Instruction.InsertValue, datas[instr_index]);
14908 const indices = extra.trail.next(extra.data.indices_len, u32, &func);
14909 try function_block.writeAbbrev(FunctionBlock.InsertValue{
14910 .val = adapter.getOffsetValueIndex(extra.data.val),
14911 .elem = adapter.getOffsetValueIndex(extra.data.elem),
14912 .indices = indices,
14913 });
14914 },
14915 .select => {
14916 const extra = func.extraData(Function.Instruction.Select, data);
14917 try function_block.writeAbbrev(FunctionBlock.Select{
14918 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14919 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14920 .cond = adapter.getOffsetValueIndex(extra.cond),
14921 });
14922 },
14923 .@"select fast" => {
14924 const extra = func.extraData(Function.Instruction.Select, data);
14925 try function_block.writeAbbrev(FunctionBlock.SelectFast{
14926 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14927 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14928 .cond = adapter.getOffsetValueIndex(extra.cond),
14929 .fast_math = FastMath.fast,
14930 });
14931 },
14932 .shufflevector => {
14933 const extra = func.extraData(Function.Instruction.ShuffleVector, data);
14934 try function_block.writeAbbrev(FunctionBlock.ShuffleVector{
14935 .lhs = adapter.getOffsetValueIndex(extra.lhs),
14936 .rhs = adapter.getOffsetValueIndex(extra.rhs),
14937 .mask = adapter.getOffsetValueIndex(extra.mask),
14938 });
14939 },
14940 .getelementptr,
14941 .@"getelementptr inbounds",
14942 => |kind| {
14943 var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, data);
14944 const indices = extra.trail.next(extra.data.indices_len, Value, &func);
14945 try function_block.writeAbbrevAdapted(
14946 FunctionBlock.GetElementPtr{
14947 .is_inbounds = kind == .@"getelementptr inbounds",
14948 .type_index = extra.data.type,
14949 .base = extra.data.base,
14950 .indices = indices,
14951 },
14952 adapter,
14953 );
14954 },
14955 .load => {
14956 const extra = func.extraData(Function.Instruction.Load, data);
14957 try function_block.writeAbbrev(FunctionBlock.Load{
14958 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14959 .ty = extra.type,
14960 .alignment = extra.info.alignment.toLlvm(),
14961 .is_volatile = extra.info.access_kind == .@"volatile",
14962 });
14963 },
14964 .@"load atomic" => {
14965 const extra = func.extraData(Function.Instruction.Load, data);
14966 try function_block.writeAbbrev(FunctionBlock.LoadAtomic{
14967 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14968 .ty = extra.type,
14969 .alignment = extra.info.alignment.toLlvm(),
14970 .is_volatile = extra.info.access_kind == .@"volatile",
14971 .success_ordering = extra.info.success_ordering,
14972 .sync_scope = extra.info.sync_scope,
14973 });
14974 },
14975 .store => {
14976 const extra = func.extraData(Function.Instruction.Store, data);
14977 try function_block.writeAbbrev(FunctionBlock.Store{
14978 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14979 .val = adapter.getOffsetValueIndex(extra.val),
14980 .alignment = extra.info.alignment.toLlvm(),
14981 .is_volatile = extra.info.access_kind == .@"volatile",
14982 });
14983 },
14984 .@"store atomic" => {
14985 const extra = func.extraData(Function.Instruction.Store, data);
14986 try function_block.writeAbbrev(FunctionBlock.StoreAtomic{
14987 .ptr = adapter.getOffsetValueIndex(extra.ptr),
14988 .val = adapter.getOffsetValueIndex(extra.val),
14989 .alignment = extra.info.alignment.toLlvm(),
14990 .is_volatile = extra.info.access_kind == .@"volatile",
14991 .success_ordering = extra.info.success_ordering,
14992 .sync_scope = extra.info.sync_scope,
14993 });
14994 },
14995 .br => {
14996 try function_block.writeAbbrev(FunctionBlock.BrUnconditional{
14997 .block = data,
14998 });
14999 },
15000 .br_cond => {
15001 const extra = func.extraData(Function.Instruction.BrCond, data);
15002 try function_block.writeAbbrev(FunctionBlock.BrConditional{
15003 .then_block = @intFromEnum(extra.then),
15004 .else_block = @intFromEnum(extra.@"else"),
15005 .condition = adapter.getOffsetValueIndex(extra.cond),
15006 });
15007 },
15008 .@"switch" => {
15009 var extra = func.extraDataTrail(Function.Instruction.Switch, data);
15010
15011 try record.ensureUnusedCapacity(self.gpa, 3 + extra.data.cases_len * 2);
15012
15013 // Conditional type
15014 record.appendAssumeCapacity(@intFromEnum(extra.data.val.typeOf(@enumFromInt(func_index), self)));
15015
15016 // Conditional
15017 record.appendAssumeCapacity(adapter.getOffsetValueIndex(extra.data.val));
15018
15019 // Default block
15020 record.appendAssumeCapacity(@intFromEnum(extra.data.default));
15021
15022 const vals = extra.trail.next(extra.data.cases_len, Constant, &func);
15023 const blocks = extra.trail.next(extra.data.cases_len, Function.Block.Index, &func);
15024 for (vals, blocks) |val, block| {
15025 record.appendAssumeCapacity(adapter.constant_adapter.getConstantIndex(val));
15026 record.appendAssumeCapacity(@intFromEnum(block));
15027 }
15028
15029 try function_block.writeUnabbrev(12, record.items);
15030 },
15031 .va_arg => {
15032 const extra = func.extraData(Function.Instruction.VaArg, data);
15033 try function_block.writeAbbrev(FunctionBlock.VaArg{
15034 .list_type = extra.list.typeOf(@enumFromInt(func_index), self),
15035 .list = adapter.getOffsetValueIndex(extra.list),
15036 .type = extra.type,
15037 });
15038 },
15039 .phi,
15040 .@"phi fast",
15041 => |kind| {
15042 var extra = func.extraDataTrail(Function.Instruction.Phi, data);
15043 const vals = extra.trail.next(block_incoming_len, Value, &func);
15044 const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &func);
15045
15046 try record.ensureUnusedCapacity(
15047 self.gpa,
15048 1 + block_incoming_len * 2 + @intFromBool(kind == .@"phi fast"),
15049 );
15050
15051 record.appendAssumeCapacity(@intFromEnum(extra.data.type));
15052
15053 for (vals, blocks) |val, block| {
15054 const offset_value = adapter.getOffsetValueSignedIndex(val);
15055 const abs_value: u32 = @intCast(@abs(offset_value));
15056 const signed_vbr = if (offset_value > 0) abs_value << 1 else ((abs_value << 1) | 1);
15057 record.appendAssumeCapacity(signed_vbr);
15058 record.appendAssumeCapacity(@intFromEnum(block));
15059 }
15060
15061 if (kind == .@"phi fast") record.appendAssumeCapacity(@as(u8, @bitCast(FastMath{})));
15062
15063 try function_block.writeUnabbrev(16, record.items);
15064 },
15065 .ret => try function_block.writeAbbrev(FunctionBlock.Ret{
15066 .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
15067 }),
15068 .@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}),
15069 .atomicrmw => {
15070 const extra = func.extraData(Function.Instruction.AtomicRmw, data);
15071 try function_block.writeAbbrev(FunctionBlock.AtomicRmw{
15072 .ptr = adapter.getOffsetValueIndex(extra.ptr),
15073 .val = adapter.getOffsetValueIndex(extra.val),
15074 .operation = extra.info.atomic_rmw_operation,
15075 .is_volatile = extra.info.access_kind == .@"volatile",
15076 .success_ordering = extra.info.success_ordering,
15077 .sync_scope = extra.info.sync_scope,
15078 .alignment = extra.info.alignment.toLlvm(),
15079 });
15080 },
15081 .cmpxchg,
15082 .@"cmpxchg weak",
15083 => |kind| {
15084 const extra = func.extraData(Function.Instruction.CmpXchg, data);
15085
15086 try function_block.writeAbbrev(FunctionBlock.CmpXchg{
15087 .ptr = adapter.getOffsetValueIndex(extra.ptr),
15088 .cmp = adapter.getOffsetValueIndex(extra.cmp),
15089 .new = adapter.getOffsetValueIndex(extra.new),
15090 .is_volatile = extra.info.access_kind == .@"volatile",
15091 .success_ordering = extra.info.success_ordering,
15092 .sync_scope = extra.info.sync_scope,
15093 .failure_ordering = extra.info.failure_ordering,
15094 .is_weak = kind == .@"cmpxchg weak",
15095 .alignment = extra.info.alignment.toLlvm(),
15096 });
15097 },
15098 .fence => {
15099 const info: MemoryAccessInfo = @bitCast(data);
15100 try function_block.writeAbbrev(FunctionBlock.Fence{
15101 .ordering = info.success_ordering,
15102 .sync_scope = info.sync_scope,
15103 });
15104 },
15105 }
15106
15107 if (!func.strip) {
15108 if (func.debug_locations.get(adapter.instruction_index)) |debug_location| {
15109 switch (debug_location) {
15110 .no_location => has_location = false,
15111 .location => |location| {
15112 try function_block.writeAbbrev(FunctionBlock.DebugLoc{
15113 .line = location.line,
15114 .column = location.column,
15115 .scope = @enumFromInt(metadata_adapter.getMetadataIndex(location.scope)),
15116 .inlined_at = @enumFromInt(metadata_adapter.getMetadataIndex(location.inlined_at)),
15117 });
15118 has_location = true;
15119 },
15120 }
15121 } else if (has_location) {
15122 try function_block.writeAbbrev(FunctionBlock.DebugLocAgain{});
15123 }
15124 }
15125 }
15126
15127 // VALUE_SYMTAB
15128 if (!func.strip) {
15129 const ValueSymbolTable = ir.FunctionValueSymbolTable;
15130
15131 var value_symtab_block = try function_block.enterSubBlock(ValueSymbolTable, false);
15132
15133 for (func.blocks, 0..) |block, block_index| {
15134 const name = block.instruction.name(&func);
15135
15136 if (name == .none or name == .empty) continue;
15137
15138 try value_symtab_block.writeAbbrev(ValueSymbolTable.BlockEntry{
15139 .value_id = @intCast(block_index),
15140 .string = name.slice(self).?,
15141 });
15142 }
15143
15144 // TODO: Emit non block entries if the builder ever starts assigning names to non blocks
15145
15146 try value_symtab_block.end();
15147 }
15148
15149 // METADATA_ATTACHMENT_BLOCK
15150 {
15151 const MetadataAttachmentBlock = ir.MetadataAttachmentBlock;
15152 var metadata_attach_block = try function_block.enterSubBlock(MetadataAttachmentBlock, false);
15153
15154 dbg: {
15155 if (func.strip) break :dbg;
15156 const dbg = func.global.ptrConst(self).dbg;
15157 if (dbg == .none) break :dbg;
15158 try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentGlobalSingle{
15159 .kind = .dbg,
15160 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(dbg) - 1),
15161 });
15162 }
15163
15164 var instr_index: u32 = 0;
15165 for (func.instructions.items(.tag), func.instructions.items(.data)) |instr_tag, data| switch (instr_tag) {
15166 .arg, .block => {}, // not an actual instruction
15167 else => {
15168 instr_index += 1;
15169 },
15170 .br_cond, .@"switch" => {
15171 const weights = switch (instr_tag) {
15172 .br_cond => func.extraData(Function.Instruction.BrCond, data).weights,
15173 .@"switch" => func.extraData(Function.Instruction.Switch, data).weights,
15174 else => unreachable,
15175 };
15176 switch (weights) {
15177 .none => {},
15178 .unpredictable => try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentInstructionSingle{
15179 .inst = instr_index,
15180 .kind = .unpredictable,
15181 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(.empty_tuple) - 1),
15182 }),
15183 _ => try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentInstructionSingle{
15184 .inst = instr_index,
15185 .kind = .prof,
15186 .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(@enumFromInt(@intFromEnum(weights))) - 1),
15187 }),
15188 }
15189 instr_index += 1;
15190 },
15191 };
15192
15193 try metadata_attach_block.end();
15194 }
15195
15196 try function_block.end();
15197 }
15198 }
15199
15200 try module_block.end();
15201 }
15202
15203 // STRTAB_BLOCK
15204 {
15205 const Strtab = ir.Strtab;
15206 var strtab_block = try bitcode.enterTopBlock(Strtab);
15207
15208 try strtab_block.writeAbbrev(Strtab.Blob{ .blob = self.strtab_string_bytes.items });
15209
15210 try strtab_block.end();
15211 }
15212
15213 return bitcode.toOwnedSlice();
15214}
15215
15216const Allocator = std.mem.Allocator;
15217const assert = std.debug.assert;
15218const bitcode_writer = @import("bitcode_writer.zig");
15219const build_options = @import("build_options");
15220const Builder = @This();
15221const builtin = @import("builtin");
15222const DW = std.dwarf;
15223const ir = @import("ir.zig");
15224const log = std.log.scoped(.llvm);
15225const std = @import("std");
src/codegen/llvm/bitcode_writer.zig deleted-433
......@@ -1,433 +0,0 @@
1const std = @import("std");
2
3pub const AbbrevOp = union(enum) {
4 literal: u32, // 0
5 fixed: u16, // 1
6 fixed_runtime: type, // 1
7 vbr: u16, // 2
8 char6: void, // 4
9 blob: void, // 5
10 array_fixed: u16, // 3, 1
11 array_fixed_runtime: type, // 3, 1
12 array_vbr: u16, // 3, 2
13 array_char6: void, // 3, 4
14};
15
16pub const Error = error{OutOfMemory};
17
18pub fn BitcodeWriter(comptime types: []const type) type {
19 return struct {
20 const BcWriter = @This();
21
22 buffer: std.ArrayList(u32),
23 bit_buffer: u32 = 0,
24 bit_count: u5 = 0,
25
26 widths: [types.len]u16,
27
28 pub fn getTypeWidth(self: BcWriter, comptime Type: type) u16 {
29 return self.widths[comptime std.mem.indexOfScalar(type, types, Type).?];
30 }
31
32 pub fn init(allocator: std.mem.Allocator, widths: [types.len]u16) BcWriter {
33 return .{
34 .buffer = std.ArrayList(u32).init(allocator),
35 .widths = widths,
36 };
37 }
38
39 pub fn deinit(self: BcWriter) void {
40 self.buffer.deinit();
41 }
42
43 pub fn toOwnedSlice(self: *BcWriter) Error![]const u32 {
44 std.debug.assert(self.bit_count == 0);
45 return self.buffer.toOwnedSlice();
46 }
47
48 pub fn length(self: BcWriter) usize {
49 std.debug.assert(self.bit_count == 0);
50 return self.buffer.items.len;
51 }
52
53 pub fn writeBits(self: *BcWriter, value: anytype, bits: u16) Error!void {
54 if (bits == 0) return;
55
56 var in_buffer = bufValue(value, 32);
57 var in_bits = bits;
58
59 // Store input bits in buffer if they fit otherwise store as many as possible and flush
60 if (self.bit_count > 0) {
61 const bits_remaining = 31 - self.bit_count + 1;
62 const n: u5 = @intCast(@min(bits_remaining, in_bits));
63 const v = @as(u32, @truncate(in_buffer)) << self.bit_count;
64 self.bit_buffer |= v;
65 in_buffer >>= n;
66
67 self.bit_count +%= n;
68 in_bits -= n;
69
70 if (self.bit_count != 0) return;
71 try self.buffer.append(self.bit_buffer);
72 self.bit_buffer = 0;
73 }
74
75 // Write 32-bit chunks of input bits
76 while (in_bits >= 32) {
77 try self.buffer.append(@truncate(in_buffer));
78
79 in_buffer >>= 31;
80 in_buffer >>= 1;
81 in_bits -= 32;
82 }
83
84 // Store remaining input bits in buffer
85 if (in_bits > 0) {
86 self.bit_count = @intCast(in_bits);
87 self.bit_buffer = @truncate(in_buffer);
88 }
89 }
90
91 pub fn writeVBR(self: *BcWriter, value: anytype, comptime vbr_bits: usize) Error!void {
92 comptime {
93 std.debug.assert(vbr_bits > 1);
94 if (@bitSizeOf(@TypeOf(value)) > 64) @compileError("Unsupported VBR block type: " ++ @typeName(@TypeOf(value)));
95 }
96
97 var in_buffer = bufValue(value, vbr_bits);
98
99 const continue_bit = @as(@TypeOf(in_buffer), 1) << @intCast(vbr_bits - 1);
100 const mask = continue_bit - 1;
101
102 // If input is larger than one VBR block can store
103 // then store vbr_bits - 1 bits and a continue bit
104 while (in_buffer > mask) {
105 try self.writeBits(in_buffer & mask | continue_bit, vbr_bits);
106 in_buffer >>= @intCast(vbr_bits - 1);
107 }
108
109 // Store remaining bits
110 try self.writeBits(in_buffer, vbr_bits);
111 }
112
113 pub fn bitsVBR(_: *const BcWriter, value: anytype, comptime vbr_bits: usize) u16 {
114 comptime {
115 std.debug.assert(vbr_bits > 1);
116 if (@bitSizeOf(@TypeOf(value)) > 64) @compileError("Unsupported VBR block type: " ++ @typeName(@TypeOf(value)));
117 }
118
119 var bits: u16 = 0;
120
121 var in_buffer = bufValue(value, vbr_bits);
122
123 const continue_bit = @as(@TypeOf(in_buffer), 1) << @intCast(vbr_bits - 1);
124 const mask = continue_bit - 1;
125
126 // If input is larger than one VBR block can store
127 // then store vbr_bits - 1 bits and a continue bit
128 while (in_buffer > mask) {
129 bits += @intCast(vbr_bits);
130 in_buffer >>= @intCast(vbr_bits - 1);
131 }
132
133 // Store remaining bits
134 bits += @intCast(vbr_bits);
135 return bits;
136 }
137
138 pub fn write6BitChar(self: *BcWriter, c: u8) Error!void {
139 try self.writeBits(charTo6Bit(c), 6);
140 }
141
142 pub fn writeBlob(self: *BcWriter, blob: []const u8) Error!void {
143 const blob_word_size = std.mem.alignForward(usize, blob.len, 4);
144 try self.buffer.ensureUnusedCapacity(blob_word_size + 1);
145 self.alignTo32() catch unreachable;
146
147 const slice = self.buffer.addManyAsSliceAssumeCapacity(blob_word_size / 4);
148 const slice_bytes = std.mem.sliceAsBytes(slice);
149 @memcpy(slice_bytes[0..blob.len], blob);
150 @memset(slice_bytes[blob.len..], 0);
151 }
152
153 pub fn alignTo32(self: *BcWriter) Error!void {
154 if (self.bit_count == 0) return;
155
156 try self.buffer.append(self.bit_buffer);
157 self.bit_buffer = 0;
158 self.bit_count = 0;
159 }
160
161 pub fn enterTopBlock(self: *BcWriter, comptime SubBlock: type) Error!BlockWriter(SubBlock) {
162 return BlockWriter(SubBlock).init(self, 2, true);
163 }
164
165 fn BlockWriter(comptime Block: type) type {
166 return struct {
167 const Self = @This();
168
169 // The minimum abbrev id length based on the number of abbrevs present in the block
170 pub const abbrev_len = std.math.log2_int_ceil(
171 u6,
172 4 + (if (@hasDecl(Block, "abbrevs")) Block.abbrevs.len else 0),
173 );
174
175 start: usize,
176 bitcode: *BcWriter,
177
178 pub fn init(bitcode: *BcWriter, comptime parent_abbrev_len: u6, comptime define_abbrevs: bool) Error!Self {
179 try bitcode.writeBits(1, parent_abbrev_len);
180 try bitcode.writeVBR(Block.id, 8);
181 try bitcode.writeVBR(abbrev_len, 4);
182 try bitcode.alignTo32();
183
184 // We store the index of the block size and store a dummy value as the number of words in the block
185 const start = bitcode.length();
186 try bitcode.writeBits(0, 32);
187
188 var self = Self{
189 .start = start,
190 .bitcode = bitcode,
191 };
192
193 // Predefine all block abbrevs
194 if (define_abbrevs) {
195 inline for (Block.abbrevs) |Abbrev| {
196 try self.defineAbbrev(&Abbrev.ops);
197 }
198 }
199
200 return self;
201 }
202
203 pub fn enterSubBlock(self: Self, comptime SubBlock: type, comptime define_abbrevs: bool) Error!BlockWriter(SubBlock) {
204 return BlockWriter(SubBlock).init(self.bitcode, abbrev_len, define_abbrevs);
205 }
206
207 pub fn end(self: *Self) Error!void {
208 try self.bitcode.writeBits(0, abbrev_len);
209 try self.bitcode.alignTo32();
210
211 // Set the number of words in the block at the start of the block
212 self.bitcode.buffer.items[self.start] = @truncate(self.bitcode.length() - self.start - 1);
213 }
214
215 pub fn writeUnabbrev(self: *Self, code: u32, values: []const u64) Error!void {
216 try self.bitcode.writeBits(3, abbrev_len);
217 try self.bitcode.writeVBR(code, 6);
218 try self.bitcode.writeVBR(values.len, 6);
219 for (values) |val| {
220 try self.bitcode.writeVBR(val, 6);
221 }
222 }
223
224 pub fn writeAbbrev(self: *Self, params: anytype) Error!void {
225 return self.writeAbbrevAdapted(params, struct {
226 pub fn get(_: @This(), param: anytype, comptime _: []const u8) @TypeOf(param) {
227 return param;
228 }
229 }{});
230 }
231
232 pub fn abbrevId(comptime Abbrev: type) u32 {
233 inline for (Block.abbrevs, 0..) |abbrev, i| {
234 if (Abbrev == abbrev) return i + 4;
235 }
236
237 @compileError("Unknown abbrev: " ++ @typeName(Abbrev));
238 }
239
240 pub fn writeAbbrevAdapted(
241 self: *Self,
242 params: anytype,
243 adapter: anytype,
244 ) Error!void {
245 const Abbrev = @TypeOf(params);
246
247 try self.bitcode.writeBits(comptime abbrevId(Abbrev), abbrev_len);
248
249 const fields = std.meta.fields(Abbrev);
250
251 // This abbreviation might only contain literals
252 if (fields.len == 0) return;
253
254 comptime var field_index: usize = 0;
255 inline for (Abbrev.ops) |ty| {
256 const field_name = fields[field_index].name;
257 const param = @field(params, field_name);
258
259 switch (ty) {
260 .literal => continue,
261 .fixed => |len| try self.bitcode.writeBits(adapter.get(param, field_name), len),
262 .fixed_runtime => |width_ty| try self.bitcode.writeBits(
263 adapter.get(param, field_name),
264 self.bitcode.getTypeWidth(width_ty),
265 ),
266 .vbr => |len| try self.bitcode.writeVBR(adapter.get(param, field_name), len),
267 .char6 => try self.bitcode.write6BitChar(adapter.get(param, field_name)),
268 .blob => {
269 try self.bitcode.writeVBR(param.len, 6);
270 try self.bitcode.writeBlob(param);
271 },
272 .array_fixed => |len| {
273 try self.bitcode.writeVBR(param.len, 6);
274 for (param) |x| {
275 try self.bitcode.writeBits(adapter.get(x, field_name), len);
276 }
277 },
278 .array_fixed_runtime => |width_ty| {
279 try self.bitcode.writeVBR(param.len, 6);
280 for (param) |x| {
281 try self.bitcode.writeBits(
282 adapter.get(x, field_name),
283 self.bitcode.getTypeWidth(width_ty),
284 );
285 }
286 },
287 .array_vbr => |len| {
288 try self.bitcode.writeVBR(param.len, 6);
289 for (param) |x| {
290 try self.bitcode.writeVBR(adapter.get(x, field_name), len);
291 }
292 },
293 .array_char6 => {
294 try self.bitcode.writeVBR(param.len, 6);
295 for (param) |x| {
296 try self.bitcode.write6BitChar(adapter.get(x, field_name));
297 }
298 },
299 }
300 field_index += 1;
301 if (field_index == fields.len) break;
302 }
303 }
304
305 pub fn defineAbbrev(self: *Self, comptime ops: []const AbbrevOp) Error!void {
306 const bitcode = self.bitcode;
307 try bitcode.writeBits(2, abbrev_len);
308
309 // ops.len is not accurate because arrays are actually two ops
310 try bitcode.writeVBR(blk: {
311 var count: usize = 0;
312 inline for (ops) |op| {
313 count += switch (op) {
314 .literal, .fixed, .fixed_runtime, .vbr, .char6, .blob => 1,
315 .array_fixed, .array_fixed_runtime, .array_vbr, .array_char6 => 2,
316 };
317 }
318 break :blk count;
319 }, 5);
320
321 inline for (ops) |op| {
322 switch (op) {
323 .literal => |value| {
324 try bitcode.writeBits(1, 1);
325 try bitcode.writeVBR(value, 8);
326 },
327 .fixed => |width| {
328 try bitcode.writeBits(0, 1);
329 try bitcode.writeBits(1, 3);
330 try bitcode.writeVBR(width, 5);
331 },
332 .fixed_runtime => |width_ty| {
333 try bitcode.writeBits(0, 1);
334 try bitcode.writeBits(1, 3);
335 try bitcode.writeVBR(bitcode.getTypeWidth(width_ty), 5);
336 },
337 .vbr => |width| {
338 try bitcode.writeBits(0, 1);
339 try bitcode.writeBits(2, 3);
340 try bitcode.writeVBR(width, 5);
341 },
342 .char6 => {
343 try bitcode.writeBits(0, 1);
344 try bitcode.writeBits(4, 3);
345 },
346 .blob => {
347 try bitcode.writeBits(0, 1);
348 try bitcode.writeBits(5, 3);
349 },
350 .array_fixed => |width| {
351 // Array op
352 try bitcode.writeBits(0, 1);
353 try bitcode.writeBits(3, 3);
354
355 // Fixed or VBR op
356 try bitcode.writeBits(0, 1);
357 try bitcode.writeBits(1, 3);
358 try bitcode.writeVBR(width, 5);
359 },
360 .array_fixed_runtime => |width_ty| {
361 // Array op
362 try bitcode.writeBits(0, 1);
363 try bitcode.writeBits(3, 3);
364
365 // Fixed or VBR op
366 try bitcode.writeBits(0, 1);
367 try bitcode.writeBits(1, 3);
368 try bitcode.writeVBR(bitcode.getTypeWidth(width_ty), 5);
369 },
370 .array_vbr => |width| {
371 // Array op
372 try bitcode.writeBits(0, 1);
373 try bitcode.writeBits(3, 3);
374
375 // Fixed or VBR op
376 try bitcode.writeBits(0, 1);
377 try bitcode.writeBits(2, 3);
378 try bitcode.writeVBR(width, 5);
379 },
380 .array_char6 => {
381 // Array op
382 try bitcode.writeBits(0, 1);
383 try bitcode.writeBits(3, 3);
384
385 // Char6 op
386 try bitcode.writeBits(0, 1);
387 try bitcode.writeBits(4, 3);
388 },
389 }
390 }
391 }
392 };
393 }
394 };
395}
396
397fn charTo6Bit(c: u8) u8 {
398 return switch (c) {
399 'a'...'z' => c - 'a',
400 'A'...'Z' => c - 'A' + 26,
401 '0'...'9' => c - '0' + 52,
402 '.' => 62,
403 '_' => 63,
404 else => @panic("Failed to encode byte as 6-bit char"),
405 };
406}
407
408fn BufType(comptime T: type, comptime min_len: usize) type {
409 return std.meta.Int(.unsigned, @max(min_len, @bitSizeOf(switch (@typeInfo(T)) {
410 .comptime_int => u32,
411 .int => |info| if (info.signedness == .unsigned)
412 T
413 else
414 @compileError("Unsupported type: " ++ @typeName(T)),
415 .@"enum" => |info| info.tag_type,
416 .bool => u1,
417 .@"struct" => |info| switch (info.layout) {
418 .auto, .@"extern" => @compileError("Unsupported type: " ++ @typeName(T)),
419 .@"packed" => std.meta.Int(.unsigned, @bitSizeOf(T)),
420 },
421 else => @compileError("Unsupported type: " ++ @typeName(T)),
422 })));
423}
424
425fn bufValue(value: anytype, comptime min_len: usize) BufType(@TypeOf(value), min_len) {
426 return switch (@typeInfo(@TypeOf(value))) {
427 .comptime_int, .int => @intCast(value),
428 .@"enum" => @intFromEnum(value),
429 .bool => @intFromBool(value),
430 .@"struct" => @intCast(@as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(value))), @bitCast(value))),
431 else => unreachable,
432 };
433}
src/codegen/llvm/ir.zig deleted-1862
......@@ -1,1862 +0,0 @@
1const std = @import("std");
2const Builder = @import("Builder.zig");
3const bitcode_writer = @import("bitcode_writer.zig");
4
5const AbbrevOp = bitcode_writer.AbbrevOp;
6
7pub const MAGIC: u32 = 0xdec04342;
8
9const ValueAbbrev = AbbrevOp{ .vbr = 6 };
10const ValueArrayAbbrev = AbbrevOp{ .array_vbr = 6 };
11
12const ConstantAbbrev = AbbrevOp{ .vbr = 6 };
13const ConstantArrayAbbrev = AbbrevOp{ .array_vbr = 6 };
14
15const MetadataAbbrev = AbbrevOp{ .vbr = 16 };
16const MetadataArrayAbbrev = AbbrevOp{ .array_vbr = 16 };
17
18const LineAbbrev = AbbrevOp{ .vbr = 8 };
19const ColumnAbbrev = AbbrevOp{ .vbr = 8 };
20
21const BlockAbbrev = AbbrevOp{ .vbr = 6 };
22const BlockArrayAbbrev = AbbrevOp{ .array_vbr = 6 };
23
24/// Unused tags are commented out so that they are omitted in the generated
25/// bitcode, which scans over this enum using reflection.
26pub const FixedMetadataKind = enum(u8) {
27 dbg = 0,
28 //tbaa = 1,
29 prof = 2,
30 //fpmath = 3,
31 //range = 4,
32 //@"tbaa.struct" = 5,
33 //@"invariant.load" = 6,
34 //@"alias.scope" = 7,
35 //@"noalias" = 8,
36 //nontemporal = 9,
37 //@"llvm.mem.parallel_loop_access" = 10,
38 //nonnull = 11,
39 //dereferenceable = 12,
40 //dereferenceable_or_null = 13,
41 //@"make.implicit" = 14,
42 unpredictable = 15,
43 //@"invariant.group" = 16,
44 //@"align" = 17,
45 //@"llvm.loop" = 18,
46 //type = 19,
47 //section_prefix = 20,
48 //absolute_symbol = 21,
49 //associated = 22,
50 //callees = 23,
51 //irr_loop = 24,
52 //@"llvm.access.group" = 25,
53 //callback = 26,
54 //@"llvm.preserve.access.index" = 27,
55 //vcall_visibility = 28,
56 //noundef = 29,
57 //annotation = 30,
58 //nosanitize = 31,
59 //func_sanitize = 32,
60 //exclude = 33,
61 //memprof = 34,
62 //callsite = 35,
63 //kcfi_type = 36,
64 //pcsections = 37,
65 //DIAssignID = 38,
66 //@"coro.outside.frame" = 39,
67};
68
69pub const MetadataCode = enum(u8) {
70 /// MDSTRING: [values]
71 STRING_OLD = 1,
72 /// VALUE: [type num, value num]
73 VALUE = 2,
74 /// NODE: [n x md num]
75 NODE = 3,
76 /// STRING: [values]
77 NAME = 4,
78 /// DISTINCT_NODE: [n x md num]
79 DISTINCT_NODE = 5,
80 /// [n x [id, name]]
81 KIND = 6,
82 /// [distinct, line, col, scope, inlined-at?]
83 LOCATION = 7,
84 /// OLD_NODE: [n x (type num, value num)]
85 OLD_NODE = 8,
86 /// OLD_FN_NODE: [n x (type num, value num)]
87 OLD_FN_NODE = 9,
88 /// NAMED_NODE: [n x mdnodes]
89 NAMED_NODE = 10,
90 /// [m x [value, [n x [id, mdnode]]]
91 ATTACHMENT = 11,
92 /// [distinct, tag, vers, header, n x md num]
93 GENERIC_DEBUG = 12,
94 /// [distinct, count, lo]
95 SUBRANGE = 13,
96 /// [isUnsigned|distinct, value, name]
97 ENUMERATOR = 14,
98 /// [distinct, tag, name, size, align, enc]
99 BASIC_TYPE = 15,
100 /// [distinct, filename, directory, checksumkind, checksum]
101 FILE = 16,
102 /// [distinct, ...]
103 DERIVED_TYPE = 17,
104 /// [distinct, ...]
105 COMPOSITE_TYPE = 18,
106 /// [distinct, flags, types, cc]
107 SUBROUTINE_TYPE = 19,
108 /// [distinct, ...]
109 COMPILE_UNIT = 20,
110 /// [distinct, ...]
111 SUBPROGRAM = 21,
112 /// [distinct, scope, file, line, column]
113 LEXICAL_BLOCK = 22,
114 ///[distinct, scope, file, discriminator]
115 LEXICAL_BLOCK_FILE = 23,
116 /// [distinct, scope, file, name, line, exportSymbols]
117 NAMESPACE = 24,
118 /// [distinct, scope, name, type, ...]
119 TEMPLATE_TYPE = 25,
120 /// [distinct, scope, name, type, value, ...]
121 TEMPLATE_VALUE = 26,
122 /// [distinct, ...]
123 GLOBAL_VAR = 27,
124 /// [distinct, ...]
125 LOCAL_VAR = 28,
126 /// [distinct, n x element]
127 EXPRESSION = 29,
128 /// [distinct, name, file, line, ...]
129 OBJC_PROPERTY = 30,
130 /// [distinct, tag, scope, entity, line, name]
131 IMPORTED_ENTITY = 31,
132 /// [distinct, scope, name, ...]
133 MODULE = 32,
134 /// [distinct, macinfo, line, name, value]
135 MACRO = 33,
136 /// [distinct, macinfo, line, file, ...]
137 MACRO_FILE = 34,
138 /// [count, offset] blob([lengths][chars])
139 STRINGS = 35,
140 /// [valueid, n x [id, mdnode]]
141 GLOBAL_DECL_ATTACHMENT = 36,
142 /// [distinct, var, expr]
143 GLOBAL_VAR_EXPR = 37,
144 /// [offset]
145 INDEX_OFFSET = 38,
146 /// [bitpos]
147 INDEX = 39,
148 /// [distinct, scope, name, file, line]
149 LABEL = 40,
150 /// [distinct, name, size, align,...]
151 STRING_TYPE = 41,
152 /// [distinct, scope, name, variable,...]
153 COMMON_BLOCK = 44,
154 /// [distinct, count, lo, up, stride]
155 GENERIC_SUBRANGE = 45,
156 /// [n x [type num, value num]]
157 ARG_LIST = 46,
158 /// [distinct, ...]
159 ASSIGN_ID = 47,
160};
161
162pub const Identification = struct {
163 pub const id = 13;
164
165 pub const abbrevs = [_]type{
166 Version,
167 Epoch,
168 };
169
170 pub const Version = struct {
171 pub const ops = [_]AbbrevOp{
172 .{ .literal = 1 },
173 .{ .array_fixed = 8 },
174 };
175 string: []const u8,
176 };
177
178 pub const Epoch = struct {
179 pub const ops = [_]AbbrevOp{
180 .{ .literal = 2 },
181 .{ .vbr = 6 },
182 };
183 epoch: u32,
184 };
185};
186
187pub const Module = struct {
188 pub const id = 8;
189
190 pub const abbrevs = [_]type{
191 Version,
192 String,
193 Variable,
194 Function,
195 Alias,
196 };
197
198 pub const Version = struct {
199 pub const ops = [_]AbbrevOp{
200 .{ .literal = 1 },
201 .{ .literal = 2 },
202 };
203 };
204
205 pub const String = struct {
206 pub const ops = [_]AbbrevOp{
207 .{ .vbr = 4 },
208 .{ .array_fixed = 8 },
209 };
210 code: u16,
211 string: []const u8,
212 };
213
214 pub const Variable = struct {
215 const AddrSpaceAndIsConst = packed struct {
216 is_const: bool,
217 one: u1 = 1,
218 addr_space: Builder.AddrSpace,
219 };
220
221 pub const ops = [_]AbbrevOp{
222 .{ .literal = 7 }, // Code
223 .{ .vbr = 16 }, // strtab_offset
224 .{ .vbr = 16 }, // strtab_size
225 .{ .fixed_runtime = Builder.Type },
226 .{ .fixed = @bitSizeOf(AddrSpaceAndIsConst) }, // isconst
227 ConstantAbbrev, // initid
228 .{ .fixed = @bitSizeOf(Builder.Linkage) },
229 .{ .fixed = @bitSizeOf(Builder.Alignment) },
230 .{ .vbr = 16 }, // section
231 .{ .fixed = @bitSizeOf(Builder.Visibility) },
232 .{ .fixed = @bitSizeOf(Builder.ThreadLocal) }, // threadlocal
233 .{ .fixed = @bitSizeOf(Builder.UnnamedAddr) },
234 .{ .fixed = @bitSizeOf(Builder.ExternallyInitialized) },
235 .{ .fixed = @bitSizeOf(Builder.DllStorageClass) },
236 .{ .literal = 0 }, // comdat
237 .{ .literal = 0 }, // attributes
238 .{ .fixed = @bitSizeOf(Builder.Preemption) },
239 };
240 strtab_offset: usize,
241 strtab_size: usize,
242 type_index: Builder.Type,
243 is_const: AddrSpaceAndIsConst,
244 initid: u32,
245 linkage: Builder.Linkage,
246 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
247 section: usize,
248 visibility: Builder.Visibility,
249 thread_local: Builder.ThreadLocal,
250 unnamed_addr: Builder.UnnamedAddr,
251 externally_initialized: Builder.ExternallyInitialized,
252 dllstorageclass: Builder.DllStorageClass,
253 preemption: Builder.Preemption,
254 };
255
256 pub const Function = struct {
257 pub const ops = [_]AbbrevOp{
258 .{ .literal = 8 }, // Code
259 .{ .vbr = 16 }, // strtab_offset
260 .{ .vbr = 16 }, // strtab_size
261 .{ .fixed_runtime = Builder.Type },
262 .{ .fixed = @bitSizeOf(Builder.CallConv) },
263 .{ .fixed = 1 }, // isproto
264 .{ .fixed = @bitSizeOf(Builder.Linkage) },
265 .{ .vbr = 16 }, // paramattr
266 .{ .fixed = @bitSizeOf(Builder.Alignment) },
267 .{ .vbr = 16 }, // section
268 .{ .fixed = @bitSizeOf(Builder.Visibility) },
269 .{ .literal = 0 }, // gc
270 .{ .fixed = @bitSizeOf(Builder.UnnamedAddr) },
271 .{ .literal = 0 }, // prologuedata
272 .{ .fixed = @bitSizeOf(Builder.DllStorageClass) },
273 .{ .literal = 0 }, // comdat
274 .{ .literal = 0 }, // prefixdata
275 .{ .literal = 0 }, // personalityfn
276 .{ .fixed = @bitSizeOf(Builder.Preemption) },
277 .{ .fixed = @bitSizeOf(Builder.AddrSpace) },
278 };
279 strtab_offset: usize,
280 strtab_size: usize,
281 type_index: Builder.Type,
282 call_conv: Builder.CallConv,
283 is_proto: bool,
284 linkage: Builder.Linkage,
285 paramattr: usize,
286 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
287 section: usize,
288 visibility: Builder.Visibility,
289 unnamed_addr: Builder.UnnamedAddr,
290 dllstorageclass: Builder.DllStorageClass,
291 preemption: Builder.Preemption,
292 addr_space: Builder.AddrSpace,
293 };
294
295 pub const Alias = struct {
296 pub const ops = [_]AbbrevOp{
297 .{ .literal = 14 }, // Code
298 .{ .vbr = 16 }, // strtab_offset
299 .{ .vbr = 16 }, // strtab_size
300 .{ .fixed_runtime = Builder.Type },
301 .{ .fixed = @bitSizeOf(Builder.AddrSpace) },
302 ConstantAbbrev, // aliasee val
303 .{ .fixed = @bitSizeOf(Builder.Linkage) },
304 .{ .fixed = @bitSizeOf(Builder.Visibility) },
305 .{ .fixed = @bitSizeOf(Builder.DllStorageClass) },
306 .{ .fixed = @bitSizeOf(Builder.ThreadLocal) },
307 .{ .fixed = @bitSizeOf(Builder.UnnamedAddr) },
308 .{ .fixed = @bitSizeOf(Builder.Preemption) },
309 };
310 strtab_offset: usize,
311 strtab_size: usize,
312 type_index: Builder.Type,
313 addr_space: Builder.AddrSpace,
314 aliasee: u32,
315 linkage: Builder.Linkage,
316 visibility: Builder.Visibility,
317 dllstorageclass: Builder.DllStorageClass,
318 thread_local: Builder.ThreadLocal,
319 unnamed_addr: Builder.UnnamedAddr,
320 preemption: Builder.Preemption,
321 };
322};
323
324pub const BlockInfo = struct {
325 pub const id = 0;
326
327 pub const set_block_id = 1;
328
329 pub const abbrevs = [_]type{};
330};
331
332pub const Type = struct {
333 pub const id = 17;
334
335 pub const abbrevs = [_]type{
336 NumEntry,
337 Simple,
338 Opaque,
339 Integer,
340 StructAnon,
341 StructNamed,
342 StructName,
343 Array,
344 Vector,
345 Pointer,
346 Target,
347 Function,
348 };
349
350 pub const NumEntry = struct {
351 pub const ops = [_]AbbrevOp{
352 .{ .literal = 1 },
353 .{ .fixed = 32 },
354 };
355 num: u32,
356 };
357
358 pub const Simple = struct {
359 pub const ops = [_]AbbrevOp{
360 .{ .vbr = 4 },
361 };
362 code: u5,
363 };
364
365 pub const Opaque = struct {
366 pub const ops = [_]AbbrevOp{
367 .{ .literal = 6 },
368 .{ .literal = 0 },
369 };
370 };
371
372 pub const Integer = struct {
373 pub const ops = [_]AbbrevOp{
374 .{ .literal = 7 },
375 .{ .fixed = 28 },
376 };
377 width: u28,
378 };
379
380 pub const StructAnon = struct {
381 pub const ops = [_]AbbrevOp{
382 .{ .literal = 18 },
383 .{ .fixed = 1 },
384 .{ .array_fixed_runtime = Builder.Type },
385 };
386 is_packed: bool,
387 types: []const Builder.Type,
388 };
389
390 pub const StructNamed = struct {
391 pub const ops = [_]AbbrevOp{
392 .{ .literal = 20 },
393 .{ .fixed = 1 },
394 .{ .array_fixed_runtime = Builder.Type },
395 };
396 is_packed: bool,
397 types: []const Builder.Type,
398 };
399
400 pub const StructName = struct {
401 pub const ops = [_]AbbrevOp{
402 .{ .literal = 19 },
403 .{ .array_fixed = 8 },
404 };
405 string: []const u8,
406 };
407
408 pub const Array = struct {
409 pub const ops = [_]AbbrevOp{
410 .{ .literal = 11 },
411 .{ .vbr = 16 },
412 .{ .fixed_runtime = Builder.Type },
413 };
414 len: u64,
415 child: Builder.Type,
416 };
417
418 pub const Vector = struct {
419 pub const ops = [_]AbbrevOp{
420 .{ .literal = 12 },
421 .{ .vbr = 16 },
422 .{ .fixed_runtime = Builder.Type },
423 };
424 len: u64,
425 child: Builder.Type,
426 };
427
428 pub const Pointer = struct {
429 pub const ops = [_]AbbrevOp{
430 .{ .literal = 25 },
431 .{ .vbr = 4 },
432 };
433 addr_space: Builder.AddrSpace,
434 };
435
436 pub const Target = struct {
437 pub const ops = [_]AbbrevOp{
438 .{ .literal = 26 },
439 .{ .vbr = 4 },
440 .{ .array_fixed_runtime = Builder.Type },
441 .{ .array_fixed = 32 },
442 };
443 num_types: u32,
444 types: []const Builder.Type,
445 ints: []const u32,
446 };
447
448 pub const Function = struct {
449 pub const ops = [_]AbbrevOp{
450 .{ .literal = 21 },
451 .{ .fixed = 1 },
452 .{ .fixed_runtime = Builder.Type },
453 .{ .array_fixed_runtime = Builder.Type },
454 };
455 is_vararg: bool,
456 return_type: Builder.Type,
457 param_types: []const Builder.Type,
458 };
459};
460
461pub const Paramattr = struct {
462 pub const id = 9;
463
464 pub const abbrevs = [_]type{
465 Entry,
466 };
467
468 pub const Entry = struct {
469 pub const ops = [_]AbbrevOp{
470 .{ .literal = 2 },
471 .{ .array_vbr = 8 },
472 };
473 group_indices: []const u64,
474 };
475};
476
477pub const ParamattrGroup = struct {
478 pub const id = 10;
479
480 pub const abbrevs = [_]type{};
481};
482
483pub const Constants = struct {
484 pub const id = 11;
485
486 pub const abbrevs = [_]type{
487 SetType,
488 Null,
489 Undef,
490 Poison,
491 Integer,
492 Half,
493 Float,
494 Double,
495 Fp80,
496 Fp128,
497 Aggregate,
498 String,
499 CString,
500 Cast,
501 Binary,
502 Cmp,
503 ExtractElement,
504 InsertElement,
505 ShuffleVector,
506 ShuffleVectorEx,
507 BlockAddress,
508 DsoLocalEquivalentOrNoCfi,
509 };
510
511 pub const SetType = struct {
512 pub const ops = [_]AbbrevOp{
513 .{ .literal = 1 },
514 .{ .fixed_runtime = Builder.Type },
515 };
516 type_id: Builder.Type,
517 };
518
519 pub const Null = struct {
520 pub const ops = [_]AbbrevOp{
521 .{ .literal = 2 },
522 };
523 };
524
525 pub const Undef = struct {
526 pub const ops = [_]AbbrevOp{
527 .{ .literal = 3 },
528 };
529 };
530
531 pub const Poison = struct {
532 pub const ops = [_]AbbrevOp{
533 .{ .literal = 26 },
534 };
535 };
536
537 pub const Integer = struct {
538 pub const ops = [_]AbbrevOp{
539 .{ .literal = 4 },
540 .{ .vbr = 16 },
541 };
542 value: u64,
543 };
544
545 pub const Half = struct {
546 pub const ops = [_]AbbrevOp{
547 .{ .literal = 6 },
548 .{ .fixed = 16 },
549 };
550 value: u16,
551 };
552
553 pub const Float = struct {
554 pub const ops = [_]AbbrevOp{
555 .{ .literal = 6 },
556 .{ .fixed = 32 },
557 };
558 value: u32,
559 };
560
561 pub const Double = struct {
562 pub const ops = [_]AbbrevOp{
563 .{ .literal = 6 },
564 .{ .vbr = 6 },
565 };
566 value: u64,
567 };
568
569 pub const Fp80 = struct {
570 pub const ops = [_]AbbrevOp{
571 .{ .literal = 6 },
572 .{ .vbr = 6 },
573 .{ .vbr = 6 },
574 };
575 hi: u64,
576 lo: u16,
577 };
578
579 pub const Fp128 = struct {
580 pub const ops = [_]AbbrevOp{
581 .{ .literal = 6 },
582 .{ .vbr = 6 },
583 .{ .vbr = 6 },
584 };
585 lo: u64,
586 hi: u64,
587 };
588
589 pub const Aggregate = struct {
590 pub const ops = [_]AbbrevOp{
591 .{ .literal = 7 },
592 .{ .array_fixed = 32 },
593 };
594 values: []const Builder.Constant,
595 };
596
597 pub const String = struct {
598 pub const ops = [_]AbbrevOp{
599 .{ .literal = 8 },
600 .{ .array_fixed = 8 },
601 };
602 string: []const u8,
603 };
604
605 pub const CString = struct {
606 pub const ops = [_]AbbrevOp{
607 .{ .literal = 9 },
608 .{ .array_fixed = 8 },
609 };
610 string: []const u8,
611 };
612
613 pub const Cast = struct {
614 const CastOpcode = Builder.CastOpcode;
615 pub const ops = [_]AbbrevOp{
616 .{ .literal = 11 },
617 .{ .fixed = @bitSizeOf(CastOpcode) },
618 .{ .fixed_runtime = Builder.Type },
619 ConstantAbbrev,
620 };
621
622 opcode: CastOpcode,
623 type_index: Builder.Type,
624 val: Builder.Constant,
625 };
626
627 pub const Binary = struct {
628 const BinaryOpcode = Builder.BinaryOpcode;
629 pub const ops = [_]AbbrevOp{
630 .{ .literal = 10 },
631 .{ .fixed = @bitSizeOf(BinaryOpcode) },
632 ConstantAbbrev,
633 ConstantAbbrev,
634 };
635
636 opcode: BinaryOpcode,
637 lhs: Builder.Constant,
638 rhs: Builder.Constant,
639 };
640
641 pub const Cmp = struct {
642 pub const ops = [_]AbbrevOp{
643 .{ .literal = 17 },
644 .{ .fixed_runtime = Builder.Type },
645 ConstantAbbrev,
646 ConstantAbbrev,
647 .{ .vbr = 6 },
648 };
649
650 ty: Builder.Type,
651 lhs: Builder.Constant,
652 rhs: Builder.Constant,
653 pred: u32,
654 };
655
656 pub const ExtractElement = struct {
657 pub const ops = [_]AbbrevOp{
658 .{ .literal = 14 },
659 .{ .fixed_runtime = Builder.Type },
660 ConstantAbbrev,
661 .{ .fixed_runtime = Builder.Type },
662 ConstantAbbrev,
663 };
664
665 val_type: Builder.Type,
666 val: Builder.Constant,
667 index_type: Builder.Type,
668 index: Builder.Constant,
669 };
670
671 pub const InsertElement = struct {
672 pub const ops = [_]AbbrevOp{
673 .{ .literal = 15 },
674 ConstantAbbrev,
675 ConstantAbbrev,
676 .{ .fixed_runtime = Builder.Type },
677 ConstantAbbrev,
678 };
679
680 val: Builder.Constant,
681 elem: Builder.Constant,
682 index_type: Builder.Type,
683 index: Builder.Constant,
684 };
685
686 pub const ShuffleVector = struct {
687 pub const ops = [_]AbbrevOp{
688 .{ .literal = 16 },
689 ValueAbbrev,
690 ValueAbbrev,
691 ValueAbbrev,
692 };
693
694 lhs: Builder.Constant,
695 rhs: Builder.Constant,
696 mask: Builder.Constant,
697 };
698
699 pub const ShuffleVectorEx = struct {
700 pub const ops = [_]AbbrevOp{
701 .{ .literal = 19 },
702 .{ .fixed_runtime = Builder.Type },
703 ValueAbbrev,
704 ValueAbbrev,
705 ValueAbbrev,
706 };
707
708 ty: Builder.Type,
709 lhs: Builder.Constant,
710 rhs: Builder.Constant,
711 mask: Builder.Constant,
712 };
713
714 pub const BlockAddress = struct {
715 pub const ops = [_]AbbrevOp{
716 .{ .literal = 21 },
717 .{ .fixed_runtime = Builder.Type },
718 ConstantAbbrev,
719 BlockAbbrev,
720 };
721 type_id: Builder.Type,
722 function: u32,
723 block: u32,
724 };
725
726 pub const DsoLocalEquivalentOrNoCfi = struct {
727 pub const ops = [_]AbbrevOp{
728 .{ .fixed = 5 },
729 .{ .fixed_runtime = Builder.Type },
730 ConstantAbbrev,
731 };
732 code: u5,
733 type_id: Builder.Type,
734 function: u32,
735 };
736};
737
738pub const MetadataKindBlock = struct {
739 pub const id = 22;
740
741 pub const abbrevs = [_]type{
742 Kind,
743 };
744
745 pub const Kind = struct {
746 pub const ops = [_]AbbrevOp{
747 .{ .literal = 6 },
748 .{ .vbr = 4 },
749 .{ .array_fixed = 8 },
750 };
751 id: u32,
752 name: []const u8,
753 };
754};
755
756pub const MetadataAttachmentBlock = struct {
757 pub const id = 16;
758
759 pub const abbrevs = [_]type{
760 AttachmentGlobalSingle,
761 AttachmentInstructionSingle,
762 };
763
764 pub const AttachmentGlobalSingle = struct {
765 pub const ops = [_]AbbrevOp{
766 .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
767 .{ .fixed = 1 },
768 MetadataAbbrev,
769 };
770 kind: FixedMetadataKind,
771 metadata: Builder.Metadata,
772 };
773
774 pub const AttachmentInstructionSingle = struct {
775 pub const ops = [_]AbbrevOp{
776 .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
777 ValueAbbrev,
778 .{ .fixed = 5 },
779 MetadataAbbrev,
780 };
781 inst: u32,
782 kind: FixedMetadataKind,
783 metadata: Builder.Metadata,
784 };
785};
786
787pub const MetadataBlock = struct {
788 pub const id = 15;
789
790 pub const abbrevs = [_]type{
791 Strings,
792 File,
793 CompileUnit,
794 Subprogram,
795 LexicalBlock,
796 Location,
797 BasicType,
798 CompositeType,
799 DerivedType,
800 SubroutineType,
801 Enumerator,
802 Subrange,
803 Expression,
804 Node,
805 LocalVar,
806 Parameter,
807 GlobalVar,
808 GlobalVarExpression,
809 Constant,
810 Name,
811 NamedNode,
812 GlobalDeclAttachment,
813 };
814
815 pub const Strings = struct {
816 pub const ops = [_]AbbrevOp{
817 .{ .literal = @intFromEnum(MetadataCode.STRINGS) },
818 .{ .vbr = 6 },
819 .{ .vbr = 6 },
820 .blob,
821 };
822 num_strings: u32,
823 strings_offset: u32,
824 blob: []const u8,
825 };
826
827 pub const File = struct {
828 pub const ops = [_]AbbrevOp{
829 .{ .literal = @intFromEnum(MetadataCode.FILE) },
830 .{ .literal = 0 }, // is distinct
831 MetadataAbbrev, // filename
832 MetadataAbbrev, // directory
833 .{ .literal = 0 }, // checksum
834 .{ .literal = 0 }, // checksum
835 };
836
837 filename: Builder.MetadataString,
838 directory: Builder.MetadataString,
839 };
840
841 pub const CompileUnit = struct {
842 pub const ops = [_]AbbrevOp{
843 .{ .literal = @intFromEnum(MetadataCode.COMPILE_UNIT) },
844 .{ .literal = 1 }, // is distinct
845 .{ .literal = std.dwarf.LANG.C99 }, // source language
846 MetadataAbbrev, // file
847 MetadataAbbrev, // producer
848 .{ .fixed = 1 }, // isOptimized
849 .{ .literal = 0 }, // raw flags
850 .{ .literal = 0 }, // runtime version
851 .{ .literal = 0 }, // split debug file name
852 .{ .literal = 1 }, // emission kind
853 MetadataAbbrev, // enums
854 .{ .literal = 0 }, // retained types
855 .{ .literal = 0 }, // subprograms
856 MetadataAbbrev, // globals
857 .{ .literal = 0 }, // imported entities
858 .{ .literal = 0 }, // DWO ID
859 .{ .literal = 0 }, // macros
860 .{ .literal = 0 }, // split debug inlining
861 .{ .literal = 0 }, // debug info profiling
862 .{ .literal = 0 }, // name table kind
863 .{ .literal = 0 }, // ranges base address
864 .{ .literal = 0 }, // raw sysroot
865 .{ .literal = 0 }, // raw SDK
866 };
867
868 file: Builder.Metadata,
869 producer: Builder.MetadataString,
870 is_optimized: bool,
871 enums: Builder.Metadata,
872 globals: Builder.Metadata,
873 };
874
875 pub const Subprogram = struct {
876 pub const ops = [_]AbbrevOp{
877 .{ .literal = @intFromEnum(MetadataCode.SUBPROGRAM) },
878 .{ .literal = 0b111 }, // is distinct | has sp flags | has flags
879 MetadataAbbrev, // scope
880 MetadataAbbrev, // name
881 MetadataAbbrev, // linkage name
882 MetadataAbbrev, // file
883 LineAbbrev, // line
884 MetadataAbbrev, // type
885 LineAbbrev, // scope line
886 .{ .literal = 0 }, // containing type
887 .{ .fixed = 32 }, // sp flags
888 .{ .literal = 0 }, // virtual index
889 .{ .fixed = 32 }, // flags
890 MetadataAbbrev, // compile unit
891 .{ .literal = 0 }, // template params
892 .{ .literal = 0 }, // declaration
893 .{ .literal = 0 }, // retained nodes
894 .{ .literal = 0 }, // this adjustment
895 .{ .literal = 0 }, // thrown types
896 .{ .literal = 0 }, // annotations
897 .{ .literal = 0 }, // target function name
898 };
899
900 scope: Builder.Metadata,
901 name: Builder.MetadataString,
902 linkage_name: Builder.MetadataString,
903 file: Builder.Metadata,
904 line: u32,
905 ty: Builder.Metadata,
906 scope_line: u32,
907 sp_flags: Builder.Metadata.Subprogram.DISPFlags,
908 flags: Builder.Metadata.DIFlags,
909 compile_unit: Builder.Metadata,
910 };
911
912 pub const LexicalBlock = struct {
913 pub const ops = [_]AbbrevOp{
914 .{ .literal = @intFromEnum(MetadataCode.LEXICAL_BLOCK) },
915 .{ .literal = 0 }, // is distinct
916 MetadataAbbrev, // scope
917 MetadataAbbrev, // file
918 LineAbbrev, // line
919 ColumnAbbrev, // column
920 };
921
922 scope: Builder.Metadata,
923 file: Builder.Metadata,
924 line: u32,
925 column: u32,
926 };
927
928 pub const Location = struct {
929 pub const ops = [_]AbbrevOp{
930 .{ .literal = @intFromEnum(MetadataCode.LOCATION) },
931 .{ .literal = 0 }, // is distinct
932 LineAbbrev, // line
933 ColumnAbbrev, // column
934 MetadataAbbrev, // scope
935 MetadataAbbrev, // inlined at
936 .{ .literal = 0 }, // is implicit code
937 };
938
939 line: u32,
940 column: u32,
941 scope: u32,
942 inlined_at: Builder.Metadata,
943 };
944
945 pub const BasicType = struct {
946 pub const ops = [_]AbbrevOp{
947 .{ .literal = @intFromEnum(MetadataCode.BASIC_TYPE) },
948 .{ .literal = 0 }, // is distinct
949 .{ .literal = std.dwarf.TAG.base_type }, // tag
950 MetadataAbbrev, // name
951 .{ .vbr = 6 }, // size in bits
952 .{ .literal = 0 }, // align in bits
953 .{ .vbr = 8 }, // encoding
954 .{ .literal = 0 }, // flags
955 };
956
957 name: Builder.MetadataString,
958 size_in_bits: u64,
959 encoding: u32,
960 };
961
962 pub const CompositeType = struct {
963 pub const ops = [_]AbbrevOp{
964 .{ .literal = @intFromEnum(MetadataCode.COMPOSITE_TYPE) },
965 .{ .literal = 0 | 0x2 }, // is distinct | is not used in old type ref
966 .{ .fixed = 32 }, // tag
967 MetadataAbbrev, // name
968 MetadataAbbrev, // file
969 LineAbbrev, // line
970 MetadataAbbrev, // scope
971 MetadataAbbrev, // underlying type
972 .{ .vbr = 6 }, // size in bits
973 .{ .vbr = 6 }, // align in bits
974 .{ .literal = 0 }, // offset in bits
975 .{ .fixed = 32 }, // flags
976 MetadataAbbrev, // elements
977 .{ .literal = 0 }, // runtime lang
978 .{ .literal = 0 }, // vtable holder
979 .{ .literal = 0 }, // template params
980 .{ .literal = 0 }, // raw id
981 .{ .literal = 0 }, // discriminator
982 .{ .literal = 0 }, // data location
983 .{ .literal = 0 }, // associated
984 .{ .literal = 0 }, // allocated
985 .{ .literal = 0 }, // rank
986 .{ .literal = 0 }, // annotations
987 };
988
989 tag: u32,
990 name: Builder.MetadataString,
991 file: Builder.Metadata,
992 line: u32,
993 scope: Builder.Metadata,
994 underlying_type: Builder.Metadata,
995 size_in_bits: u64,
996 align_in_bits: u64,
997 flags: Builder.Metadata.DIFlags,
998 elements: Builder.Metadata,
999 };
1000
1001 pub const DerivedType = struct {
1002 pub const ops = [_]AbbrevOp{
1003 .{ .literal = @intFromEnum(MetadataCode.DERIVED_TYPE) },
1004 .{ .literal = 0 }, // is distinct
1005 .{ .fixed = 32 }, // tag
1006 MetadataAbbrev, // name
1007 MetadataAbbrev, // file
1008 LineAbbrev, // line
1009 MetadataAbbrev, // scope
1010 MetadataAbbrev, // underlying type
1011 .{ .vbr = 6 }, // size in bits
1012 .{ .vbr = 6 }, // align in bits
1013 .{ .vbr = 6 }, // offset in bits
1014 .{ .literal = 0 }, // flags
1015 .{ .literal = 0 }, // extra data
1016 };
1017
1018 tag: u32,
1019 name: Builder.MetadataString,
1020 file: Builder.Metadata,
1021 line: u32,
1022 scope: Builder.Metadata,
1023 underlying_type: Builder.Metadata,
1024 size_in_bits: u64,
1025 align_in_bits: u64,
1026 offset_in_bits: u64,
1027 };
1028
1029 pub const SubroutineType = struct {
1030 pub const ops = [_]AbbrevOp{
1031 .{ .literal = @intFromEnum(MetadataCode.SUBROUTINE_TYPE) },
1032 .{ .literal = 0 | 0x2 }, // is distinct | has no old type refs
1033 .{ .literal = 0 }, // flags
1034 MetadataAbbrev, // types
1035 .{ .literal = 0 }, // cc
1036 };
1037
1038 types: Builder.Metadata,
1039 };
1040
1041 pub const Enumerator = struct {
1042 pub const id: MetadataCode = .ENUMERATOR;
1043
1044 pub const Flags = packed struct(u3) {
1045 distinct: bool = false,
1046 unsigned: bool,
1047 bigint: bool = true,
1048 };
1049
1050 pub const ops = [_]AbbrevOp{
1051 .{ .literal = @intFromEnum(Enumerator.id) },
1052 .{ .fixed = @bitSizeOf(Flags) }, // flags
1053 .{ .vbr = 6 }, // bit width
1054 MetadataAbbrev, // name
1055 .{ .vbr = 16 }, // integer value
1056 };
1057
1058 flags: Flags,
1059 bit_width: u32,
1060 name: Builder.MetadataString,
1061 value: u64,
1062 };
1063
1064 pub const Subrange = struct {
1065 pub const ops = [_]AbbrevOp{
1066 .{ .literal = @intFromEnum(MetadataCode.SUBRANGE) },
1067 .{ .literal = 0b10 }, // is distinct | version
1068 MetadataAbbrev, // count
1069 MetadataAbbrev, // lower bound
1070 .{ .literal = 0 }, // upper bound
1071 .{ .literal = 0 }, // stride
1072 };
1073
1074 count: Builder.Metadata,
1075 lower_bound: Builder.Metadata,
1076 };
1077
1078 pub const Expression = struct {
1079 pub const ops = [_]AbbrevOp{
1080 .{ .literal = @intFromEnum(MetadataCode.EXPRESSION) },
1081 .{ .literal = 0 | (3 << 1) }, // is distinct | version
1082 MetadataArrayAbbrev, // elements
1083 };
1084
1085 elements: []const u32,
1086 };
1087
1088 pub const Node = struct {
1089 pub const ops = [_]AbbrevOp{
1090 .{ .literal = @intFromEnum(MetadataCode.NODE) },
1091 MetadataArrayAbbrev, // elements
1092 };
1093
1094 elements: []const Builder.Metadata,
1095 };
1096
1097 pub const LocalVar = struct {
1098 pub const ops = [_]AbbrevOp{
1099 .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
1100 .{ .literal = 0b10 }, // is distinct | has alignment
1101 MetadataAbbrev, // scope
1102 MetadataAbbrev, // name
1103 MetadataAbbrev, // file
1104 LineAbbrev, // line
1105 MetadataAbbrev, // type
1106 .{ .literal = 0 }, // arg
1107 .{ .literal = 0 }, // flags
1108 .{ .literal = 0 }, // align bits
1109 .{ .literal = 0 }, // annotations
1110 };
1111
1112 scope: Builder.Metadata,
1113 name: Builder.MetadataString,
1114 file: Builder.Metadata,
1115 line: u32,
1116 ty: Builder.Metadata,
1117 };
1118
1119 pub const Parameter = struct {
1120 pub const ops = [_]AbbrevOp{
1121 .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
1122 .{ .literal = 0b10 }, // is distinct | has alignment
1123 MetadataAbbrev, // scope
1124 MetadataAbbrev, // name
1125 MetadataAbbrev, // file
1126 LineAbbrev, // line
1127 MetadataAbbrev, // type
1128 .{ .vbr = 4 }, // arg
1129 .{ .literal = 0 }, // flags
1130 .{ .literal = 0 }, // align bits
1131 .{ .literal = 0 }, // annotations
1132 };
1133
1134 scope: Builder.Metadata,
1135 name: Builder.MetadataString,
1136 file: Builder.Metadata,
1137 line: u32,
1138 ty: Builder.Metadata,
1139 arg: u32,
1140 };
1141
1142 pub const GlobalVar = struct {
1143 pub const ops = [_]AbbrevOp{
1144 .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR) },
1145 .{ .literal = 0b101 }, // is distinct | version
1146 MetadataAbbrev, // scope
1147 MetadataAbbrev, // name
1148 MetadataAbbrev, // linkage name
1149 MetadataAbbrev, // file
1150 LineAbbrev, // line
1151 MetadataAbbrev, // type
1152 .{ .fixed = 1 }, // local
1153 .{ .literal = 1 }, // defined
1154 .{ .literal = 0 }, // static data members declaration
1155 .{ .literal = 0 }, // template params
1156 .{ .literal = 0 }, // align in bits
1157 .{ .literal = 0 }, // annotations
1158 };
1159
1160 scope: Builder.Metadata,
1161 name: Builder.MetadataString,
1162 linkage_name: Builder.MetadataString,
1163 file: Builder.Metadata,
1164 line: u32,
1165 ty: Builder.Metadata,
1166 local: bool,
1167 };
1168
1169 pub const GlobalVarExpression = struct {
1170 pub const ops = [_]AbbrevOp{
1171 .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR_EXPR) },
1172 .{ .literal = 0 }, // is distinct
1173 MetadataAbbrev, // variable
1174 MetadataAbbrev, // expression
1175 };
1176
1177 variable: Builder.Metadata,
1178 expression: Builder.Metadata,
1179 };
1180
1181 pub const Constant = struct {
1182 pub const ops = [_]AbbrevOp{
1183 .{ .literal = @intFromEnum(MetadataCode.VALUE) },
1184 MetadataAbbrev, // type
1185 MetadataAbbrev, // value
1186 };
1187
1188 ty: Builder.Type,
1189 constant: Builder.Constant,
1190 };
1191
1192 pub const Name = struct {
1193 pub const ops = [_]AbbrevOp{
1194 .{ .literal = @intFromEnum(MetadataCode.NAME) },
1195 .{ .array_fixed = 8 }, // name
1196 };
1197
1198 name: []const u8,
1199 };
1200
1201 pub const NamedNode = struct {
1202 pub const ops = [_]AbbrevOp{
1203 .{ .literal = @intFromEnum(MetadataCode.NAMED_NODE) },
1204 MetadataArrayAbbrev, // elements
1205 };
1206
1207 elements: []const Builder.Metadata,
1208 };
1209
1210 pub const GlobalDeclAttachment = struct {
1211 pub const ops = [_]AbbrevOp{
1212 .{ .literal = @intFromEnum(MetadataCode.GLOBAL_DECL_ATTACHMENT) },
1213 ValueAbbrev, // value id
1214 .{ .fixed = 1 }, // kind
1215 MetadataAbbrev, // elements
1216 };
1217
1218 value: Builder.Constant,
1219 kind: FixedMetadataKind,
1220 metadata: Builder.Metadata,
1221 };
1222};
1223
1224pub const OperandBundleTags = struct {
1225 pub const id = 21;
1226
1227 pub const abbrevs = [_]type{OperandBundleTag};
1228
1229 pub const OperandBundleTag = struct {
1230 pub const ops = [_]AbbrevOp{
1231 .{ .literal = 1 },
1232 .array_char6,
1233 };
1234 tag: []const u8,
1235 };
1236};
1237
1238pub const FunctionMetadataBlock = struct {
1239 pub const id = 15;
1240
1241 pub const abbrevs = [_]type{
1242 Value,
1243 };
1244
1245 pub const Value = struct {
1246 pub const ops = [_]AbbrevOp{
1247 .{ .literal = 2 },
1248 .{ .fixed = 32 }, // variable
1249 .{ .fixed = 32 }, // expression
1250 };
1251
1252 ty: Builder.Type,
1253 value: Builder.Value,
1254 };
1255};
1256
1257pub const FunctionBlock = struct {
1258 pub const id = 12;
1259
1260 pub const abbrevs = [_]type{
1261 DeclareBlocks,
1262 Call,
1263 CallFast,
1264 FNeg,
1265 FNegFast,
1266 Binary,
1267 BinaryNoWrap,
1268 BinaryExact,
1269 BinaryFast,
1270 Cmp,
1271 CmpFast,
1272 Select,
1273 SelectFast,
1274 Cast,
1275 Alloca,
1276 GetElementPtr,
1277 ExtractValue,
1278 InsertValue,
1279 ExtractElement,
1280 InsertElement,
1281 ShuffleVector,
1282 RetVoid,
1283 Ret,
1284 Unreachable,
1285 Load,
1286 LoadAtomic,
1287 Store,
1288 StoreAtomic,
1289 BrUnconditional,
1290 BrConditional,
1291 VaArg,
1292 AtomicRmw,
1293 CmpXchg,
1294 Fence,
1295 DebugLoc,
1296 DebugLocAgain,
1297 ColdOperandBundle,
1298 IndirectBr,
1299 };
1300
1301 pub const DeclareBlocks = struct {
1302 pub const ops = [_]AbbrevOp{
1303 .{ .literal = 1 },
1304 .{ .vbr = 8 },
1305 };
1306 num_blocks: usize,
1307 };
1308
1309 pub const Call = struct {
1310 pub const CallType = packed struct(u17) {
1311 tail: bool = false,
1312 call_conv: Builder.CallConv,
1313 reserved: u3 = 0,
1314 must_tail: bool = false,
1315 // We always use the explicit type version as that is what LLVM does
1316 explicit_type: bool = true,
1317 no_tail: bool = false,
1318 };
1319 pub const ops = [_]AbbrevOp{
1320 .{ .literal = 34 },
1321 .{ .fixed_runtime = Builder.FunctionAttributes },
1322 .{ .fixed = @bitSizeOf(CallType) },
1323 .{ .fixed_runtime = Builder.Type },
1324 ValueAbbrev, // Callee
1325 ValueArrayAbbrev, // Args
1326 };
1327
1328 attributes: Builder.FunctionAttributes,
1329 call_type: CallType,
1330 type_id: Builder.Type,
1331 callee: Builder.Value,
1332 args: []const Builder.Value,
1333 };
1334
1335 pub const CallFast = struct {
1336 const CallType = packed struct(u18) {
1337 tail: bool = false,
1338 call_conv: Builder.CallConv,
1339 reserved: u3 = 0,
1340 must_tail: bool = false,
1341 // We always use the explicit type version as that is what LLVM does
1342 explicit_type: bool = true,
1343 no_tail: bool = false,
1344 fast: bool = true,
1345 };
1346
1347 pub const ops = [_]AbbrevOp{
1348 .{ .literal = 34 },
1349 .{ .fixed_runtime = Builder.FunctionAttributes },
1350 .{ .fixed = @bitSizeOf(CallType) },
1351 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1352 .{ .fixed_runtime = Builder.Type },
1353 ValueAbbrev, // Callee
1354 ValueArrayAbbrev, // Args
1355 };
1356
1357 attributes: Builder.FunctionAttributes,
1358 call_type: CallType,
1359 fast_math: Builder.FastMath,
1360 type_id: Builder.Type,
1361 callee: Builder.Value,
1362 args: []const Builder.Value,
1363 };
1364
1365 pub const FNeg = struct {
1366 pub const ops = [_]AbbrevOp{
1367 .{ .literal = 56 },
1368 ValueAbbrev,
1369 .{ .literal = 0 },
1370 };
1371
1372 val: u32,
1373 };
1374
1375 pub const FNegFast = struct {
1376 pub const ops = [_]AbbrevOp{
1377 .{ .literal = 56 },
1378 ValueAbbrev,
1379 .{ .literal = 0 },
1380 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1381 };
1382
1383 val: u32,
1384 fast_math: Builder.FastMath,
1385 };
1386
1387 pub const Binary = struct {
1388 const BinaryOpcode = Builder.BinaryOpcode;
1389 pub const ops = [_]AbbrevOp{
1390 .{ .literal = 2 },
1391 ValueAbbrev,
1392 ValueAbbrev,
1393 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1394 };
1395
1396 lhs: u32,
1397 rhs: u32,
1398 opcode: BinaryOpcode,
1399 };
1400
1401 pub const BinaryNoWrap = struct {
1402 const BinaryOpcode = Builder.BinaryOpcode;
1403 pub const ops = [_]AbbrevOp{
1404 .{ .literal = 2 },
1405 ValueAbbrev,
1406 ValueAbbrev,
1407 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1408 .{ .fixed = 2 },
1409 };
1410
1411 lhs: u32,
1412 rhs: u32,
1413 opcode: BinaryOpcode,
1414 flags: packed struct(u2) {
1415 no_unsigned_wrap: bool,
1416 no_signed_wrap: bool,
1417 },
1418 };
1419
1420 pub const BinaryExact = struct {
1421 const BinaryOpcode = Builder.BinaryOpcode;
1422 pub const ops = [_]AbbrevOp{
1423 .{ .literal = 2 },
1424 ValueAbbrev,
1425 ValueAbbrev,
1426 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1427 .{ .literal = 1 },
1428 };
1429
1430 lhs: u32,
1431 rhs: u32,
1432 opcode: BinaryOpcode,
1433 };
1434
1435 pub const BinaryFast = struct {
1436 const BinaryOpcode = Builder.BinaryOpcode;
1437 pub const ops = [_]AbbrevOp{
1438 .{ .literal = 2 },
1439 ValueAbbrev,
1440 ValueAbbrev,
1441 .{ .fixed = @bitSizeOf(BinaryOpcode) },
1442 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1443 };
1444
1445 lhs: u32,
1446 rhs: u32,
1447 opcode: BinaryOpcode,
1448 fast_math: Builder.FastMath,
1449 };
1450
1451 pub const Cmp = struct {
1452 const CmpPredicate = Builder.CmpPredicate;
1453 pub const ops = [_]AbbrevOp{
1454 .{ .literal = 28 },
1455 ValueAbbrev,
1456 ValueAbbrev,
1457 .{ .fixed = @bitSizeOf(CmpPredicate) },
1458 };
1459
1460 lhs: u32,
1461 rhs: u32,
1462 pred: CmpPredicate,
1463 };
1464
1465 pub const CmpFast = struct {
1466 const CmpPredicate = Builder.CmpPredicate;
1467 pub const ops = [_]AbbrevOp{
1468 .{ .literal = 28 },
1469 ValueAbbrev,
1470 ValueAbbrev,
1471 .{ .fixed = @bitSizeOf(CmpPredicate) },
1472 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1473 };
1474
1475 lhs: u32,
1476 rhs: u32,
1477 pred: CmpPredicate,
1478 fast_math: Builder.FastMath,
1479 };
1480
1481 pub const Select = struct {
1482 pub const ops = [_]AbbrevOp{
1483 .{ .literal = 29 },
1484 ValueAbbrev,
1485 ValueAbbrev,
1486 ValueAbbrev,
1487 };
1488
1489 lhs: u32,
1490 rhs: u32,
1491 cond: u32,
1492 };
1493
1494 pub const SelectFast = struct {
1495 pub const ops = [_]AbbrevOp{
1496 .{ .literal = 29 },
1497 ValueAbbrev,
1498 ValueAbbrev,
1499 ValueAbbrev,
1500 .{ .fixed = @bitSizeOf(Builder.FastMath) },
1501 };
1502
1503 lhs: u32,
1504 rhs: u32,
1505 cond: u32,
1506 fast_math: Builder.FastMath,
1507 };
1508
1509 pub const Cast = struct {
1510 const CastOpcode = Builder.CastOpcode;
1511 pub const ops = [_]AbbrevOp{
1512 .{ .literal = 3 },
1513 ValueAbbrev,
1514 .{ .fixed_runtime = Builder.Type },
1515 .{ .fixed = @bitSizeOf(CastOpcode) },
1516 };
1517
1518 val: u32,
1519 type_index: Builder.Type,
1520 opcode: CastOpcode,
1521 };
1522
1523 pub const Alloca = struct {
1524 pub const Flags = packed struct(u11) {
1525 align_lower: u5,
1526 inalloca: bool,
1527 explicit_type: bool,
1528 swift_error: bool,
1529 align_upper: u3,
1530 };
1531 pub const ops = [_]AbbrevOp{
1532 .{ .literal = 19 },
1533 .{ .fixed_runtime = Builder.Type },
1534 .{ .fixed_runtime = Builder.Type },
1535 ValueAbbrev,
1536 .{ .fixed = @bitSizeOf(Flags) },
1537 };
1538
1539 inst_type: Builder.Type,
1540 len_type: Builder.Type,
1541 len_value: u32,
1542 flags: Flags,
1543 };
1544
1545 pub const RetVoid = struct {
1546 pub const ops = [_]AbbrevOp{
1547 .{ .literal = 10 },
1548 };
1549 };
1550
1551 pub const Ret = struct {
1552 pub const ops = [_]AbbrevOp{
1553 .{ .literal = 10 },
1554 ValueAbbrev,
1555 };
1556 val: u32,
1557 };
1558
1559 pub const GetElementPtr = struct {
1560 pub const ops = [_]AbbrevOp{
1561 .{ .literal = 43 },
1562 .{ .fixed = 1 },
1563 .{ .fixed_runtime = Builder.Type },
1564 ValueAbbrev,
1565 ValueArrayAbbrev,
1566 };
1567
1568 is_inbounds: bool,
1569 type_index: Builder.Type,
1570 base: Builder.Value,
1571 indices: []const Builder.Value,
1572 };
1573
1574 pub const ExtractValue = struct {
1575 pub const ops = [_]AbbrevOp{
1576 .{ .literal = 26 },
1577 ValueAbbrev,
1578 ValueArrayAbbrev,
1579 };
1580
1581 val: u32,
1582 indices: []const u32,
1583 };
1584
1585 pub const InsertValue = struct {
1586 pub const ops = [_]AbbrevOp{
1587 .{ .literal = 27 },
1588 ValueAbbrev,
1589 ValueAbbrev,
1590 ValueArrayAbbrev,
1591 };
1592
1593 val: u32,
1594 elem: u32,
1595 indices: []const u32,
1596 };
1597
1598 pub const ExtractElement = struct {
1599 pub const ops = [_]AbbrevOp{
1600 .{ .literal = 6 },
1601 ValueAbbrev,
1602 ValueAbbrev,
1603 };
1604
1605 val: u32,
1606 index: u32,
1607 };
1608
1609 pub const InsertElement = struct {
1610 pub const ops = [_]AbbrevOp{
1611 .{ .literal = 7 },
1612 ValueAbbrev,
1613 ValueAbbrev,
1614 ValueAbbrev,
1615 };
1616
1617 val: u32,
1618 elem: u32,
1619 index: u32,
1620 };
1621
1622 pub const ShuffleVector = struct {
1623 pub const ops = [_]AbbrevOp{
1624 .{ .literal = 8 },
1625 ValueAbbrev,
1626 ValueAbbrev,
1627 ValueAbbrev,
1628 };
1629
1630 lhs: u32,
1631 rhs: u32,
1632 mask: u32,
1633 };
1634
1635 pub const Unreachable = struct {
1636 pub const ops = [_]AbbrevOp{
1637 .{ .literal = 15 },
1638 };
1639 };
1640
1641 pub const Load = struct {
1642 pub const ops = [_]AbbrevOp{
1643 .{ .literal = 20 },
1644 ValueAbbrev,
1645 .{ .fixed_runtime = Builder.Type },
1646 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1647 .{ .fixed = 1 },
1648 };
1649 ptr: u32,
1650 ty: Builder.Type,
1651 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1652 is_volatile: bool,
1653 };
1654
1655 pub const LoadAtomic = struct {
1656 pub const ops = [_]AbbrevOp{
1657 .{ .literal = 41 },
1658 ValueAbbrev,
1659 .{ .fixed_runtime = Builder.Type },
1660 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1661 .{ .fixed = 1 },
1662 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1663 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1664 };
1665 ptr: u32,
1666 ty: Builder.Type,
1667 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1668 is_volatile: bool,
1669 success_ordering: Builder.AtomicOrdering,
1670 sync_scope: Builder.SyncScope,
1671 };
1672
1673 pub const Store = struct {
1674 pub const ops = [_]AbbrevOp{
1675 .{ .literal = 44 },
1676 ValueAbbrev,
1677 ValueAbbrev,
1678 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1679 .{ .fixed = 1 },
1680 };
1681 ptr: u32,
1682 val: u32,
1683 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1684 is_volatile: bool,
1685 };
1686
1687 pub const StoreAtomic = struct {
1688 pub const ops = [_]AbbrevOp{
1689 .{ .literal = 45 },
1690 ValueAbbrev,
1691 ValueAbbrev,
1692 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1693 .{ .fixed = 1 },
1694 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1695 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1696 };
1697 ptr: u32,
1698 val: u32,
1699 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1700 is_volatile: bool,
1701 success_ordering: Builder.AtomicOrdering,
1702 sync_scope: Builder.SyncScope,
1703 };
1704
1705 pub const BrUnconditional = struct {
1706 pub const ops = [_]AbbrevOp{
1707 .{ .literal = 11 },
1708 BlockAbbrev,
1709 };
1710 block: u32,
1711 };
1712
1713 pub const BrConditional = struct {
1714 pub const ops = [_]AbbrevOp{
1715 .{ .literal = 11 },
1716 BlockAbbrev,
1717 BlockAbbrev,
1718 BlockAbbrev,
1719 };
1720 then_block: u32,
1721 else_block: u32,
1722 condition: u32,
1723 };
1724
1725 pub const VaArg = struct {
1726 pub const ops = [_]AbbrevOp{
1727 .{ .literal = 23 },
1728 .{ .fixed_runtime = Builder.Type },
1729 ValueAbbrev,
1730 .{ .fixed_runtime = Builder.Type },
1731 };
1732 list_type: Builder.Type,
1733 list: u32,
1734 type: Builder.Type,
1735 };
1736
1737 pub const AtomicRmw = struct {
1738 pub const ops = [_]AbbrevOp{
1739 .{ .literal = 59 },
1740 ValueAbbrev,
1741 ValueAbbrev,
1742 .{ .fixed = @bitSizeOf(Builder.Function.Instruction.AtomicRmw.Operation) },
1743 .{ .fixed = 1 },
1744 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1745 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1746 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1747 };
1748 ptr: u32,
1749 val: u32,
1750 operation: Builder.Function.Instruction.AtomicRmw.Operation,
1751 is_volatile: bool,
1752 success_ordering: Builder.AtomicOrdering,
1753 sync_scope: Builder.SyncScope,
1754 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1755 };
1756
1757 pub const CmpXchg = struct {
1758 pub const ops = [_]AbbrevOp{
1759 .{ .literal = 46 },
1760 ValueAbbrev,
1761 ValueAbbrev,
1762 ValueAbbrev,
1763 .{ .fixed = 1 },
1764 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1765 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1766 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1767 .{ .fixed = 1 },
1768 .{ .fixed = @bitSizeOf(Builder.Alignment) },
1769 };
1770 ptr: u32,
1771 cmp: u32,
1772 new: u32,
1773 is_volatile: bool,
1774 success_ordering: Builder.AtomicOrdering,
1775 sync_scope: Builder.SyncScope,
1776 failure_ordering: Builder.AtomicOrdering,
1777 is_weak: bool,
1778 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1779 };
1780
1781 pub const Fence = struct {
1782 pub const ops = [_]AbbrevOp{
1783 .{ .literal = 36 },
1784 .{ .fixed = @bitSizeOf(Builder.AtomicOrdering) },
1785 .{ .fixed = @bitSizeOf(Builder.SyncScope) },
1786 };
1787 ordering: Builder.AtomicOrdering,
1788 sync_scope: Builder.SyncScope,
1789 };
1790
1791 pub const DebugLoc = struct {
1792 pub const ops = [_]AbbrevOp{
1793 .{ .literal = 35 },
1794 LineAbbrev,
1795 ColumnAbbrev,
1796 MetadataAbbrev,
1797 MetadataAbbrev,
1798 .{ .literal = 0 },
1799 };
1800 line: u32,
1801 column: u32,
1802 scope: Builder.Metadata,
1803 inlined_at: Builder.Metadata,
1804 };
1805
1806 pub const DebugLocAgain = struct {
1807 pub const ops = [_]AbbrevOp{
1808 .{ .literal = 33 },
1809 };
1810 };
1811
1812 pub const ColdOperandBundle = struct {
1813 pub const ops = [_]AbbrevOp{
1814 .{ .literal = 55 },
1815 .{ .literal = 0 },
1816 };
1817 };
1818
1819 pub const IndirectBr = struct {
1820 pub const ops = [_]AbbrevOp{
1821 .{ .literal = 31 },
1822 .{ .fixed_runtime = Builder.Type },
1823 ValueAbbrev,
1824 BlockArrayAbbrev,
1825 };
1826 ty: Builder.Type,
1827 addr: Builder.Value,
1828 targets: []const Builder.Function.Block.Index,
1829 };
1830};
1831
1832pub const FunctionValueSymbolTable = struct {
1833 pub const id = 14;
1834
1835 pub const abbrevs = [_]type{
1836 BlockEntry,
1837 };
1838
1839 pub const BlockEntry = struct {
1840 pub const ops = [_]AbbrevOp{
1841 .{ .literal = 2 },
1842 ValueAbbrev,
1843 .{ .array_fixed = 8 },
1844 };
1845 value_id: u32,
1846 string: []const u8,
1847 };
1848};
1849
1850pub const Strtab = struct {
1851 pub const id = 23;
1852
1853 pub const abbrevs = [_]type{Blob};
1854
1855 pub const Blob = struct {
1856 pub const ops = [_]AbbrevOp{
1857 .{ .literal = 1 },
1858 .blob,
1859 };
1860 blob: []const u8,
1861 };
1862};