authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-21 10:20:57+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-25 15:47:10+02:00
logfcb9d475a1f1db7ac11038766fedc67c21949d8c
tree0210f6b6bd89a6b68626bfff98763b3f1729ec8c
parentdccc724179d984ac5785b6a20bd187bb9c8f749d

spirv: merge Module into CodeGen and trim caches

- Delete `Module.zig`. Fields and helpers are moved into `CodeGen.zig`. - Drop the caches that are already handled by `dedup_types` and fix the bugs that got exposed after this change. - Reorder fields by lifecycle and inline some functions into their caller

4 files changed, 1792 insertions(+), 2152 deletions(-)

src/codegen/spirv/Assembler.zig+74-85
......@@ -3,7 +3,7 @@ const Allocator = std.mem.Allocator;
33const assert = std.debug.assert;
44
55const CodeGen = @import("CodeGen.zig");
6const Decl = @import("Module.zig").Decl;
6const Decl = @import("CodeGen.zig").Decl;
77
88const spec = @import("spec.zig");
99const Opcode = spec.Opcode;
......@@ -56,7 +56,7 @@ const Operand = union(enum) {
5656};
5757
5858pub fn deinit(ass: *Assembler) void {
59 const gpa = ass.cg.module.gpa;
59 const gpa = ass.cg.gpa;
6060 for (ass.errors.items) |err| gpa.free(err.msg);
6161 ass.tokens.deinit(gpa);
6262 ass.errors.deinit(gpa);
......@@ -69,7 +69,7 @@ pub fn deinit(ass: *Assembler) void {
6969const Error = error{ AssembleFail, OutOfMemory };
7070
7171pub fn assemble(ass: *Assembler, src: []const u8) Error!void {
72 const gpa = ass.cg.module.gpa;
72 const gpa = ass.cg.gpa;
7373
7474 ass.src = src;
7575 ass.errors.clearRetainingCapacity();
......@@ -100,7 +100,7 @@ const ErrorMsg = struct {
100100};
101101
102102fn addError(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytype) !void {
103 const gpa = ass.cg.module.gpa;
103 const gpa = ass.cg.gpa;
104104 const msg = try std.fmt.allocPrint(gpa, fmt, args);
105105 errdefer gpa.free(msg);
106106 try ass.errors.append(gpa, .{
......@@ -159,7 +159,7 @@ const AsmValue = union(enum) {
159159/// If this function returns `error.AssembleFail`, an explanatory
160160/// error message has already been emitted into `ass.errors`.
161161fn processInstruction(ass: *Assembler) !void {
162 const module = ass.cg.module;
162 const cg = ass.cg;
163163 const result: AsmValue = switch (ass.inst.opcode) {
164164 .OpEntryPoint => {
165165 return ass.fail(ass.currentToken().start, "cannot export entry points in assembly", .{});
......@@ -176,7 +176,7 @@ fn processInstruction(ass: *Assembler) !void {
176176 const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse {
177177 return ass.fail(set_name_offset, "unknown instruction set: {s}", .{set_name});
178178 };
179 break :blk .{ .value = try module.importInstructionSet(set_tag) };
179 break :blk .{ .value = try cg.importInstructionSet(set_tag) };
180180 },
181181 else => switch (ass.inst.opcode.class()) {
182182 .type_declaration => try ass.processTypeInstruction(),
......@@ -197,13 +197,12 @@ fn processInstruction(ass: *Assembler) !void {
197197
198198fn processTypeInstruction(ass: *Assembler) !AsmValue {
199199 const cg = ass.cg;
200 const gpa = cg.module.gpa;
201 const module = cg.module;
200 const gpa = cg.gpa;
202201 const operands = ass.inst.operands.items;
203 const section = &module.sections.globals;
202 const section = &cg.sections.globals;
204203 const id = switch (ass.inst.opcode) {
205 .OpTypeVoid => try module.voidType(),
206 .OpTypeBool => try module.boolType(),
204 .OpTypeVoid => try cg.voidType(),
205 .OpTypeBool => try cg.boolType(),
207206 .OpTypeInt => blk: {
208207 const signedness: std.lang.Signedness = switch (operands[2].literal32) {
209208 0 => .unsigned,
......@@ -216,7 +215,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
216215 const width = std.math.cast(u16, operands[1].literal32) orelse {
217216 return ass.fail(0, "int type of {} bits is too large", .{operands[1].literal32});
218217 };
219 break :blk try module.intType(signedness, width);
218 break :blk try cg.intType(signedness, width);
220219 },
221220 .OpTypeFloat => blk: {
222221 const bits = operands[1].literal32;
......@@ -226,11 +225,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
226225 return ass.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});
227226 },
228227 }
229 break :blk try module.floatType(@intCast(bits));
228 break :blk try cg.floatType(@intCast(bits));
230229 },
231230 .OpTypeVector => blk: {
232231 const child_type = try ass.resolveRefId(operands[1].ref_id);
233 break :blk try module.vectorType(operands[2].literal32, child_type);
232 break :blk try cg.vectorType(operands[2].literal32, child_type);
234233 },
235234 .OpTypeArray => {
236235 // TODO: The length of an OpTypeArray is determined by a constant (which may be a spec constant),
......@@ -239,8 +238,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
239238 },
240239 .OpTypeRuntimeArray => blk: {
241240 const element_type = try ass.resolveRefId(operands[1].ref_id);
242 const result_id = module.allocId();
243 try section.emit(module.gpa, .OpTypeRuntimeArray, .{
241 const result_id = cg.allocId();
242 try section.emit(cg.gpa, .OpTypeRuntimeArray, .{
244243 .id_result = result_id,
245244 .element_type = element_type,
246245 });
......@@ -249,8 +248,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
249248 .OpTypePointer => blk: {
250249 const storage_class: StorageClass = @enumFromInt(operands[1].value);
251250 const child_type = try ass.resolveRefId(operands[2].ref_id);
252 const result_id = module.allocId();
253 try section.emit(module.gpa, .OpTypePointer, .{
251 const result_id = cg.allocId();
252 try section.emit(cg.gpa, .OpTypePointer, .{
254253 .id_result = result_id,
255254 .storage_class = storage_class,
256255 .type = child_type,
......@@ -262,11 +261,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
262261 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
263262 const ids = try cg.id_scratch.addManyAsSlice(gpa, operands[1..].len);
264263 for (operands[1..], ids) |op, *id| id.* = try ass.resolveRefId(op.ref_id);
265 break :blk try module.structType(ids, null, .none);
264 break :blk try cg.structType(ids, null, .none);
266265 },
267266 .OpTypeImage => blk: {
268267 const sampled_type = try ass.resolveRefId(operands[1].ref_id);
269 const result_id = module.allocId();
268 const result_id = cg.allocId();
270269 try section.emit(gpa, .OpTypeImage, .{
271270 .id_result = result_id,
272271 .sampled_type = sampled_type,
......@@ -280,13 +279,13 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
280279 break :blk result_id;
281280 },
282281 .OpTypeSampler => blk: {
283 const result_id = module.allocId();
282 const result_id = cg.allocId();
284283 try section.emit(gpa, .OpTypeSampler, .{ .id_result = result_id });
285284 break :blk result_id;
286285 },
287286 .OpTypeSampledImage => blk: {
288287 const image_type = try ass.resolveRefId(operands[1].ref_id);
289 const result_id = module.allocId();
288 const result_id = cg.allocId();
290289 try section.emit(gpa, .OpTypeSampledImage, .{ .id_result = result_id, .image_type = image_type });
291290 break :blk result_id;
292291 },
......@@ -301,8 +300,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
301300 for (param_types, param_operands) |*param, operand| {
302301 param.* = try ass.resolveRefId(operand.ref_id);
303302 }
304 const result_id = module.allocId();
305 try section.emit(module.gpa, .OpTypeFunction, .{
303 const result_id = cg.allocId();
304 try section.emit(cg.gpa, .OpTypeFunction, .{
306305 .id_result = result_id,
307306 .return_type = return_type,
308307 .id_ref_2 = param_types,
......@@ -318,27 +317,27 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
318317/// - No forward references are allowed in operands.
319318/// - Target section is determined from instruction type.
320319fn processGenericInstruction(ass: *Assembler) !?AsmValue {
321 const module = ass.cg.module;
322 const target = module.zcu.getTarget();
320 const cg = ass.cg;
321 const target = cg.zcu.getTarget();
323322 const operands = ass.inst.operands.items;
324323 var maybe_spv_decl_index: ?Decl.Index = null;
325324 const section = switch (ass.inst.opcode.class()) {
326 .constant_creation => &module.sections.globals,
327 .annotation => &module.sections.annotations,
325 .constant_creation => &cg.sections.globals,
326 .annotation => &cg.sections.annotations,
328327 .type_declaration => unreachable, // Handled elsewhere.
329328 else => switch (ass.inst.opcode) {
330329 .OpEntryPoint => unreachable,
331 .OpExecutionMode, .OpExecutionModeId => &module.sections.execution_modes,
330 .OpExecutionMode, .OpExecutionModeId => &cg.sections.execution_modes,
332331 .OpVariable => section: {
333332 const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);
334333 if (storage_class == .function) break :section &ass.cg.prologue;
335 maybe_spv_decl_index = try module.allocDecl(.global);
334 maybe_spv_decl_index = try cg.allocDecl(.global);
336335 if (!target.cpu.has(.spirv, .v1_4) and storage_class != .input and storage_class != .output) {
337336 // Before version 1.4, the interface’s storage classes are limited to the Input and Output
338 break :section &module.sections.globals;
337 break :section &cg.sections.globals;
339338 }
340 try ass.cg.module.decl_deps.append(module.gpa, maybe_spv_decl_index.?);
341 break :section &module.sections.globals;
339 try ass.cg.decl_deps.append(cg.gpa, maybe_spv_decl_index.?);
340 break :section &cg.sections.globals;
342341 },
343342 else => &ass.cg.body,
344343 },
......@@ -348,36 +347,36 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue {
348347 const first_word = section.instructions.items.len;
349348 // At this point we're not quite sure how many operands this instruction is
350349 // going to have, so insert 0 and patch up the actual opcode word later.
351 try section.ensureUnusedCapacity(module.gpa, 1);
350 try section.ensureUnusedCapacity(cg.gpa, 1);
352351 section.writeWord(0);
353352
354353 for (operands) |operand| {
355354 switch (operand) {
356355 .value, .literal32 => |word| {
357 try section.ensureUnusedCapacity(module.gpa, 1);
356 try section.ensureUnusedCapacity(cg.gpa, 1);
358357 section.writeWord(word);
359358 },
360359 .literal64 => |dword| {
361 try section.ensureUnusedCapacity(module.gpa, 2);
360 try section.ensureUnusedCapacity(cg.gpa, 2);
362361 section.writeDoubleWord(dword);
363362 },
364363 .result_id => {
365364 maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index|
366 module.declPtr(spv_decl_index).result_id
365 cg.declPtr(spv_decl_index).result_id
367366 else
368 module.allocId();
369 try section.ensureUnusedCapacity(module.gpa, 1);
367 cg.allocId();
368 try section.ensureUnusedCapacity(cg.gpa, 1);
370369 section.writeOperand(Id, maybe_result_id.?);
371370 },
372371 .ref_id => |index| {
373372 const result = try ass.resolveRef(index);
374 try section.ensureUnusedCapacity(module.gpa, 1);
373 try section.ensureUnusedCapacity(cg.gpa, 1);
375374 section.writeOperand(spec.Id, result.resultId());
376375 },
377376 .string => |offset| {
378377 const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0);
379378 const size = std.math.divCeil(usize, text.len + 1, @sizeOf(Word)) catch unreachable;
380 try section.ensureUnusedCapacity(module.gpa, size);
379 try section.ensureUnusedCapacity(cg.gpa, size);
381380 section.writeOperand(spec.LiteralString, text);
382381 },
383382 }
......@@ -430,7 +429,7 @@ fn resolveRefId(ass: *Assembler, ref: AsmValue.Ref) !Id {
430429}
431430
432431fn parseInstruction(ass: *Assembler) !void {
433 const gpa = ass.cg.module.gpa;
432 const gpa = ass.cg.gpa;
434433
435434 ass.inst.opcode = undefined;
436435 ass.inst.operands.clearRetainingCapacity();
......@@ -522,7 +521,7 @@ fn parseOperand(ass: *Assembler, kind: spec.OperandKind) Error!void {
522521
523522/// Also handles parsing any required extra operands.
524523fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {
525 const gpa = ass.cg.module.gpa;
524 const gpa = ass.cg.gpa;
526525
527526 var tok = ass.currentToken();
528527 try ass.expectToken(.value);
......@@ -571,7 +570,7 @@ fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {
571570
572571/// Also handles parsing any required extra operands.
573572fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {
574 const gpa = ass.cg.module.gpa;
573 const gpa = ass.cg.gpa;
575574
576575 const tok = ass.currentToken();
577576 if (ass.eatToken(.placeholder)) {
......@@ -622,7 +621,7 @@ fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {
622621}
623622
624623fn parseRefId(ass: *Assembler) !void {
625 const gpa = ass.cg.module.gpa;
624 const gpa = ass.cg.gpa;
626625
627626 const tok = ass.currentToken();
628627 try ass.expectToken(.result_id);
......@@ -638,7 +637,7 @@ fn parseRefId(ass: *Assembler) !void {
638637}
639638
640639fn parseLiteralInteger(ass: *Assembler) !void {
641 const gpa = ass.cg.module.gpa;
640 const gpa = ass.cg.gpa;
642641
643642 const tok = ass.currentToken();
644643 if (ass.eatToken(.placeholder)) {
......@@ -671,7 +670,7 @@ fn parseLiteralInteger(ass: *Assembler) !void {
671670}
672671
673672fn parseLiteralExtInstInteger(ass: *Assembler) !void {
674 const gpa = ass.cg.module.gpa;
673 const gpa = ass.cg.gpa;
675674
676675 const tok = ass.currentToken();
677676 if (ass.eatToken(.placeholder)) {
......@@ -699,7 +698,7 @@ fn parseLiteralExtInstInteger(ass: *Assembler) !void {
699698}
700699
701700fn parseString(ass: *Assembler) !void {
702 const gpa = ass.cg.module.gpa;
701 const gpa = ass.cg.gpa;
703702
704703 const tok = ass.currentToken();
705704 try ass.expectToken(.string);
......@@ -722,46 +721,36 @@ fn parseString(ass: *Assembler) !void {
722721}
723722
724723fn parseContextDependentNumber(ass: *Assembler) !void {
725 const module = ass.cg.module;
726
727 // For context dependent numbers, the actual type to parse is determined by the instruction.
728 // Currently, this operand appears in OpConstant and OpSpecConstant, where the too-be-parsed type
729 // is determined by the result type. That means that in this instructions we have to resolve the
730 // operand type early and look at the result to see how we need to proceed.
724 const cg = ass.cg;
731725 assert(ass.inst.opcode == .OpConstant or ass.inst.opcode == .OpSpecConstant);
732726
733727 const tok = ass.currentToken();
734728 const result = try ass.resolveRef(ass.inst.operands.items[0].ref_id);
735729 const result_id = result.resultId();
736 // We are going to cheat a little bit: The types we are interested in, int and float,
737 // are added to the module and cached via module.intType and module.floatType. Therefore,
738 // we can determine the width of these types by directly checking the cache.
739 // This only works if the Assembler and codegen both use spv.intType and spv.floatType though.
740 // We don't expect there to be many of these types, so just look it up every time.
741 // TODO: Count be improved to be a little bit more efficent.
742
743 {
744 var it = module.cache.int_types.iterator();
745 while (it.next()) |entry| {
746 const id = entry.value_ptr.*;
747 if (id != result_id) continue;
748 const info = entry.key_ptr.*;
749 return try ass.parseContextDependentInt(info.signedness, info.bits);
750 }
751 }
752730
753 {
754 var it = module.cache.float_types.iterator();
755 while (it.next()) |entry| {
756 const id = entry.value_ptr.*;
757 if (id != result_id) continue;
758 const info = entry.key_ptr.*;
759 switch (info.bits) {
760 16 => try ass.parseContextDependentFloat(16),
761 32 => try ass.parseContextDependentFloat(32),
762 64 => try ass.parseContextDependentFloat(64),
763 else => return ass.fail(tok.start, "cannot parse {}-bit info literal", .{info.bits}),
764 }
731 const words = cg.sections.globals.instructions.items;
732 var offset: usize = 0;
733 while (offset < words.len) {
734 const word_count = words[offset] >> 16;
735 const opcode: Opcode = @enumFromInt(words[offset] & 0xFFFF);
736 defer offset += word_count;
737 if (word_count == 0) break;
738 switch (opcode) {
739 .OpTypeInt => if (word_count >= 4 and @as(Id, @enumFromInt(words[offset + 1])) == result_id) {
740 const width: u16 = @intCast(words[offset + 2]);
741 const signedness: std.lang.Signedness = if (words[offset + 3] == 0) .unsigned else .signed;
742 return ass.parseContextDependentInt(signedness, width);
743 },
744 .OpTypeFloat => if (word_count >= 3 and @as(Id, @enumFromInt(words[offset + 1])) == result_id) {
745 const bits = words[offset + 2];
746 return switch (bits) {
747 16 => ass.parseContextDependentFloat(16),
748 32 => ass.parseContextDependentFloat(32),
749 64 => ass.parseContextDependentFloat(64),
750 else => ass.fail(tok.start, "cannot parse {}-bit info literal", .{bits}),
751 };
752 },
753 else => {},
765754 }
766755 }
767756
......@@ -769,7 +758,7 @@ fn parseContextDependentNumber(ass: *Assembler) !void {
769758}
770759
771760fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, width: u32) !void {
772 const gpa = ass.cg.module.gpa;
761 const gpa = ass.cg.gpa;
773762
774763 const tok = ass.currentToken();
775764 if (ass.eatToken(.placeholder)) {
......@@ -820,7 +809,7 @@ fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, wi
820809}
821810
822811fn parseContextDependentFloat(ass: *Assembler, comptime width: u16) !void {
823 const gpa = ass.cg.module.gpa;
812 const gpa = ass.cg.gpa;
824813
825814 const Float = std.meta.Float(width);
826815 const Int = @Int(.unsigned, width);
......@@ -893,7 +882,7 @@ fn tokenText(ass: Assembler, tok: Token) []const u8 {
893882/// Tokenize `ass.src` and put the tokens in `ass.tokens`.
894883/// Any errors encountered are appended to `ass.errors`.
895884fn tokenize(ass: *Assembler) !void {
896 const gpa = ass.cg.module.gpa;
885 const gpa = ass.cg.gpa;
897886
898887 ass.tokens.clearRetainingCapacity();
899888
src/codegen/spirv/CodeGen.zig+1713-1271
......@@ -1,36 +1,103 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const Target = std.Target;
4const Signedness = std.lang.Signedness;
5const assert = std.debug.assert;
6const log = std.log.scoped(.codegen);
1// Compilation
2pt: Zcu.PerThread,
3zcu: *Zcu,
4gpa: Allocator,
5arena: Allocator,
6air: Air,
7liveness: Air.Liveness,
8owner_nav: InternPool.Nav.Index,
9base_line: u32,
710
8const builtin = @import("builtin");
9const link = @import("../../link.zig");
10const codegen = @import("../../codegen.zig");
11const Zcu = @import("../../Zcu.zig");
12const Type = @import("../../Type.zig");
13const Value = @import("../../Value.zig");
14const Air = @import("../../Air.zig");
15const InternPool = @import("../../InternPool.zig");
16const Section = @import("Section.zig");
17const Assembler = @import("Assembler.zig");
18const Mir = @import("Mir.zig");
11// Module-level output (accumulated across the nav's codegen)
12next_result_id: Word = 1,
13decls: std.ArrayList(Decl) = .empty,
14decl_deps: std.ArrayList(Decl.Index) = .empty,
15nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty,
16uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty,
17entry_points: std.array_hash_map.Auto(Id, EntryPoint) = .empty,
18error_buffer: ?Decl.Index = null,
19struct_types: std.array_hash_map.Custom(StructType, Id, StructType.HashContext, true) = .empty,
20builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty,
21sections: struct {
22 // Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".
23 extended_instruction_set: Section = .{},
24 memory_model: Section = .{},
25 execution_modes: Section = .{},
26 debug_strings: Section = .{},
27 debug_names: Section = .{},
28 annotations: Section = .{},
29 globals: Section = .{},
30 functions: Section = .{},
31} = .{},
32
33// Per-function state (reset between top-level genNav calls)
34prologue: Section = .{},
35body: Section = .{},
36args: std.ArrayList(Id) = .empty,
37next_arg_index: u32 = 0,
38block_stack: std.ArrayList(*Block) = .empty,
39block_label: Id = .none,
40/// Whether the current block has been terminated by a terminator
41/// instruction (e.g. OpKill from inline assembly). When true, no further
42/// branch instructions should be emitted for the current block.
43block_terminated: bool = false,
44block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
45inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
46tracked_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,
47loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty,
48id_scratch: std.ArrayList(Id) = .empty,
1949
20const spec = @import("spec.zig");
21const Opcode = spec.Opcode;
22const Word = spec.Word;
23const Id = spec.Id;
24const IdRange = spec.IdRange;
25const StorageClass = spec.StorageClass;
50const big_int_bits = @bitSizeOf(u32);
2651
27const Module = @import("Module.zig");
28const Decl = Module.Decl;
29const Repr = Module.Repr;
30const InternMap = Module.InternMap;
31const PtrTypeMap = Module.PtrTypeMap;
52/// Data can be lowered into in two basic representations: indirect, which is when
53/// a type is stored in memory, and direct, which is how a type is stored when its
54/// a direct SPIR-V value.
55pub const Repr = enum {
56 /// A SPIR-V value as it would be used in operations.
57 direct,
58 /// A SPIR-V value as it is stored in memory.
59 indirect,
60};
3261
33const CodeGen = @This();
62/// A function or global, tracked here so the linker can order globals and build
63/// per-entry-point interface lists.
64pub const Decl = struct {
65 pub const Index = enum(u32) { _ };
66 pub const Kind = enum { func, global, invocation_global };
67
68 kind: Kind,
69 /// Result-id of the associated OpFunction / OpVariable / InvocationGlobal.
70 result_id: Id,
71 /// Range into `decl_deps` for this decl's dependencies.
72 begin_dep: usize = 0,
73 end_dep: usize = 0,
74 /// Whether an extern-function stub has been emitted.
75 has_extern_stub: bool = false,
76};
77
78pub const EntryPoint = struct {
79 decl_index: Decl.Index,
80 name: []const u8,
81 cc: std.builtin.CallingConvention,
82};
83
84const StructType = struct {
85 fields: []const Id,
86 ip_index: InternPool.Index,
87
88 const HashContext = struct {
89 pub fn hash(_: @This(), ty: StructType) u32 {
90 var hasher = std.hash.Wyhash.init(0);
91 hasher.update(std.mem.sliceAsBytes(ty.fields));
92 hasher.update(std.mem.asBytes(&ty.ip_index));
93 return @truncate(hasher.final());
94 }
95
96 pub fn eql(_: @This(), a: StructType, b: StructType, _: usize) bool {
97 return a.ip_index == b.ip_index and std.mem.eql(Id, a.fields, b.fields);
98 }
99 };
100};
34101
35102pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
36103 return comptime &.initMany(&.{
......@@ -43,60 +110,40 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
43110 });
44111}
45112
46pub const zig_call_abi_ver = 3;
47
48113const LoopSwitch = struct { cond_var: Id, continue_label: Id };
49114
50/// This type indicates the way that a block is terminated. The
51/// state of a particular block is used to track how a jump from
52/// inside the block must reach the outside.
115/// Pointer-typed AIR refs should resolve through `resolvePtr` to handle the
116/// `tracked_allocas` case explicitly at every use site.
117const Ptr = union(enum) {
118 id: Id,
119 /// Function-local pointer whose value lives in `tracked_allocas` rather
120 /// than a real OpVariable. `slot` is the current pointee value.
121 tracked: struct { id: Id, slot: *?Id },
122};
123
124/// Tracks how control flow leaves a Zig `block` under SPIR-V's structured
125/// control flow rules.
53126const Block = union(enum) {
54127 const Incoming = struct {
55128 src_label: Id,
56 /// Instruction that returns an u32 value of the
57 /// `Air.Inst.Index` that control flow should jump to.
129 /// Block index (u32) that control flow should jump to next.
58130 next_block: Id,
59131 };
60132
61133 const SelectionMerge = struct {
62 /// Incoming block from the `then` label.
63 /// Note that the incoming block from the `else` label is
64 /// either given by the next element in the stack.
65134 incoming: Incoming,
66 /// The label id of the cond_br's merge block.
67 /// For the top-most element in the stack, this
68 /// value is undefined.
135 /// Label of the cond_br's merge block (undefined for top-of-stack).
69136 merge_block: Id,
70137 };
71138
72 /// For a `selection` type block, we cannot use early exits, and we
73 /// must generate a 'merge ladder' of OpSelection instructions. To that end,
74 /// we keep a stack of the merges that still must be closed at the end of
75 /// a block.
76 ///
77 /// This entire structure basically just resembles a tree like
78 /// a x
79 /// \ /
80 /// b o merge
81 /// \ /
82 /// c o merge
83 /// \ /
84 /// o merge
85 /// /
86 /// o jump to next block
139 /// Selection blocks can't use early exits. Closing requires a "merge ladder"
140 /// of nested OpSelectionMerge instructions, one per pending merge.
87141 selection: struct {
88 /// In order to know which merges we still need to do, we need to keep
89 /// a stack of those.
90142 merge_stack: std.ArrayList(SelectionMerge) = .empty,
91143 },
92 /// For a `loop` type block, we can early-exit the block by
93 /// jumping to the loop exit node, and we don't need to generate
94 /// an entire stack of merges.
144 /// Loop blocks early-exit by jumping to the loop merge label.
95145 loop: struct {
96 /// The next block to jump to can be determined from any number
97 /// of conditions that jump to the loop exit.
98146 merges: std.ArrayList(Incoming) = .empty,
99 /// The label id of the loop's merge block.
100147 merge_block: Id,
101148 },
102149
......@@ -109,39 +156,36 @@ const Block = union(enum) {
109156 }
110157};
111158
112pt: Zcu.PerThread,
113air: Air,
114liveness: Air.Liveness,
115owner_nav: InternPool.Nav.Index,
116module: *Module,
117block_stack: std.ArrayList(*Block) = .empty,
118block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
119base_line: u32,
120block_label: Id = .none,
121/// Whether the current block has been terminated by a terminator
122/// instruction (e.g. OpKill from inline assembly). When true, no further
123/// branch instructions should be emitted for the current block.
124block_terminated: bool = false,
125next_arg_index: u32 = 0,
126args: std.ArrayList(Id) = .empty,
127virtual_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,
128inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
129loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty,
130id_scratch: std.ArrayList(Id) = .empty,
131prologue: Section = .{},
132body: Section = .{},
133
134159pub fn deinit(cg: *CodeGen) void {
135 const gpa = cg.module.gpa;
160 const gpa = cg.gpa;
136161 cg.block_stack.deinit(gpa);
137162 cg.block_results.deinit(gpa);
138163 cg.args.deinit(gpa);
139 cg.virtual_allocas.deinit(gpa);
164 cg.tracked_allocas.deinit(gpa);
140165 cg.inst_results.deinit(gpa);
141166 cg.loop_switches.deinit(gpa);
142167 cg.id_scratch.deinit(gpa);
143168 cg.prologue.deinit(gpa);
144169 cg.body.deinit(gpa);
170
171 cg.nav_link.deinit(gpa);
172 cg.uav_link.deinit(gpa);
173
174 cg.sections.extended_instruction_set.deinit(gpa);
175 cg.sections.memory_model.deinit(gpa);
176 cg.sections.execution_modes.deinit(gpa);
177 cg.sections.debug_strings.deinit(gpa);
178 cg.sections.debug_names.deinit(gpa);
179 cg.sections.annotations.deinit(gpa);
180 cg.sections.globals.deinit(gpa);
181 cg.sections.functions.deinit(gpa);
182
183 cg.struct_types.deinit(gpa);
184 cg.builtins.deinit(gpa);
185
186 cg.decls.deinit(gpa);
187 cg.decl_deps.deinit(gpa);
188 cg.entry_points.deinit(gpa);
145189}
146190
147191pub fn generate(
......@@ -157,19 +201,15 @@ pub fn generate(
157201
158202 var arena = std.heap.ArenaAllocator.init(gpa);
159203 defer arena.deinit();
160 var module: Module = .{
161 .gpa = gpa,
162 .arena = arena.allocator(),
163 .zcu = zcu,
164 };
165 defer module.deinit();
166204
167205 var cg: CodeGen = .{
168206 .pt = pt,
207 .gpa = gpa,
208 .arena = arena.allocator(),
209 .zcu = zcu,
169210 .air = air.*,
170211 .liveness = liveness.*.?,
171212 .owner_nav = nav,
172 .module = &module,
173213 .base_line = zcu.navSrcLine(nav),
174214 };
175215 defer cg.deinit();
......@@ -191,19 +231,15 @@ pub fn generateNav(
191231
192232 var arena = std.heap.ArenaAllocator.init(gpa);
193233 defer arena.deinit();
194 var module: Module = .{
195 .gpa = gpa,
196 .arena = arena.allocator(),
197 .zcu = zcu,
198 };
199 defer module.deinit();
200234
201235 var cg: CodeGen = .{
202236 .pt = pt,
237 .gpa = gpa,
238 .arena = arena.allocator(),
239 .zcu = zcu,
203240 .air = undefined,
204241 .liveness = undefined,
205242 .owner_nav = nav_index,
206 .module = &module,
207243 .base_line = zcu.navSrcLine(nav_index),
208244 };
209245 defer cg.deinit();
......@@ -217,11 +253,9 @@ pub fn generateNav(
217253}
218254
219255fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
220 const module = cg.module;
221
222 const owner_entry = module.nav_link.get(cg.owner_nav);
256 const owner_entry = cg.nav_link.get(cg.owner_nav);
223257 const owner_decl_index = owner_entry orelse return .{
224 .id_bound = module.next_result_id,
258 .id_bound = cg.next_result_id,
225259 .owner_nav = cg.owner_nav,
226260 .kind = .func,
227261 .decl_result_id = .none,
......@@ -239,14 +273,14 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
239273 .entry_points = &.{},
240274 };
241275
242 const owner_decl = module.declPtr(owner_decl_index);
276 const owner_decl = cg.declPtr(owner_decl_index);
243277
244278 var nav_refs: std.ArrayList(Mir.NavRef) = .empty;
245279 defer nav_refs.deinit(gpa);
246 var nav_it = module.nav_link.iterator();
280 var nav_it = cg.nav_link.iterator();
247281 while (nav_it.next()) |entry| {
248282 if (entry.key_ptr.* == cg.owner_nav) continue;
249 const decl = module.declPtr(entry.value_ptr.*);
283 const decl = cg.declPtr(entry.value_ptr.*);
250284 try nav_refs.append(gpa, .{
251285 .local_id = decl.result_id,
252286 .nav = entry.key_ptr.*,
......@@ -256,9 +290,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
256290
257291 var uav_refs: std.ArrayList(Mir.UavRef) = .empty;
258292 defer uav_refs.deinit(gpa);
259 var uav_it = module.uav_link.iterator();
293 var uav_it = cg.uav_link.iterator();
260294 while (uav_it.next()) |entry| {
261 const decl = module.declPtr(entry.value_ptr.*);
295 const decl = cg.declPtr(entry.value_ptr.*);
262296 try uav_refs.append(gpa, .{
263297 .local_id = decl.result_id,
264298 .val = entry.key_ptr.*[0],
......@@ -272,9 +306,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
272306 var internal_globals: std.ArrayList(Id) = .empty;
273307 defer internal_globals.deinit(gpa);
274308
275 const deps = module.decl_deps.items[owner_decl.begin_dep..owner_decl.end_dep];
309 const deps = cg.decl_deps.items[owner_decl.begin_dep..owner_decl.end_dep];
276310 for (deps) |dep_index| {
277 const dep_decl = module.declPtr(dep_index);
311 const dep_decl = cg.declPtr(dep_index);
278312 var found = false;
279313 nav_it.index = 0;
280314 while (nav_it.next()) |entry| {
......@@ -294,10 +328,10 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
294328
295329 var ep_list: std.ArrayList(Mir.EntryPoint) = .empty;
296330 defer ep_list.deinit(gpa);
297 var ep_it = module.entry_points.iterator();
331 var ep_it = cg.entry_points.iterator();
298332 while (ep_it.next()) |entry| {
299333 const ep = entry.value_ptr;
300 const ep_decl = module.declPtr(ep.decl_index);
334 const ep_decl = cg.declPtr(ep.decl_index);
301335 try ep_list.append(gpa, .{
302336 .local_id = ep_decl.result_id,
303337 .name = try gpa.dupe(u8, ep.name),
......@@ -306,17 +340,17 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
306340 }
307341
308342 return .{
309 .id_bound = module.next_result_id,
343 .id_bound = cg.next_result_id,
310344 .owner_nav = cg.owner_nav,
311345 .kind = owner_decl.kind,
312346 .decl_result_id = owner_decl.result_id,
313 .extended_instruction_set = try module.sections.extended_instruction_set.instructions.toOwnedSlice(gpa),
314 .globals = try module.sections.globals.instructions.toOwnedSlice(gpa),
315 .functions = try module.sections.functions.instructions.toOwnedSlice(gpa),
316 .annotations = try module.sections.annotations.instructions.toOwnedSlice(gpa),
317 .debug_names = try module.sections.debug_names.instructions.toOwnedSlice(gpa),
318 .debug_strings = try module.sections.debug_strings.instructions.toOwnedSlice(gpa),
319 .execution_modes = try module.sections.execution_modes.instructions.toOwnedSlice(gpa),
347 .extended_instruction_set = try cg.sections.extended_instruction_set.instructions.toOwnedSlice(gpa),
348 .globals = try cg.sections.globals.instructions.toOwnedSlice(gpa),
349 .functions = try cg.sections.functions.instructions.toOwnedSlice(gpa),
350 .annotations = try cg.sections.annotations.instructions.toOwnedSlice(gpa),
351 .debug_names = try cg.sections.debug_names.instructions.toOwnedSlice(gpa),
352 .debug_strings = try cg.sections.debug_strings.instructions.toOwnedSlice(gpa),
353 .execution_modes = try cg.sections.execution_modes.instructions.toOwnedSlice(gpa),
320354 .nav_refs = try nav_refs.toOwnedSlice(gpa),
321355 .uav_refs = try uav_refs.toOwnedSlice(gpa),
322356 .decl_deps = try decl_deps.toOwnedSlice(gpa),
......@@ -325,11 +359,365 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
325359 };
326360}
327361
362fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
363 const zcu = cg.zcu;
364 return cg.air.typeOf(inst, &zcu.intern_pool);
365}
366
367fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
368 const zcu = cg.zcu;
369 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
370}
371
372/// Does not generate the nav.
373pub fn resolveNav(cg: *CodeGen, ip: *InternPool, nav_index: InternPool.Nav.Index) !Decl.Index {
374 const entry = try cg.nav_link.getOrPut(cg.gpa, nav_index);
375 if (!entry.found_existing) {
376 const nav = ip.getNav(nav_index);
377 // TODO: Extern fn?
378 const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type))
379 .func
380 else switch (nav.resolved.?.@"addrspace") {
381 .generic => .invocation_global,
382 else => .global,
383 };
384 entry.value_ptr.* = try cg.allocDecl(kind);
385 }
386
387 return entry.value_ptr.*;
388}
389
390pub fn allocIds(cg: *CodeGen, n: u32) spec.IdRange {
391 defer cg.next_result_id += n;
392 return .{ .base = cg.next_result_id, .len = n };
393}
394
395pub fn allocId(cg: *CodeGen) Id {
396 return cg.allocIds(1).at(0);
397}
398
399pub fn idBound(cg: *const CodeGen) Word {
400 return cg.next_result_id;
401}
402
403pub fn addEntryPointDeps(
404 cg: *CodeGen,
405 decl_index: Decl.Index,
406 seen: *std.bit_set.Dynamic,
407 interface: *std.array_list.Managed(Id),
408) !void {
409 const decl = cg.declPtr(decl_index);
410 const deps = cg.decl_deps.items[decl.begin_dep..decl.end_dep];
411
412 if (seen.isSet(@intFromEnum(decl_index))) {
413 return;
414 }
415
416 seen.set(@intFromEnum(decl_index));
417
418 if (decl.kind == .global) {
419 try interface.append(decl.result_id);
420 }
421
422 for (deps) |dep| {
423 try cg.addEntryPointDeps(dep, seen, interface);
424 }
425}
426
427pub fn importInstructionSet(cg: *CodeGen, set: spec.InstructionSet) !Id {
428 assert(set != .core);
429 const result_id = cg.allocId();
430 try cg.sections.extended_instruction_set.emit(cg.gpa, .OpExtInstImport, .{
431 .id_result = result_id,
432 .name = @tagName(set),
433 });
434 return result_id;
435}
436
437pub fn boolType(cg: *CodeGen) !Id {
438 const result_id = cg.allocId();
439 try cg.sections.globals.emit(cg.gpa, .OpTypeBool, .{
440 .id_result = result_id,
441 });
442 return result_id;
443}
444
445pub fn voidType(cg: *CodeGen) !Id {
446 const result_id = cg.allocId();
447 try cg.sections.globals.emit(cg.gpa, .OpTypeVoid, .{
448 .id_result = result_id,
449 });
450 try cg.debugName(result_id, "void");
451 return result_id;
452}
453
454pub fn opaqueType(cg: *CodeGen, name: []const u8) !Id {
455 const result_id = cg.allocId();
456 try cg.sections.globals.emit(cg.gpa, .OpTypeOpaque, .{
457 .id_result = result_id,
458 .literal_string = name,
459 });
460 try cg.debugName(result_id, name);
461 return result_id;
462}
463
464pub fn backingIntBits(cg: *const CodeGen, bits: u16) struct { u16, bool } {
465 assert(bits != 0);
466 const target = cg.zcu.getTarget();
467 const ints = [_]struct { bits: u16, enabled: bool }{
468 .{ .bits = 8, .enabled = target.cpu.has(.spirv, .int8) },
469 .{ .bits = 16, .enabled = target.cpu.has(.spirv, .int16) },
470 .{ .bits = 32, .enabled = true },
471 .{ .bits = 64, .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64 },
472 };
473
474 for (ints) |int| {
475 if (bits <= int.bits and int.enabled) return .{ int.bits, false };
476 }
477
478 return .{ std.mem.alignForward(u16, bits, big_int_bits), true };
479}
480
481pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id {
482 assert(bits > 0);
483
484 const target = cg.zcu.getTarget();
485 const actual_signedness = switch (target.os.tag) {
486 // Kernel only supports unsigned ints.
487 .opencl, .amdhsa => .unsigned,
488 else => signedness,
489 };
490 const backing_bits, const big_int = cg.backingIntBits(bits);
491 if (big_int) {
492 const u32_ty = try cg.intType(.unsigned, 32);
493 const len_id = cg.allocId();
494 try cg.sections.globals.emit(cg.gpa, .OpConstant, .{
495 .id_result_type = u32_ty,
496 .id_result = len_id,
497 .value = .{ .uint32 = backing_bits / big_int_bits },
498 });
499 return cg.arrayType(len_id, u32_ty);
500 }
501
502 const result_id = cg.allocId();
503 try cg.sections.globals.emit(cg.gpa, .OpTypeInt, .{
504 .id_result = result_id,
505 .width = backing_bits,
506 .signedness = switch (actual_signedness) {
507 .signed => 1,
508 .unsigned => 0,
509 },
510 });
511 switch (actual_signedness) {
512 .signed => try cg.debugNameFmt(result_id, "i{}", .{backing_bits}),
513 .unsigned => try cg.debugNameFmt(result_id, "u{}", .{backing_bits}),
514 }
515 return result_id;
516}
517
518pub fn floatType(cg: *CodeGen, bits: u16) !Id {
519 assert(bits > 0);
520 const result_id = cg.allocId();
521 try cg.sections.globals.emit(cg.gpa, .OpTypeFloat, .{
522 .id_result = result_id,
523 .width = bits,
524 });
525 try cg.debugNameFmt(result_id, "f{}", .{bits});
526 return result_id;
527}
528
529pub fn vectorType(cg: *CodeGen, len: u32, child_ty_id: Id) !Id {
530 const result_id = cg.allocId();
531 try cg.sections.globals.emit(cg.gpa, .OpTypeVector, .{
532 .id_result = result_id,
533 .component_type = child_ty_id,
534 .component_count = len,
535 });
536 return result_id;
537}
538
539pub fn arrayType(cg: *CodeGen, len_id: Id, child_ty_id: Id) !Id {
540 const result_id = cg.allocId();
541 try cg.sections.globals.emit(cg.gpa, .OpTypeArray, .{
542 .id_result = result_id,
543 .element_type = child_ty_id,
544 .length = len_id,
545 });
546 return result_id;
547}
548
549pub fn ptrType(cg: *CodeGen, child_ty_id: Id, storage_class: spec.StorageClass) !Id {
550 const result_id = cg.allocId();
551 try cg.sections.globals.emit(cg.gpa, .OpTypePointer, .{
552 .id_result = result_id,
553 .storage_class = storage_class,
554 .type = child_ty_id,
555 });
556 return result_id;
557}
558
559pub fn structType(
560 cg: *CodeGen,
561 types: []const Id,
562 maybe_names: ?[]const []const u8,
563 ip_index: InternPool.Index,
564) !Id {
565 const actual_ip_index = if (cg.zcu.comp.config.root_strip) .none else ip_index;
566
567 if (cg.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id;
568 const result_id = cg.allocId();
569 const types_dup = try cg.arena.dupe(Id, types);
570 try cg.sections.globals.emit(cg.gpa, .OpTypeStruct, .{
571 .id_result = result_id,
572 .id_ref = types_dup,
573 });
574
575 if (maybe_names) |names| {
576 assert(names.len == types.len);
577 for (names, 0..) |name, i| {
578 try cg.memberDebugName(result_id, @intCast(i), name);
579 }
580 }
581
582 try cg.struct_types.put(
583 cg.gpa,
584 .{ .fields = types_dup, .ip_index = actual_ip_index },
585 result_id,
586 );
587 return result_id;
588}
589
590pub fn functionType(cg: *CodeGen, return_ty_id: Id, param_type_ids: []const Id) !Id {
591 const result_id = cg.allocId();
592 try cg.sections.globals.emit(cg.gpa, .OpTypeFunction, .{
593 .id_result = result_id,
594 .return_type = return_ty_id,
595 .id_ref_2 = param_type_ids,
596 });
597 return result_id;
598}
599
600pub fn constUndef(cg: *CodeGen, ty_id: Id) !Id {
601 const result_id = cg.allocId();
602 try cg.sections.globals.emit(cg.gpa, .OpUndef, .{
603 .id_result_type = ty_id,
604 .id_result = result_id,
605 });
606 return result_id;
607}
608
609pub fn constNull(cg: *CodeGen, ty_id: Id) !Id {
610 const result_id = cg.allocId();
611 try cg.sections.globals.emit(cg.gpa, .OpConstantNull, .{
612 .id_result_type = ty_id,
613 .id_result = result_id,
614 });
615 return result_id;
616}
617
618pub fn decorate(
619 cg: *CodeGen,
620 target: Id,
621 decoration: spec.Decoration.Extended,
622) !void {
623 try cg.sections.annotations.emit(cg.gpa, .OpDecorate, .{
624 .target = target,
625 .decoration = decoration,
626 });
627}
628
629pub fn decorateMember(
630 cg: *CodeGen,
631 structure_type: Id,
632 member: u32,
633 decoration: spec.Decoration.Extended,
634) !void {
635 try cg.sections.annotations.emit(cg.gpa, .OpMemberDecorate, .{
636 .structure_type = structure_type,
637 .member = member,
638 .decoration = decoration,
639 });
640}
641
642pub fn allocDecl(cg: *CodeGen, kind: Decl.Kind) !Decl.Index {
643 try cg.decls.append(cg.gpa, .{
644 .kind = kind,
645 .result_id = cg.allocId(),
646 });
647
648 return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(cg.decls.items.len - 1))));
649}
650
651pub fn declPtr(cg: *CodeGen, index: Decl.Index) *Decl {
652 return &cg.decls.items[@intFromEnum(index)];
653}
654
655pub fn debugName(cg: *CodeGen, target: Id, name: []const u8) !void {
656 if (cg.zcu.comp.config.root_strip) return;
657 try cg.sections.debug_names.emit(cg.gpa, .OpName, .{
658 .target = target,
659 .name = name,
660 });
661}
662
663pub fn debugNameFmt(cg: *CodeGen, target: Id, comptime fmt: []const u8, args: anytype) !void {
664 if (cg.zcu.comp.config.root_strip) return;
665 const name = try std.fmt.allocPrint(cg.gpa, fmt, args);
666 defer cg.gpa.free(name);
667 try cg.debugName(target, name);
668}
669
670pub fn memberDebugName(cg: *CodeGen, target: Id, member: u32, name: []const u8) !void {
671 if (cg.zcu.comp.config.root_strip) return;
672 try cg.sections.debug_names.emit(cg.gpa, .OpMemberName, .{
673 .type = target,
674 .member = member,
675 .name = name,
676 });
677}
678
679pub fn storageClass(cg: *const CodeGen, as: std.lang.AddressSpace) spec.StorageClass {
680 const target = cg.zcu.getTarget();
681 return switch (as) {
682 .generic => .function,
683 .global => switch (target.os.tag) {
684 .opencl, .amdhsa => .cross_workgroup,
685 else => .storage_buffer,
686 },
687 .push_constant => .push_constant,
688 .output => .output,
689 .uniform => .uniform,
690 .storage_buffer => .storage_buffer,
691 .physical_storage_buffer => .physical_storage_buffer,
692 .constant => .uniform_constant,
693 .shared => .workgroup,
694 .local => .function,
695 .input => .input,
696 .gs,
697 .fs,
698 .ss,
699 .far,
700 .param,
701 .flash,
702 .flash1,
703 .flash2,
704 .flash3,
705 .flash4,
706 .flash5,
707 .cog,
708 .lut,
709 .hub,
710 .externref,
711 .funcref,
712 => unreachable,
713 };
714}
715
328716const Error = error{ AlreadyReported, OutOfMemory };
329717
330718pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
331 const gpa = cg.module.gpa;
332 const zcu = cg.module.zcu;
719 const gpa = cg.gpa;
720 const zcu = cg.zcu;
333721 const ip = &zcu.intern_pool;
334722 const target = zcu.getTarget();
335723
......@@ -339,17 +727,17 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
339727
340728 if (!do_codegen and !ty.hasRuntimeBits(zcu)) return;
341729
342 const spv_decl_index = try cg.module.resolveNav(ip, cg.owner_nav);
343 const decl = cg.module.declPtr(spv_decl_index);
730 const spv_decl_index = try cg.resolveNav(ip, cg.owner_nav);
731 const decl = cg.declPtr(spv_decl_index);
344732 const result_id = decl.result_id;
345 decl.begin_dep = cg.module.decl_deps.items.len;
733 decl.begin_dep = cg.decl_deps.items.len;
346734
347735 switch (decl.kind) {
348736 .func => {
349737 if (nav.resolved.?.is_extern_decl) {
350738 _ = try cg.resolveType(ty, .direct);
351739 try emitExternFnStub(cg, nav, decl, ty);
352 decl.end_dep = cg.module.decl_deps.items.len;
740 decl.end_dep = cg.decl_deps.items.len;
353741 return;
354742 }
355743
......@@ -357,7 +745,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
357745 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
358746 const is_test = zcu.test_functions.contains(cg.owner_nav);
359747
360 const func_result_id = if (is_test) cg.module.allocId() else result_id;
748 const func_result_id = if (is_test) cg.allocId() else result_id;
361749 const prototype_ty_id = try cg.resolveType(ty, .direct);
362750 try cg.prologue.emit(gpa, .OpFunction, .{
363751 .id_result_type = return_ty_id,
......@@ -368,14 +756,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
368756 .function_control = .{},
369757 });
370758
371 comptime assert(zig_call_abi_ver == 3);
372759 try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len);
373760 for (fn_info.param_types.get(ip)) |param_ty_index| {
374761 const param_ty: Type = .fromInterned(param_ty_index);
375762 if (!param_ty.hasRuntimeBits(zcu)) continue;
376763
377764 const param_type_id = try cg.resolveType(param_ty, .direct);
378 const arg_result_id = cg.module.allocId();
765 const arg_result_id = cg.allocId();
379766 try cg.prologue.emit(gpa, .OpFunctionParameter, .{
380767 .id_result_type = param_type_id,
381768 .id_result = arg_result_id,
......@@ -384,7 +771,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
384771 }
385772
386773 // TODO: This could probably be done in a better way...
387 const root_block_id = cg.module.allocId();
774 const root_block_id = cg.allocId();
388775
389776 // The root block of a function declaration should appear before OpVariable instructions,
390777 // so it is generated into the function's prologue.
......@@ -400,26 +787,26 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
400787 try cg.body.emit(gpa, .OpUnreachable, {});
401788 try cg.body.emit(gpa, .OpFunctionEnd, {});
402789 // Append the actual code into the functions section.
403 try cg.module.sections.functions.append(gpa, cg.prologue);
404 try cg.module.sections.functions.append(gpa, cg.body);
790 try cg.sections.functions.append(gpa, cg.prologue);
791 try cg.sections.functions.append(gpa, cg.body);
405792
406793 // Temporarily generate a test kernel declaration if this is a test function.
407794 if (is_test) {
408795 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);
409796 }
410797
411 try cg.module.debugName(func_result_id, nav.fqn.toSlice(ip));
798 try cg.debugName(func_result_id, nav.fqn.toSlice(ip));
412799 },
413800 .global => {
414801 const key = ip.indexToKey(val.toIntern()).@"extern";
415802
416 const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace");
803 const storage_class = cg.storageClass(nav.resolved.?.@"addrspace");
417804 assert(storage_class != .generic); // These should be instance globals
418805
419806 const ty_id = try cg.resolveType(ty, .indirect);
420 const ptr_ty_id = try cg.module.ptrType(ty_id, storage_class);
807 const ptr_ty_id = try cg.ptrType(ty_id, storage_class);
421808
422 try cg.module.sections.globals.emit(gpa, .OpVariable, .{
809 try cg.sections.globals.emit(gpa, .OpVariable, .{
423810 .id_result_type = ptr_ty_id,
424811 .id_result = result_id,
425812 .storage_class = storage_class,
......@@ -430,11 +817,11 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
430817 switch (storage_class) {
431818 .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => {
432819 if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) {
433 try cg.module.decorate(ty_id, .block);
820 try cg.decorate(ty_id, .block);
434821 }
435822
436823 if (ty.hasRuntimeBits(zcu)) {
437 try cg.module.decorate(ptr_ty_id, .{
824 try cg.decorate(ptr_ty_id, .{
438825 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },
439826 });
440827 try cg.decorateLayout(ty, ty_id);
......@@ -448,23 +835,23 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
448835 if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) {
449836 return cg.fail("storage class must be one of (output, input, uniform_constant) but is {s}", .{@tagName(storage_class)});
450837 }
451 try cg.module.decorate(result_id, .{
838 try cg.decorate(result_id, .{
452839 .location = .{ .location = location },
453840 });
454841 },
455842 .flat => |location| {
456 try cg.module.decorate(result_id, .{ .location = .{ .location = location } });
457 try cg.module.decorate(result_id, .flat);
843 try cg.decorate(result_id, .{ .location = .{ .location = location } });
844 try cg.decorate(result_id, .flat);
458845 },
459846 .descriptor => |descriptor| {
460847 if (storage_class != .storage_buffer and storage_class != .uniform and storage_class != .uniform_constant) {
461848 return cg.fail("storage class must be one of (storage_buffer, uniform, uniform_constant) but is {s}", .{@tagName(storage_class)});
462849 }
463 try cg.module.decorate(result_id, .{
850 try cg.decorate(result_id, .{
464851 .binding = .{ .binding_point = descriptor.binding },
465852 });
466853
467 try cg.module.decorate(result_id, .{
854 try cg.decorate(result_id, .{
468855 .descriptor_set = .{ .descriptor_set = descriptor.set },
469856 });
470857 },
......@@ -474,10 +861,10 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
474861 }
475862
476863 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |built_in| {
477 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = built_in } });
864 try cg.decorate(result_id, .{ .built_in = .{ .built_in = built_in } });
478865 }
479866
480 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
867 try cg.debugName(result_id, nav.fqn.toSlice(ip));
481868 },
482869 .invocation_global => {
483870 // `@extern()` produces an invocation_global whose value is a
......@@ -488,18 +875,18 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
488875 if (ptr_key.base_addr != .nav or ptr_key.byte_offset != 0) break :alias;
489876 const underlying_nav = ip.getNav(ptr_key.base_addr.nav);
490877 if (!underlying_nav.resolved.?.is_extern_decl) break :alias;
491 cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len;
878 cg.declPtr(spv_decl_index).end_dep = cg.decl_deps.items.len;
492879 return;
493880 }
494881
495882 const ty_id = try cg.resolveType(ty, .indirect);
496 const ptr_ty_id = try cg.module.ptrType(ty_id, .function);
883 const ptr_ty_id = try cg.ptrType(ty_id, .function);
497884
498885 // TODO: Combine with resolveAnonDecl?
499886 const void_ty_id = try cg.resolveType(.void, .direct);
500 const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
887 const initializer_proto_ty_id = try cg.functionType(void_ty_id, &.{});
501888
502 const initializer_id = cg.module.allocId();
889 const initializer_id = cg.allocId();
503890 try cg.prologue.emit(gpa, .OpFunction, .{
504891 .id_result_type = try cg.resolveType(.void, .direct),
505892 .id_result = initializer_id,
......@@ -507,7 +894,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
507894 .function_type = initializer_proto_ty_id,
508895 });
509896
510 const root_block_id = cg.module.allocId();
897 const root_block_id = cg.allocId();
511898 try cg.prologue.emit(gpa, .OpLabel, .{
512899 .id_result = root_block_id,
513900 });
......@@ -521,33 +908,33 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
521908
522909 try cg.body.emit(gpa, .OpReturn, {});
523910 try cg.body.emit(gpa, .OpFunctionEnd, {});
524 try cg.module.sections.functions.append(gpa, cg.prologue);
525 try cg.module.sections.functions.append(gpa, cg.body);
911 try cg.sections.functions.append(gpa, cg.prologue);
912 try cg.sections.functions.append(gpa, cg.body);
526913
527 try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
528 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
914 try cg.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
915 try cg.debugName(result_id, nav.fqn.toSlice(ip));
529916
530 try cg.module.sections.globals.emit(gpa, .OpExtInst, .{
917 try cg.sections.globals.emit(gpa, .OpExtInst, .{
531918 .id_result_type = ptr_ty_id,
532919 .id_result = result_id,
533 .set = try cg.module.importInstructionSet(.zig),
920 .set = try cg.importInstructionSet(.zig),
534921 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
535922 .id_ref_4 = &.{initializer_id},
536923 });
537924 },
538925 }
539926
540 cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len;
927 cg.declPtr(spv_decl_index).end_dep = cg.decl_deps.items.len;
541928}
542929
543930fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
544 const zcu = cg.module.zcu;
931 const zcu = cg.zcu;
545932 const ip = &zcu.intern_pool;
546933 switch (ty.zigTypeTag(zcu)) {
547934 .array => {
548935 const elem_ty = ty.childType(zcu);
549936 if (!elem_ty.hasRuntimeBits(zcu)) return;
550 try cg.module.decorate(ty_id, .{
937 try cg.decorate(ty_id, .{
551938 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
552939 });
553940 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
......@@ -556,7 +943,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
556943 const elem_ty = ty.childType(zcu);
557944 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
558945 if (cg.isSpvVector(ty)) return;
559 try cg.module.decorate(ty_id, .{
946 try cg.decorate(ty_id, .{
560947 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
561948 });
562949 },
......@@ -570,7 +957,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
570957 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
571958 if (!field_ty.hasRuntimeBits(zcu)) continue;
572959 const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu));
573 try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } });
960 try cg.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } });
574961 try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect));
575962 member += 1;
576963 }
......@@ -598,13 +985,13 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
598985 const u8_id = try cg.resolveType(.u8, .direct);
599986 if (layout.payload_padding_size != 0) {
600987 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
601 const arr_id = try cg.module.arrayType(len_id, u8_id);
602 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
988 const arr_id = try cg.arrayType(len_id, u8_id);
989 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
603990 }
604991 if (layout.padding_size != 0) {
605992 const len_id = try cg.constInt(.u32, layout.padding_size);
606 const arr_id = try cg.module.arrayType(len_id, u8_id);
607 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
993 const arr_id = try cg.arrayType(len_id, u8_id);
994 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
608995 }
609996 },
610997 .optional => {
......@@ -621,7 +1008,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
6211008
6221009pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
6231010 @branchHint(.cold);
624 return cg.module.zcu.codegenFail(cg.owner_nav, format, args);
1011 return cg.zcu.codegenFail(cg.owner_nav, format, args);
6251012}
6261013
6271014pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
......@@ -631,17 +1018,17 @@ pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
6311018/// This imports the "default" extended instruction set for the target
6321019/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.
6331020fn importExtendedSet(cg: *CodeGen) !Id {
634 const target = cg.module.zcu.getTarget();
1021 const target = cg.zcu.getTarget();
6351022 return switch (target.os.tag) {
636 .opencl, .amdhsa => try cg.module.importInstructionSet(.@"OpenCL.std"),
637 .vulkan, .opengl => try cg.module.importInstructionSet(.@"GLSL.std.450"),
1023 .opencl, .amdhsa => try cg.importInstructionSet(.@"OpenCL.std"),
1024 .vulkan, .opengl => try cg.importInstructionSet(.@"GLSL.std.450"),
6381025 else => unreachable,
6391026 };
6401027}
6411028
6421029/// Fetch the result-id for a previously generated instruction or constant.
6431030fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
644 const zcu = cg.module.zcu;
1031 const zcu = cg.zcu;
6451032 const ip = &zcu.intern_pool;
6461033 if (inst.toInterned()) |val_ip_index| {
6471034 const ty = cg.typeOf(inst);
......@@ -652,9 +1039,9 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
6521039 .func => |func| func.owner_nav,
6531040 else => unreachable,
6541041 };
655 const spv_decl_index = try cg.module.resolveNav(ip, fn_nav);
656 try cg.module.decl_deps.append(cg.module.gpa, spv_decl_index);
657 const decl = cg.module.declPtr(spv_decl_index);
1042 const spv_decl_index = try cg.resolveNav(ip, fn_nav);
1043 try cg.decl_deps.append(cg.gpa, spv_decl_index);
1044 const decl = cg.declPtr(spv_decl_index);
6581045 if (val_key == .@"extern") {
6591046 const nav = ip.getNav(fn_nav);
6601047 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
......@@ -670,22 +1057,22 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
6701057}
6711058
6721059fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
673 const gpa = cg.module.gpa;
1060 const gpa = cg.gpa;
6741061
6751062 // TODO: This cannot be a function at this point, but it should probably be handled anyway.
6761063
677 const zcu = cg.module.zcu;
1064 const zcu = cg.zcu;
6781065 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
6791066 const ty_id = try cg.resolveType(ty, .indirect);
6801067
6811068 const spv_decl_index = blk: {
682 const entry = try cg.module.uav_link.getOrPut(gpa, .{ val, .function });
1069 const entry = try cg.uav_link.getOrPut(gpa, .{ val, .function });
6831070 if (entry.found_existing) {
6841071 try cg.addFunctionDep(entry.value_ptr.*, .function);
685 return cg.module.declPtr(entry.value_ptr.*).result_id;
1072 return cg.declPtr(entry.value_ptr.*).result_id;
6861073 }
6871074
688 const spv_decl_index = try cg.module.allocDecl(.invocation_global);
1075 const spv_decl_index = try cg.allocDecl(.invocation_global);
6891076 try cg.addFunctionDep(spv_decl_index, .function);
6901077 entry.value_ptr.* = spv_decl_index;
6911078 break :blk spv_decl_index;
......@@ -697,7 +1084,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
6971084 // constant lowering of this value will need to be deferred to an initializer similar to
6981085 // other globals.
6991086
700 const result_id = cg.module.declPtr(spv_decl_index).result_id;
1087 const result_id = cg.declPtr(spv_decl_index).result_id;
7011088
7021089 {
7031090 // Save the current state so that we can temporarily generate into a different function.
......@@ -719,16 +1106,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
7191106 }
7201107
7211108 const void_ty_id = try cg.resolveType(.void, .direct);
722 const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
1109 const initializer_proto_ty_id = try cg.functionType(void_ty_id, &.{});
7231110
724 const initializer_id = cg.module.allocId();
1111 const initializer_id = cg.allocId();
7251112 try cg.prologue.emit(gpa, .OpFunction, .{
7261113 .id_result_type = try cg.resolveType(.void, .direct),
7271114 .id_result = initializer_id,
7281115 .function_control = .{},
7291116 .function_type = initializer_proto_ty_id,
7301117 });
731 const root_block_id = cg.module.allocId();
1118 const root_block_id = cg.allocId();
7321119 try cg.prologue.emit(gpa, .OpLabel, .{
7331120 .id_result = root_block_id,
7341121 });
......@@ -743,16 +1130,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
7431130 try cg.body.emit(gpa, .OpReturn, {});
7441131 try cg.body.emit(gpa, .OpFunctionEnd, {});
7451132
746 try cg.module.sections.functions.append(gpa, cg.prologue);
747 try cg.module.sections.functions.append(gpa, cg.body);
1133 try cg.sections.functions.append(gpa, cg.prologue);
1134 try cg.sections.functions.append(gpa, cg.body);
7481135
749 try cg.module.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
1136 try cg.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
7501137
751 const fn_decl_ptr_ty_id = try cg.module.ptrType(ty_id, .function);
752 try cg.module.sections.globals.emit(gpa, .OpExtInst, .{
1138 const fn_decl_ptr_ty_id = try cg.ptrType(ty_id, .function);
1139 try cg.sections.globals.emit(gpa, .OpExtInst, .{
7531140 .id_result_type = fn_decl_ptr_ty_id,
7541141 .id_result = result_id,
755 .set = try cg.module.importInstructionSet(.zig),
1142 .set = try cg.importInstructionSet(.zig),
7561143 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
7571144 .id_ref_4 = &.{initializer_id},
7581145 });
......@@ -761,15 +1148,21 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
7611148 return result_id;
7621149}
7631150
764fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void {
765 const gpa = cg.module.gpa;
766 const target = cg.module.zcu.getTarget();
1151fn resolvePtr(cg: *CodeGen, ref: Air.Inst.Ref) !Ptr {
1152 const id = try cg.resolve(ref);
1153 if (cg.tracked_allocas.getPtr(id)) |slot| return .{ .tracked = .{ .id = id, .slot = slot } };
1154 return .{ .id = id };
1155}
1156
1157fn addFunctionDep(cg: *CodeGen, decl_index: Decl.Index, storage_class: StorageClass) !void {
1158 const gpa = cg.gpa;
1159 const target = cg.zcu.getTarget();
7671160 if (target.cpu.has(.spirv, .v1_4)) {
768 try cg.module.decl_deps.append(gpa, decl_index);
1161 try cg.decl_deps.append(gpa, decl_index);
7691162 } else {
7701163 // Before version 1.4, the interface’s storage classes are limited to the Input and Output
7711164 if (storage_class == .input or storage_class == .output) {
772 try cg.module.decl_deps.append(gpa, decl_index);
1165 try cg.decl_deps.append(gpa, decl_index);
7731166 }
7741167 }
7751168}
......@@ -779,25 +1172,11 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St
7791172/// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to
7801173/// keep track of the previous block.
7811174fn beginSpvBlock(cg: *CodeGen, label: Id) !void {
782 try cg.body.emit(cg.module.gpa, .OpLabel, .{ .id_result = label });
1175 try cg.body.emit(cg.gpa, .OpLabel, .{ .id_result = label });
7831176 cg.block_label = label;
7841177 cg.block_terminated = false;
7851178}
7861179
787/// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if
788/// the Int64 capability is enabled).
789/// Note: The extension SPV_INTEL_arbitrary_precision_integers allows any integer size (at least up to 32 bits).
790/// In theory that could also be used, but since the spec says that it only guarantees support up to 32-bit ints there
791/// is no way of knowing whether those are actually supported.
792/// TODO: Maybe this should be cached?
793fn largestSupportedIntBits(cg: *CodeGen) u16 {
794 const target = cg.module.zcu.getTarget();
795 if (target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64) {
796 return 64;
797 }
798 return 32;
799}
800
8011180const ArithmeticTypeInfo = struct {
8021181 const Class = enum {
8031182 bool,
......@@ -835,8 +1214,8 @@ const ArithmeticTypeInfo = struct {
8351214};
8361215
8371216fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
838 const zcu = cg.module.zcu;
839 const target = cg.module.zcu.getTarget();
1217 const zcu = cg.zcu;
1218 const target = cg.zcu.getTarget();
8401219 var scalar_ty = ty.scalarType(zcu);
8411220 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {
8421221 scalar_ty = scalar_ty.intTagType(zcu);
......@@ -845,7 +1224,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8451224 return switch (scalar_ty.zigTypeTag(zcu)) {
8461225 .bool => .{
8471226 .bits = 1, // Doesn't matter for this class.
848 .backing_bits = cg.module.backingIntBits(1).@"0",
1227 .backing_bits = cg.backingIntBits(1).@"0",
8491228 .vector_len = vector_len,
8501229 .signedness = .unsigned, // Technically, but doesn't matter for this class.
8511230 .class = .bool,
......@@ -860,7 +1239,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8601239 .int => blk: {
8611240 const int_info = scalar_ty.intInfo(zcu);
8621241 // TODO: Maybe it's useful to also return this value.
863 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
1242 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
8641243 break :blk .{
8651244 .bits = int_info.bits,
8661245 .backing_bits = backing_bits,
......@@ -880,8 +1259,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8801259
8811260/// Checks whether the type can be directly translated to SPIR-V vectors
8821261fn isSpvVector(cg: *CodeGen, ty: Type) bool {
883 const zcu = cg.module.zcu;
884 const target = cg.module.zcu.getTarget();
1262 const zcu = cg.zcu;
1263 const target = cg.zcu.getTarget();
8851264 if (ty.zigTypeTag(zcu) != .vector) return false;
8861265
8871266 // TODO: This check must be expanded for types that can be represented
......@@ -909,23 +1288,34 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {
9091288
9101289/// Emits a bool constant in a particular representation.
9111290fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {
912 return switch (repr) {
913 .indirect => cg.constInt(.u1, @intFromBool(value)),
914 .direct => cg.module.constBool(value),
915 };
1291 switch (repr) {
1292 .indirect => return cg.constInt(.u1, @intFromBool(value)),
1293 .direct => {
1294 const result_ty_id = try cg.boolType();
1295 const result_id = cg.allocId();
1296 switch (value) {
1297 inline else => |value_ct| try cg.sections.globals.emit(
1298 cg.gpa,
1299 if (value_ct) .OpConstantTrue else .OpConstantFalse,
1300 .{ .id_result_type = result_ty_id, .id_result = result_id },
1301 ),
1302 }
1303 return result_id;
1304 },
1305 }
9161306}
9171307
9181308/// Emits an integer constant.
919/// This function, unlike Module.constInt, takes care to bitcast
1309/// This function, unlike cg.constInt, takes care to bitcast
9201310/// the value to an unsigned int first for Kernels.
9211311fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
922 const gpa = cg.module.gpa;
923 const zcu = cg.module.zcu;
924 const target = cg.module.zcu.getTarget();
1312 const gpa = cg.gpa;
1313 const zcu = cg.zcu;
1314 const target = cg.zcu.getTarget();
9251315 const scalar_ty = ty.scalarType(zcu);
9261316 const int_info = scalar_ty.intInfo(zcu);
9271317 // Use backing bits so that negatives are sign extended
928 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
1318 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
9291319 assert(backing_bits != 0); // u0 is comptime
9301320
9311321 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);
......@@ -939,7 +1329,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
9391329 .signed => @bitCast(@as(i64, @intCast(value))),
9401330 .unsigned => @as(u64, @intCast(value)),
9411331 };
942 const n_limbs = backing_bits / Module.big_int_bits;
1332 const n_limbs = backing_bits / big_int_bits;
9431333 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;
9441334 const scratch_top = cg.id_scratch.items.len;
9451335 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
......@@ -979,61 +1369,45 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
9791369 },
9801370 };
9811371
982 const result_id = try cg.module.constant(result_ty_id, final_value);
1372 const result_id = cg.allocId();
1373 try cg.sections.globals.emit(cg.gpa, .OpConstant, .{
1374 .id_result_type = result_ty_id,
1375 .id_result = result_id,
1376 .value = final_value,
1377 });
9831378
9841379 if (!ty.isVector(zcu)) return result_id;
9851380 return cg.constructCompositeSplat(ty, result_id);
9861381}
9871382
988fn constIntBig(cg: *CodeGen, ty: Type, val: Value) !Id {
989 const gpa = cg.module.gpa;
990 const zcu = cg.module.zcu;
991 const int_info = ty.intInfo(zcu);
992 const backing_bits, _ = cg.module.backingIntBits(int_info.bits);
993 const n_limbs = backing_bits / Module.big_int_bits;
994 const result_ty_id = try cg.resolveType(ty, .indirect);
995
996 var bigint_space: Value.BigIntSpace = undefined;
997 const bigint = val.toBigInt(&bigint_space, zcu);
998
999 const limb_values = try gpa.alloc(u32, n_limbs);
1000 defer gpa.free(limb_values);
1001
1002 const bytes = std.mem.sliceAsBytes(limb_values);
1003 bigint.writeTwosComplement(bytes, .little);
1004 if (builtin.cpu.arch.endian() == .big) {
1005 for (limb_values) |*limb| limb.* = @byteSwap(limb.*);
1006 }
1007
1008 const scratch_top = cg.id_scratch.items.len;
1009 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
1010 const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
1011 for (constituents, 0..) |*c, i| {
1012 c.* = try cg.constInt(.u32, limb_values[i]);
1013 }
1014 return cg.constructComposite(result_ty_id, constituents);
1015}
1016
10171383/// Construct a composite value from its constituents.
10181384/// In logical addressing mode (Vulkan/OpenGL), OpCompositeConstruct cannot accept
10191385/// pointer operands, so for struct types we use alloc, store for each field and load instead.
10201386pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id {
1021 const gpa = cg.module.gpa;
1387 const gpa = cg.gpa;
10221388
1023 if (cg.module.structFields(result_ty_id)) |fields| {
1389 const maybe_fields: ?[]const Id = for (cg.struct_types.keys(), cg.struct_types.values()) |key, val| {
1390 if (val == result_ty_id) break key.fields;
1391 } else null;
1392 if (maybe_fields) |fields| {
10241393 assert(fields.len == constituents.len);
1025 const u32_ty_id = try cg.module.intType(.unsigned, 32);
1394 const u32_ty_id = try cg.intType(.unsigned, 32);
10261395 const var_id = try cg.alloc(result_ty_id, null);
10271396 for (fields, constituents, 0..) |field_ty_id, constituent, i| {
1028 const field_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);
1029 const index_id = try cg.module.constant(u32_ty_id, .{ .uint32 = @intCast(i) });
1397 const field_ptr_ty_id = try cg.ptrType(field_ty_id, .function);
1398 const index_id = cg.allocId();
1399 try cg.sections.globals.emit(gpa, .OpConstant, .{
1400 .id_result_type = u32_ty_id,
1401 .id_result = index_id,
1402 .value = .{ .uint32 = @intCast(i) },
1403 });
10301404 const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id});
10311405 try cg.body.emit(gpa, .OpStore, .{
10321406 .pointer = field_ptr,
10331407 .object = constituent,
10341408 });
10351409 }
1036 const result_id = cg.module.allocId();
1410 const result_id = cg.allocId();
10371411 try cg.body.emit(gpa, .OpLoad, .{
10381412 .id_result_type = result_ty_id,
10391413 .id_result = result_id,
......@@ -1042,7 +1416,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
10421416 return result_id;
10431417 }
10441418
1045 const result_id = cg.module.allocId();
1419 const result_id = cg.allocId();
10461420 try cg.body.emit(gpa, .OpCompositeConstruct, .{
10471421 .id_result_type = result_ty_id,
10481422 .id_result = result_id,
......@@ -1054,8 +1428,8 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
10541428/// Construct a composite at runtime with all lanes set to the same value.
10551429/// ty must be an aggregate type.
10561430fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
1057 const gpa = cg.module.gpa;
1058 const zcu = cg.module.zcu;
1431 const gpa = cg.gpa;
1432 const zcu = cg.zcu;
10591433 const n: usize = @intCast(ty.arrayLen(zcu));
10601434
10611435 const scratch_top = cg.id_scratch.items.len;
......@@ -1075,24 +1449,17 @@ fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
10751449//
10761450/// This function should only be called during function code generation.
10771451fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1078 const gpa = cg.module.gpa;
1079
1080 // Note: Using intern_map can only be used with constants that DO NOT generate any runtime code!!
1081 // Ideally that should be all constants in the future, or it should be cleaned up somehow. For
1082 // now, only use the intern_map on case-by-case basis by breaking to :cache.
1083 if (cg.module.intern_map.get(.{ val.toIntern(), repr })) |id| {
1084 return id;
1085 }
1452 const gpa = cg.gpa;
10861453
10871454 const pt = cg.pt;
1088 const zcu = cg.module.zcu;
1089 const target = cg.module.zcu.getTarget();
1455 const zcu = cg.zcu;
1456 const target = cg.zcu.getTarget();
10901457 const result_ty_id = try cg.resolveType(ty, repr);
10911458 const ip = &zcu.intern_pool;
10921459
10931460 log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });
10941461 if (val.isUndef(zcu)) {
1095 return cg.module.constUndef(result_ty_id);
1462 return cg.constUndef(result_ty_id);
10961463 }
10971464
10981465 const cacheable_id = cache: {
......@@ -1133,9 +1500,25 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
11331500 },
11341501 .int => {
11351502 const int_info = ty.intInfo(zcu);
1136 _, const is_big_int = cg.module.backingIntBits(int_info.bits);
1503 const backing_bits, const is_big_int = cg.backingIntBits(int_info.bits);
11371504 if (is_big_int) {
1138 break :cache try cg.constIntBig(ty, val);
1505 const n_limbs = backing_bits / big_int_bits;
1506 const big_result_ty_id = try cg.resolveType(ty, .indirect);
1507 var bigint_space: Value.BigIntSpace = undefined;
1508 const bigint = val.toBigInt(&bigint_space, zcu);
1509 const limb_values = try gpa.alloc(u32, n_limbs);
1510 defer gpa.free(limb_values);
1511 bigint.writeTwosComplement(std.mem.sliceAsBytes(limb_values), .little);
1512 if (builtin.cpu.arch.endian() == .big) {
1513 for (limb_values) |*limb| limb.* = @byteSwap(limb.*);
1514 }
1515 const scratch_top = cg.id_scratch.items.len;
1516 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
1517 const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
1518 for (constituents, 0..) |*c, i| {
1519 c.* = try cg.constInt(.u32, limb_values[i]);
1520 }
1521 break :cache try cg.constructComposite(big_result_ty_id, constituents);
11391522 }
11401523 if (ty.isSignedInt(zcu)) {
11411524 break :cache try cg.constInt(ty, val.toSignedInt(zcu));
......@@ -1151,7 +1534,13 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
11511534 80, 128 => unreachable, // TODO
11521535 else => unreachable,
11531536 };
1154 break :cache try cg.module.constant(result_ty_id, lit);
1537 const lit_id = cg.allocId();
1538 try cg.sections.globals.emit(gpa, .OpConstant, .{
1539 .id_result_type = result_ty_id,
1540 .id_result = lit_id,
1541 .value = lit,
1542 });
1543 break :cache lit_id;
11551544 },
11561545 .err => |err| {
11571546 const value = try pt.getErrorValue(err.name);
......@@ -1218,7 +1607,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
12181607 if (maybe_payload_val) |payload_val| {
12191608 return try cg.constant(payload_ty, payload_val, .indirect);
12201609 } else {
1221 break :cache try cg.module.constNull(result_ty_id);
1610 break :cache try cg.constNull(result_ty_id);
12221611 }
12231612 }
12241613
......@@ -1229,7 +1618,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
12291618 const payload_id = if (maybe_payload_val) |payload_val|
12301619 try cg.constant(payload_ty, payload_val, .indirect)
12311620 else
1232 try cg.module.constUndef(try cg.resolveType(payload_ty, .indirect));
1621 try cg.constUndef(try cg.resolveType(payload_ty, .indirect));
12331622
12341623 const comp_ty_id = try cg.resolveType(ty, .direct);
12351624 return try cg.constructComposite(comp_ty_id, &.{ payload_id, has_pl_id });
......@@ -1339,21 +1728,18 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
13391728 .memoized_call => unreachable,
13401729 }
13411730 };
1342
1343 try cg.module.intern_map.putNoClobber(gpa, .{ val.toIntern(), repr }, cacheable_id);
1344
13451731 return cacheable_id;
13461732}
13471733
13481734fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
13491735 const pt = cg.pt;
1350 const zcu = cg.module.zcu;
1351 const gpa = cg.module.gpa;
1736 const zcu = cg.zcu;
1737 const gpa = cg.gpa;
13521738
13531739 if (ptr_val.isUndef(zcu)) {
13541740 const result_ty = ptr_val.typeOf(zcu);
13551741 const result_ty_id = try cg.resolveType(result_ty, .direct);
1356 return cg.module.constUndef(result_ty_id);
1742 return cg.constUndef(result_ty_id);
13571743 }
13581744
13591745 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -1364,9 +1750,9 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
13641750}
13651751
13661752fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1367 const gpa = cg.module.gpa;
1753 const gpa = cg.gpa;
13681754 const pt = cg.pt;
1369 const zcu = cg.module.zcu;
1755 const zcu = cg.zcu;
13701756 const target = zcu.getTarget();
13711757 switch (derivation) {
13721758 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
......@@ -1383,7 +1769,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
13831769 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
13841770 // that is not implemented by Mesa yet. Therefore, just generate it
13851771 // as a runtime operation.
1386 const result_ptr_id = cg.module.allocId();
1772 const result_ptr_id = cg.allocId();
13871773 const value_id = try cg.constInt(.usize, int.addr);
13881774 try cg.body.emit(gpa, .OpConvertUToPtr, .{
13891775 .id_result_type = result_ty_id,
......@@ -1392,13 +1778,83 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
13921778 });
13931779 return result_ptr_id;
13941780 },
1395 .nav_ptr => |nav| {
1396 const result_ptr_ty = try pt.navPtrType(nav);
1397 return cg.constantNavRef(result_ptr_ty, nav);
1781 .nav_ptr => |nav_index| {
1782 const ip = &zcu.intern_pool;
1783 const result_ptr_ty = try pt.navPtrType(nav_index);
1784 const ty_id = try cg.resolveType(result_ptr_ty, .direct);
1785 const nav = ip.getNav(nav_index);
1786 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
1787
1788 switch (nav.resolved.?.value) {
1789 .none => {},
1790 else => |value| switch (ip.indexToKey(value)) {
1791 // TODO: Properly lower function pointers; for now substitute undef.
1792 .func => return try cg.constUndef(ty_id),
1793 .@"extern" => if (ip.isFunctionType(nav_ty.toIntern())) {
1794 const spv_decl_index = try cg.resolveNav(ip, nav_index);
1795 const decl = cg.declPtr(spv_decl_index);
1796 try emitExternFnStub(cg, nav, decl, nav_ty);
1797 return decl.result_id;
1798 },
1799 else => {},
1800 },
1801 }
1802
1803 if (!nav_ty.hasRuntimeBits(zcu)) return cg.constUndef(ty_id);
1804
1805 const spv_decl_index = try cg.resolveNav(ip, nav_index);
1806 const spv_decl = cg.declPtr(spv_decl_index);
1807 assert(spv_decl.kind != .func);
1808 const storage_class = cg.storageClass(nav.resolved.?.@"addrspace");
1809 try cg.addFunctionDep(spv_decl_index, storage_class);
1810
1811 const nav_ty_id = try cg.resolveType(nav_ty, .indirect);
1812 const decl_ptr_ty_id = try cg.ptrType(nav_ty_id, storage_class);
1813 if (decl_ptr_ty_id == ty_id) return spv_decl.result_id;
1814 switch (target.os.tag) {
1815 .vulkan, .opengl => return spv_decl.result_id,
1816 else => {},
1817 }
1818 const casted_ptr_id = cg.allocId();
1819 try cg.body.emit(gpa, .OpBitcast, .{
1820 .id_result_type = ty_id,
1821 .id_result = casted_ptr_id,
1822 .operand = spv_decl.result_id,
1823 });
1824 return casted_ptr_id;
13981825 },
13991826 .uav_ptr => |uav| {
1827 const ip = &zcu.intern_pool;
14001828 const result_ptr_ty: Type = .fromInterned(uav.orig_ty);
1401 return cg.constantUavRef(result_ptr_ty, uav);
1829 const ty_id = try cg.resolveType(result_ptr_ty, .direct);
1830 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
1831
1832 switch (ip.indexToKey(uav.val)) {
1833 .func => unreachable, // TODO
1834 .@"extern" => assert(!ip.isFunctionType(uav_ty.toIntern())),
1835 else => {},
1836 }
1837
1838 if (!uav_ty.hasRuntimeBits(zcu)) return cg.constUndef(ty_id);
1839
1840 // Uav refs are always generic.
1841 assert(result_ptr_ty.ptrAddressSpace(zcu) == .generic);
1842 const uav_ty_id = try cg.resolveType(uav_ty, .indirect);
1843 const decl_ptr_ty_id = try cg.ptrType(uav_ty_id, .function);
1844 const ptr_id = try cg.resolveUav(uav.val);
1845
1846 if (decl_ptr_ty_id == ty_id) return ptr_id;
1847 switch (target.os.tag) {
1848 .vulkan, .opengl => return ptr_id,
1849 else => {},
1850 }
1851 const casted_ptr_id = cg.allocId();
1852 try cg.body.emit(gpa, .OpBitcast, .{
1853 .id_result_type = ty_id,
1854 .id_result = casted_ptr_id,
1855 .operand = ptr_id,
1856 });
1857 return casted_ptr_id;
14021858 },
14031859 .eu_payload_ptr => @panic("TODO"),
14041860 .opt_payload_ptr => @panic("TODO"),
......@@ -1450,7 +1906,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
14501906 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);
14511907 }
14521908 if (target.os.tag == .opencl) {
1453 const result_ptr_id = cg.module.allocId();
1909 const result_ptr_id = cg.allocId();
14541910 try cg.body.emit(gpa, .OpBitcast, .{
14551911 .id_result_type = result_ty_id,
14561912 .id_result = result_ptr_id,
......@@ -1468,59 +1924,15 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
14681924 }
14691925}
14701926
1471fn constantUavRef(
1472 cg: *CodeGen,
1473 ty: Type,
1474 uav: InternPool.Key.Ptr.BaseAddr.Uav,
1475) !Id {
1476 // TODO: Merge this function with constantDeclRef.
1477
1478 const zcu = cg.module.zcu;
1479 const ip = &zcu.intern_pool;
1480 const ty_id = try cg.resolveType(ty, .direct);
1481 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
1482
1483 switch (ip.indexToKey(uav.val)) {
1484 .func => unreachable, // TODO
1485 .@"extern" => assert(!ip.isFunctionType(uav_ty.toIntern())),
1486 else => {},
1487 }
1488
1489 // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn";
1490 if (!uav_ty.hasRuntimeBits(zcu)) {
1491 // Pointer to nothing - return undefined
1492 return cg.module.constUndef(ty_id);
1493 }
1494
1495 // Uav refs are always generic.
1496 assert(ty.ptrAddressSpace(zcu) == .generic);
1497 const uav_ty_id = try cg.resolveType(uav_ty, .indirect);
1498 const decl_ptr_ty_id = try cg.module.ptrType(uav_ty_id, .function);
1499 const ptr_id = try cg.resolveUav(uav.val);
1500
1501 if (decl_ptr_ty_id != ty_id) {
1502 // Differing pointer types, insert a cast.
1503 const casted_ptr_id = cg.module.allocId();
1504 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
1505 .id_result_type = ty_id,
1506 .id_result = casted_ptr_id,
1507 .operand = ptr_id,
1508 });
1509 return casted_ptr_id;
1510 } else {
1511 return ptr_id;
1512 }
1513}
1514
15151927/// Emit a stub OpFunction/OpFunctionEnd + Import linkage decoration for an
15161928/// extern function so the module is structurally valid. The stub will be
15171929/// replaced by the real definition at link time.
1518fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Module.Decl, fn_ty: Type) !void {
1930fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Decl, fn_ty: Type) !void {
15191931 if (decl.has_extern_stub) return;
15201932 decl.has_extern_stub = true;
15211933
1522 const gpa = cg.module.gpa;
1523 const zcu = cg.module.zcu;
1934 const gpa = cg.gpa;
1935 const zcu = cg.zcu;
15241936 const ip = &zcu.intern_pool;
15251937 const fn_info = zcu.typeToFunc(fn_ty).?;
15261938 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
......@@ -1540,81 +1952,25 @@ fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Module.Decl, fn_ty
15401952 const param_type_id = try cg.resolveType(param_ty, .direct);
15411953 try stub.emit(gpa, .OpFunctionParameter, .{
15421954 .id_result_type = param_type_id,
1543 .id_result = cg.module.allocId(),
1955 .id_result = cg.allocId(),
15441956 });
15451957 }
15461958 try stub.emit(gpa, .OpFunctionEnd, {});
1547 try cg.module.sections.functions.append(gpa, stub);
1959 try cg.sections.functions.append(gpa, stub);
15481960
15491961 const extern_name = nav.getExtern(ip).?.name.toSlice(ip);
1550 try cg.module.sections.annotations.emit(gpa, .OpDecorate, .{
1962 try cg.sections.annotations.emit(gpa, .OpDecorate, .{
15511963 .target = decl.result_id,
15521964 .decoration = .{ .linkage_attributes = .{
15531965 .name = extern_name,
15541966 .linkage_type = .import,
15551967 } },
15561968 });
1557 try cg.module.debugName(decl.result_id, extern_name);
1558}
1559
1560fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
1561 const zcu = cg.module.zcu;
1562 const ip = &zcu.intern_pool;
1563 const ty_id = try cg.resolveType(ty, .direct);
1564 const nav = ip.getNav(nav_index);
1565 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
1566
1567 switch (nav.resolved.?.value) {
1568 .none => {}, // this is not a function or extern
1569 else => |value| switch (ip.indexToKey(value)) {
1570 .func => {
1571 // TODO: Properly lower function pointers. For now we are going to hack around it and
1572 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
1573 return try cg.module.constUndef(ty_id);
1574 },
1575 .@"extern" => if (ip.isFunctionType(nav_ty.toIntern())) {
1576 const spv_decl_index = try cg.module.resolveNav(ip, nav_index);
1577 const decl = cg.module.declPtr(spv_decl_index);
1578 try emitExternFnStub(cg, nav, decl, nav_ty);
1579 return decl.result_id;
1580 },
1581 else => {},
1582 },
1583 }
1584
1585 if (!nav_ty.hasRuntimeBits(zcu)) {
1586 // Pointer to nothing - return undefined.
1587 return cg.module.constUndef(ty_id);
1588 }
1589
1590 const spv_decl_index = try cg.module.resolveNav(ip, nav_index);
1591 const spv_decl = cg.module.declPtr(spv_decl_index);
1592 const spv_decl_result_id = spv_decl.result_id;
1593 assert(spv_decl.kind != .func);
1594
1595 const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace");
1596 try cg.addFunctionDep(spv_decl_index, storage_class);
1597
1598 const nav_ty_id = try cg.resolveType(nav_ty, .indirect);
1599 const decl_ptr_ty_id = try cg.module.ptrType(nav_ty_id, storage_class);
1600
1601 if (decl_ptr_ty_id != ty_id) {
1602 // Differing pointer types, insert a cast.
1603 const casted_ptr_id = cg.module.allocId();
1604 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
1605 .id_result_type = ty_id,
1606 .id_result = casted_ptr_id,
1607 .operand = spv_decl_result_id,
1608 });
1609 return casted_ptr_id;
1610 }
1611
1612 return spv_decl_result_id;
1969 try cg.debugName(decl.result_id, extern_name);
16131970}
16141971
1615// Turn a Zig type's name into a cache reference.
16161972fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1617 const gpa = cg.module.gpa;
1973 const gpa = cg.gpa;
16181974 var aw: std.Io.Writer.Allocating = .init(gpa);
16191975 defer aw.deinit();
16201976 ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) {
......@@ -1641,67 +1997,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
16411997/// padding: [padding_size]u8,
16421998/// }
16431999/// If any of the fields' size is 0, it will be omitted.
1644fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
1645 const gpa = cg.module.gpa;
1646 const zcu = cg.module.zcu;
1647 const union_obj = zcu.typeToUnion(ty).?;
1648
1649 if (union_obj.layout == .@"packed") {
1650 return try cg.module.intType(.unsigned, @intCast(ty.bitSize(zcu)));
1651 }
1652
1653 const layout = cg.unionLayout(ty);
1654 if (!layout.has_payload) {
1655 // No payload, so represent this as just the tag type.
1656 return try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
1657 }
1658
1659 var member_types: [4]Id = undefined;
1660 var member_names: [4][]const u8 = undefined;
1661
1662 const u8_ty_id = try cg.resolveType(.u8, .direct);
1663
1664 if (layout.tag_size != 0) {
1665 const tag_ty_id = try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
1666 member_types[layout.tag_index] = tag_ty_id;
1667 member_names[layout.tag_index] = "(tag)";
1668 }
1669
1670 if (layout.payload_size != 0) {
1671 const payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
1672 member_types[layout.payload_index] = payload_ty_id;
1673 member_names[layout.payload_index] = "(payload)";
1674 }
1675
1676 if (layout.payload_padding_size != 0) {
1677 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
1678 const payload_padding_ty_id = try cg.module.arrayType(len_id, u8_ty_id);
1679 member_types[layout.payload_padding_index] = payload_padding_ty_id;
1680 member_names[layout.payload_padding_index] = "(payload padding)";
1681 }
1682
1683 if (layout.padding_size != 0) {
1684 const len_id = try cg.constInt(.u32, layout.padding_size);
1685 const padding_ty_id = try cg.module.arrayType(len_id, u8_ty_id);
1686 member_types[layout.padding_index] = padding_ty_id;
1687 member_names[layout.padding_index] = "(padding)";
1688 }
1689
1690 const result_id = try cg.module.structType(
1691 member_types[0..layout.total_fields],
1692 member_names[0..layout.total_fields],
1693 .none,
1694 );
1695
1696 const type_name = try cg.resolveTypeName(ty);
1697 defer gpa.free(type_name);
1698 try cg.module.debugName(result_id, type_name);
1699
1700 return result_id;
1701}
1702
17032000fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1704 const zcu = cg.module.zcu;
2001 const zcu = cg.zcu;
17052002 if (!ret_ty.hasRuntimeBits(zcu)) {
17062003 // If the return type is an error set or an error union, then we make this
17072004 // anyerror return type instead, so that it can be coerced into a function
......@@ -1717,38 +2014,38 @@ fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
17172014}
17182015
17192016fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1720 const gpa = cg.module.gpa;
2017 const gpa = cg.gpa;
17212018 const pt = cg.pt;
1722 const zcu = cg.module.zcu;
2019 const zcu = cg.zcu;
17232020 const ip = &zcu.intern_pool;
1724 const target = cg.module.zcu.getTarget();
2021 const target = cg.zcu.getTarget();
17252022
17262023 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});
17272024
17282025 switch (ty.zigTypeTag(zcu)) {
17292026 .noreturn => {
17302027 assert(repr == .direct);
1731 return try cg.module.voidType();
2028 return try cg.voidType();
17322029 },
17332030 .void => switch (repr) {
1734 .direct => return try cg.module.voidType(),
2031 .direct => return try cg.voidType(),
17352032 .indirect => {
17362033 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1737 return try cg.module.opaqueType("void");
2034 return try cg.opaqueType("void");
17382035 },
17392036 },
17402037 .bool => switch (repr) {
1741 .direct => return try cg.module.boolType(),
2038 .direct => return try cg.boolType(),
17422039 .indirect => return try cg.resolveType(.u1, .indirect),
17432040 },
17442041 .int => {
17452042 if (ty.toIntern() == .u0_type) {
17462043 assert(repr == .indirect);
17472044 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1748 return try cg.module.opaqueType("u0");
2045 return try cg.opaqueType("u0");
17492046 }
17502047 const int_info = ty.intInfo(zcu);
1751 return try cg.module.intType(int_info.signedness, int_info.bits);
2048 return try cg.intType(int_info.signedness, int_info.bits);
17522049 },
17532050 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
17542051 .float => {
......@@ -1767,7 +2064,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
17672064 );
17682065 }
17692066
1770 return try cg.module.floatType(bits);
2067 return try cg.floatType(bits);
17712068 },
17722069 .array => {
17732070 const elem_ty = ty.childType(zcu);
......@@ -1779,7 +2076,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
17792076 if (!elem_ty.hasRuntimeBits(zcu)) {
17802077 assert(repr == .indirect);
17812078 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1782 return try cg.module.opaqueType("zero-sized-array");
2079 return try cg.opaqueType("zero-sized-array");
17832080 } else if (total_len == 0) {
17842081 // The size of the array would be 0, but that is not allowed in SPIR-V.
17852082 // This path can be reached for example when there is a slicing of a pointer
......@@ -1790,25 +2087,24 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
17902087 // generate an array of 1 element instead, so that ptr_elem_ptr instructions
17912088 // can be lowered to ptrAccessChain instead of manually performing the math.
17922089 const len_id = try cg.constInt(.u32, 1);
1793 return try cg.module.arrayType(len_id, elem_ty_id);
2090 return try cg.arrayType(len_id, elem_ty_id);
17942091 } else {
17952092 const total_len_id = try cg.constInt(.u32, total_len);
1796 return try cg.module.arrayType(total_len_id, elem_ty_id);
2093 return try cg.arrayType(total_len_id, elem_ty_id);
17972094 }
17982095 },
17992096 .vector => {
18002097 const elem_ty = ty.childType(zcu);
18012098 const elem_ty_id = try cg.resolveType(elem_ty, repr);
18022099 const len = ty.vectorLen(zcu);
1803 if (cg.isSpvVector(ty)) return try cg.module.vectorType(len, elem_ty_id);
2100 if (cg.isSpvVector(ty)) return try cg.vectorType(len, elem_ty_id);
18042101 const len_id = try cg.constInt(.u32, len);
1805 return try cg.module.arrayType(len_id, elem_ty_id);
2102 return try cg.arrayType(len_id, elem_ty_id);
18062103 },
18072104 .@"fn" => switch (repr) {
18082105 .direct => {
18092106 const fn_info = zcu.typeToFunc(ty).?;
18102107
1811 comptime assert(zig_call_abi_ver == 3);
18122108 assert(!fn_info.is_var_args);
18132109 switch (fn_info.cc) {
18142110 .auto,
......@@ -1837,7 +2133,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
18372133 param_index += 1;
18382134 }
18392135
1840 return try cg.module.functionType(return_ty_id, param_ty_ids[0..param_index]);
2136 return try cg.functionType(return_ty_id, param_ty_ids[0..param_index]);
18412137 },
18422138 .indirect => {
18432139 // TODO: Represent function pointers properly.
......@@ -1860,15 +2156,15 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
18602156 },
18612157 };
18622158 const child_ty_id = try cg.resolveType(child_ty, .indirect);
1863 const storage_class = cg.module.storageClass(ptr_info.flags.address_space);
1864 const ptr_ty_id = try cg.module.ptrType(child_ty_id, storage_class);
2159 const storage_class = cg.storageClass(ptr_info.flags.address_space);
2160 const ptr_ty_id = try cg.ptrType(child_ty_id, storage_class);
18652161
18662162 if (ptr_info.flags.size != .slice) {
18672163 return ptr_ty_id;
18682164 }
18692165
18702166 const size_ty_id = try cg.resolveType(.usize, .direct);
1871 return try cg.module.structType(
2167 return try cg.structType(
18722168 &.{ ptr_ty_id, size_ty_id },
18732169 &.{ "ptr", "len" },
18742170 .none,
......@@ -1889,14 +2185,14 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
18892185 member_index += 1;
18902186 }
18912187
1892 const result_id = try cg.module.structType(
2188 const result_id = try cg.structType(
18932189 member_types[0..member_index],
18942190 null,
18952191 .none,
18962192 );
18972193 const type_name = try cg.resolveTypeName(ty);
18982194 defer gpa.free(type_name);
1899 try cg.module.debugName(result_id, type_name);
2195 try cg.debugName(result_id, type_name);
19002196 return result_id;
19012197 },
19022198 .struct_type => ip.loadStructType(ty.toIntern()),
......@@ -1923,7 +2219,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19232219 try member_names.append(field_name.toSlice(ip));
19242220 }
19252221
1926 const result_id = try cg.module.structType(
2222 const result_id = try cg.structType(
19272223 member_types.items,
19282224 member_names.items,
19292225 ty.toIntern(),
......@@ -1931,7 +2227,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19312227
19322228 const type_name = try cg.resolveTypeName(ty);
19332229 defer gpa.free(type_name);
1934 try cg.module.debugName(result_id, type_name);
2230 try cg.debugName(result_id, type_name);
19352231
19362232 return result_id;
19372233 },
......@@ -1952,13 +2248,52 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19522248
19532249 const bool_ty_id = try cg.resolveType(.bool, .indirect);
19542250
1955 return try cg.module.structType(
2251 return try cg.structType(
19562252 &.{ payload_ty_id, bool_ty_id },
19572253 &.{ "payload", "valid" },
19582254 .none,
19592255 );
19602256 },
1961 .@"union" => return try cg.resolveUnionType(ty),
2257 .@"union" => {
2258 const union_obj = zcu.typeToUnion(ty).?;
2259 if (union_obj.layout == .@"packed") {
2260 return try cg.intType(.unsigned, @intCast(ty.bitSize(zcu)));
2261 }
2262 const layout = cg.unionLayout(ty);
2263 if (!layout.has_payload) {
2264 return try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
2265 }
2266 var member_types: [4]Id = undefined;
2267 var member_names: [4][]const u8 = undefined;
2268 const u8_ty_id = try cg.resolveType(.u8, .direct);
2269 if (layout.tag_size != 0) {
2270 member_types[layout.tag_index] = try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
2271 member_names[layout.tag_index] = "(tag)";
2272 }
2273 if (layout.payload_size != 0) {
2274 member_types[layout.payload_index] = try cg.resolveType(layout.payload_ty, .indirect);
2275 member_names[layout.payload_index] = "(payload)";
2276 }
2277 if (layout.payload_padding_size != 0) {
2278 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
2279 member_types[layout.payload_padding_index] = try cg.arrayType(len_id, u8_ty_id);
2280 member_names[layout.payload_padding_index] = "(payload padding)";
2281 }
2282 if (layout.padding_size != 0) {
2283 const len_id = try cg.constInt(.u32, layout.padding_size);
2284 member_types[layout.padding_index] = try cg.arrayType(len_id, u8_ty_id);
2285 member_names[layout.padding_index] = "(padding)";
2286 }
2287 const result_id = try cg.structType(
2288 member_types[0..layout.total_fields],
2289 member_names[0..layout.total_fields],
2290 .none,
2291 );
2292 const type_name = try cg.resolveTypeName(ty);
2293 defer gpa.free(type_name);
2294 try cg.debugName(result_id, type_name);
2295 return result_id;
2296 },
19622297 .error_set => {
19632298 const err_int_ty = try pt.errorIntType();
19642299 return try cg.resolveType(err_int_ty, repr);
......@@ -1989,46 +2324,46 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19892324 // TODO: ABI padding?
19902325 }
19912326
1992 return try cg.module.structType(&member_types, &member_names, .none);
2327 return try cg.structType(&member_types, &member_names, .none);
19932328 },
19942329 .@"opaque" => {
19952330 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
19962331 const type_name = try cg.resolveTypeName(ty);
19972332 defer gpa.free(type_name);
1998 return try cg.module.opaqueType(type_name);
2333 return try cg.opaqueType(type_name);
19992334 },
20002335 .spirv => {
2001 const ip_index = ty.toIntern();
2002 const spirv_type = ip.loadSpirvType(ip_index);
2336 const spirv_type = ip.loadSpirvType(ty.toIntern());
2337 const result_id = cg.allocId();
20032338 switch (spirv_type.flags.tag) {
2004 .sampler => return try cg.module.samplerType(ip_index),
2339 .sampler => try cg.sections.globals.emit(gpa, .OpTypeSampler, .{ .id_result = result_id }),
20052340 .image => {
2006 const sampled_type_id = blk: {
2007 if (spirv_type.ty == .none) break :blk try cg.module.intType(.unsigned, 32);
2008 break :blk try cg.resolveType(Type.fromInterned(spirv_type.ty), .direct);
2009 };
2010 return try cg.module.imageType(
2011 ip_index,
2012 sampled_type_id,
2013 switch (spirv_type.flags.dim) {
2341 const sampled_type_id = if (spirv_type.ty == .none)
2342 try cg.intType(.unsigned, 32)
2343 else
2344 try cg.resolveType(Type.fromInterned(spirv_type.ty), .direct);
2345 try cg.sections.globals.emit(gpa, .OpTypeImage, .{
2346 .id_result = result_id,
2347 .sampled_type = sampled_type_id,
2348 .dim = switch (spirv_type.flags.dim) {
20142349 .@"1d" => .@"1d",
20152350 .@"2d" => .@"2d",
20162351 .@"3d" => .@"3d",
20172352 .cube => .cube,
20182353 },
2019 switch (spirv_type.flags.depth) {
2354 .depth = switch (spirv_type.flags.depth) {
20202355 .not_depth => 0,
20212356 .depth => 1,
20222357 .unknown => 2,
20232358 },
2024 @intFromBool(spirv_type.flags.is_arrayed),
2025 @intFromBool(spirv_type.flags.is_multisampled),
2026 switch (spirv_type.flags.usage) {
2359 .arrayed = @intFromBool(spirv_type.flags.is_arrayed),
2360 .ms = @intFromBool(spirv_type.flags.is_multisampled),
2361 .sampled = switch (spirv_type.flags.usage) {
20272362 .unknown => 1,
20282363 .sampled => 1,
20292364 .storage => 2,
20302365 },
2031 switch (spirv_type.flags.format) {
2366 .image_format = switch (spirv_type.flags.format) {
20322367 .unknown => .unknown,
20332368 .rgba32f => .rgba32f,
20342369 .rgba32i => .rgba32i,
......@@ -2044,31 +2379,36 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
20442379 .r32i => .r32i,
20452380 .r32u => .r32ui,
20462381 },
2047 switch (spirv_type.flags.access) {
2382 .access_qualifier = switch (spirv_type.flags.access) {
20482383 .unknown => null,
20492384 .read_only => .read_only,
20502385 .write_only => .write_only,
20512386 .read_write => .read_write,
20522387 },
2053 );
2388 });
20542389 },
20552390 .sampled_image => {
20562391 const image_ty_id = try cg.resolveType(.fromInterned(spirv_type.ty), .indirect);
2057 return try cg.module.sampledImageType(ip_index, image_ty_id);
2392 try cg.sections.globals.emit(gpa, .OpTypeSampledImage, .{
2393 .id_result = result_id,
2394 .image_type = image_ty_id,
2395 });
20582396 },
20592397 .runtime_array => {
20602398 const elem_ty: Type = .fromInterned(spirv_type.ty);
20612399 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
2062 const result_id = try cg.module.runtimeArrayType(ip_index, elem_ty_id);
2063
2400 try cg.sections.globals.emit(gpa, .OpTypeRuntimeArray, .{
2401 .id_result = result_id,
2402 .element_type = elem_ty_id,
2403 });
20642404 if (elem_ty.hasRuntimeBits(zcu)) {
2065 try cg.module.decorate(result_id, .{ .array_stride = .{
2405 try cg.decorate(result_id, .{ .array_stride = .{
20662406 .array_stride = @intCast(elem_ty.abiSize(zcu)),
20672407 } });
20682408 }
2069 return result_id;
20702409 },
20712410 }
2411 return result_id;
20722412 },
20732413
20742414 .null,
......@@ -2099,7 +2439,7 @@ const ErrorUnionLayout = struct {
20992439};
21002440
21012441fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {
2102 const zcu = cg.module.zcu;
2442 const zcu = cg.zcu;
21032443
21042444 const error_align = Type.abiAlignment(.anyerror, zcu);
21052445 const payload_align = payload_ty.abiAlignment(zcu);
......@@ -2130,7 +2470,7 @@ const UnionLayout = struct {
21302470};
21312471
21322472fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {
2133 const zcu = cg.module.zcu;
2473 const zcu = cg.zcu;
21342474 const ip = &zcu.intern_pool;
21352475 const layout = ty.unionGetLayout(zcu);
21362476 const union_obj = zcu.typeToUnion(ty).?;
......@@ -2220,8 +2560,8 @@ const Temporary = struct {
22202560 }
22212561
22222562 fn materialize(temp: Temporary, cg: *CodeGen) !Id {
2223 const gpa = cg.module.gpa;
2224 const zcu = cg.module.zcu;
2563 const gpa = cg.gpa;
2564 const zcu = cg.zcu;
22252565 switch (temp.value) {
22262566 .singleton => |id| return id,
22272567 .exploded_vector => |range| {
......@@ -2255,7 +2595,7 @@ const Temporary = struct {
22552595 /// 'Explode' a temporary into separate elements. This turns a vector
22562596 /// into a bag of elements.
22572597 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {
2258 const zcu = cg.module.zcu;
2598 const zcu = cg.zcu;
22592599
22602600 // If the value is a scalar, then this is a no-op.
22612601 if (!temp.ty.isVector(zcu)) {
......@@ -2267,7 +2607,7 @@ const Temporary = struct {
22672607
22682608 const ty_id = try cg.resolveType(temp.ty.scalarType(zcu), .direct);
22692609 const n = temp.ty.vectorLen(zcu);
2270 const results = cg.module.allocIds(n);
2610 const results = cg.allocIds(n);
22712611
22722612 const id = switch (temp.value) {
22732613 .singleton => |id| id,
......@@ -2276,7 +2616,7 @@ const Temporary = struct {
22762616
22772617 for (0..n) |i| {
22782618 const indexes = [_]u32{@intCast(i)};
2279 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
2619 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
22802620 .id_result_type = ty_id,
22812621 .id_result = results.at(i),
22822622 .composite = id,
......@@ -2296,12 +2636,12 @@ const CompositeInt = struct {
22962636 info: ArithmeticTypeInfo,
22972637
22982638 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {
2299 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;
2300 const gpa = cg.module.gpa;
2639 const n_limbs: u16 = info.backing_bits / big_int_bits;
2640 const gpa = cg.gpa;
23012641 const u32_ty_id = try cg.resolveType(.u32, .direct);
23022642 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
23032643 for (limbs, 0..) |*limb, i| {
2304 const result_id = cg.module.allocId();
2644 const result_id = cg.allocId();
23052645 try cg.body.emit(gpa, .OpCompositeExtract, .{
23062646 .id_result_type = u32_ty_id,
23072647 .id_result = result_id,
......@@ -2323,8 +2663,8 @@ const CompositeInt = struct {
23232663 }
23242664
23252665 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {
2326 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;
2327 const limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, n_limbs);
2666 const n_limbs: u16 = info.backing_bits / big_int_bits;
2667 const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs);
23282668 const zero_id = try cg.constInt(.u32, @as(u32, 0));
23292669 for (limbs) |*limb| limb.* = zero_id;
23302670 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
......@@ -2337,9 +2677,9 @@ const CompositeInt = struct {
23372677
23382678 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {
23392679 const cg = ci.cg;
2340 const gpa = cg.module.gpa;
2680 const gpa = cg.gpa;
23412681 const u32_ty_id = try cg.resolveType(.u32, .direct);
2342 const result_id = cg.module.allocId();
2682 const result_id = cg.allocId();
23432683 try cg.body.emitRaw(gpa, opcode, 4);
23442684 cg.body.writeOperand(Id, u32_ty_id);
23452685 cg.body.writeOperand(Id, result_id);
......@@ -2350,9 +2690,9 @@ const CompositeInt = struct {
23502690
23512691 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {
23522692 const cg = ci.cg;
2353 const gpa = cg.module.gpa;
2693 const gpa = cg.gpa;
23542694 const u32_ty_id = try cg.resolveType(.u32, .direct);
2355 const result_id = cg.module.allocId();
2695 const result_id = cg.allocId();
23562696 try cg.body.emitRaw(gpa, opcode, 3);
23572697 cg.body.writeOperand(Id, u32_ty_id);
23582698 cg.body.writeOperand(Id, result_id);
......@@ -2362,7 +2702,7 @@ const CompositeInt = struct {
23622702
23632703 fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt {
23642704 const cg = ci.cg;
2365 const gpa = cg.module.gpa;
2705 const gpa = cg.gpa;
23662706 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
23672707 for (result_limbs, 0..) |*r, i| {
23682708 r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]);
......@@ -2372,7 +2712,7 @@ const CompositeInt = struct {
23722712
23732713 fn bitwiseNot(ci: CompositeInt) !CompositeInt {
23742714 const cg = ci.cg;
2375 const gpa = cg.module.gpa;
2715 const gpa = cg.gpa;
23762716 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
23772717 for (result_limbs, 0..) |*r, i| {
23782718 r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]);
......@@ -2382,41 +2722,45 @@ const CompositeInt = struct {
23822722
23832723 fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id {
23842724 const cg = ci.cg;
2385 const gpa = cg.module.gpa;
2725 const gpa = cg.gpa;
23862726 const bool_ty_id = try cg.resolveType(.bool, .direct);
23872727
23882728 switch (op) {
23892729 .eq, .neq => {
23902730 var result = blk: {
2391 const r = cg.module.allocId();
2392 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2393 cg.body.writeOperand(Id, bool_ty_id);
2394 cg.body.writeOperand(Id, r);
2395 cg.body.writeOperand(Id, ci.limbs[0]);
2396 cg.body.writeOperand(Id, other.limbs[0]);
2731 const r = cg.allocId();
2732 try cg.body.emit(gpa, .OpIEqual, .{
2733 .id_result_type = bool_ty_id,
2734 .id_result = r,
2735 .operand_1 = ci.limbs[0],
2736 .operand_2 = other.limbs[0],
2737 });
23972738 break :blk r;
23982739 };
23992740 for (1..ci.n_limbs) |i| {
2400 const limb_eq = cg.module.allocId();
2401 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2402 cg.body.writeOperand(Id, bool_ty_id);
2403 cg.body.writeOperand(Id, limb_eq);
2404 cg.body.writeOperand(Id, ci.limbs[i]);
2405 cg.body.writeOperand(Id, other.limbs[i]);
2406 const combined = cg.module.allocId();
2407 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
2408 cg.body.writeOperand(Id, bool_ty_id);
2409 cg.body.writeOperand(Id, combined);
2410 cg.body.writeOperand(Id, result);
2411 cg.body.writeOperand(Id, limb_eq);
2741 const limb_eq = cg.allocId();
2742 try cg.body.emit(gpa, .OpIEqual, .{
2743 .id_result_type = bool_ty_id,
2744 .id_result = limb_eq,
2745 .operand_1 = ci.limbs[i],
2746 .operand_2 = other.limbs[i],
2747 });
2748 const combined = cg.allocId();
2749 try cg.body.emit(gpa, .OpLogicalAnd, .{
2750 .id_result_type = bool_ty_id,
2751 .id_result = combined,
2752 .operand_1 = result,
2753 .operand_2 = limb_eq,
2754 });
24122755 result = combined;
24132756 }
24142757 if (op == .neq) {
2415 const negated = cg.module.allocId();
2416 try cg.body.emitRaw(gpa, .OpLogicalNot, 3);
2417 cg.body.writeOperand(Id, bool_ty_id);
2418 cg.body.writeOperand(Id, negated);
2419 cg.body.writeOperand(Id, result);
2758 const negated = cg.allocId();
2759 try cg.body.emit(gpa, .OpLogicalNot, .{
2760 .id_result_type = bool_ty_id,
2761 .id_result = negated,
2762 .operand = result,
2763 });
24202764 result = negated;
24212765 }
24222766 return result;
......@@ -2429,12 +2773,13 @@ const CompositeInt = struct {
24292773 for (0..ci.n_limbs) |i| {
24302774 const l = ci.limbs[i];
24312775 const r = other.limbs[i];
2432 const limb_ne = cg.module.allocId();
2433 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
2434 cg.body.writeOperand(Id, bool_ty_id);
2435 cg.body.writeOperand(Id, limb_ne);
2436 cg.body.writeOperand(Id, l);
2437 cg.body.writeOperand(Id, r);
2776 const limb_ne = cg.allocId();
2777 try cg.body.emit(gpa, .OpINotEqual, .{
2778 .id_result_type = bool_ty_id,
2779 .id_result = limb_ne,
2780 .operand_1 = l,
2781 .operand_2 = r,
2782 });
24382783
24392784 const is_top = (i == ci.n_limbs - 1);
24402785 const use_signed = is_top and ci.info.signedness == .signed;
......@@ -2442,13 +2787,13 @@ const CompositeInt = struct {
24422787 var cmp_r = r;
24432788 if (use_signed) {
24442789 const i32_ty_id = try cg.resolveType(.i32, .direct);
2445 const sl = cg.module.allocId();
2790 const sl = cg.allocId();
24462791 try cg.body.emit(gpa, .OpBitcast, .{
24472792 .id_result_type = i32_ty_id,
24482793 .id_result = sl,
24492794 .operand = l,
24502795 });
2451 const sr = cg.module.allocId();
2796 const sr = cg.allocId();
24522797 try cg.body.emit(gpa, .OpBitcast, .{
24532798 .id_result_type = i32_ty_id,
24542799 .id_result = sr,
......@@ -2463,14 +2808,14 @@ const CompositeInt = struct {
24632808 else
24642809 (if (use_signed) .OpSGreaterThan else .OpUGreaterThan);
24652810
2466 const limb_cmp = cg.module.allocId();
2811 const limb_cmp = cg.allocId();
24672812 try cg.body.emitRaw(gpa, cmp_opcode, 4);
24682813 cg.body.writeOperand(Id, bool_ty_id);
24692814 cg.body.writeOperand(Id, limb_cmp);
24702815 cg.body.writeOperand(Id, cmp_l);
24712816 cg.body.writeOperand(Id, cmp_r);
24722817
2473 const selected = cg.module.allocId();
2818 const selected = cg.allocId();
24742819 try cg.body.emit(gpa, .OpSelect, .{
24752820 .id_result_type = bool_ty_id,
24762821 .id_result = selected,
......@@ -2487,9 +2832,9 @@ const CompositeInt = struct {
24872832
24882833 fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt {
24892834 const cg = ci.cg;
2490 const gpa = cg.module.gpa;
2835 const gpa = cg.gpa;
24912836 const pt = cg.pt;
2492 const zcu = cg.module.zcu;
2837 const zcu = cg.zcu;
24932838 const ip = &zcu.intern_pool;
24942839 const comp = zcu.comp;
24952840 const io = comp.io;
......@@ -2508,21 +2853,21 @@ const CompositeInt = struct {
25082853 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;
25092854
25102855 for (0..ci.n_limbs) |i| {
2511 const op1 = cg.module.allocId();
2856 const op1 = cg.allocId();
25122857 try cg.body.emitRaw(gpa, opcode, 4);
25132858 cg.body.writeOperand(Id, carry_struct_ty_id);
25142859 cg.body.writeOperand(Id, op1);
25152860 cg.body.writeOperand(Id, ci.limbs[i]);
25162861 cg.body.writeOperand(Id, other.limbs[i]);
25172862
2518 const sum1 = cg.module.allocId();
2863 const sum1 = cg.allocId();
25192864 try cg.body.emit(gpa, .OpCompositeExtract, .{
25202865 .id_result_type = u32_ty_id,
25212866 .id_result = sum1,
25222867 .composite = op1,
25232868 .indexes = &.{0},
25242869 });
2525 const carry1 = cg.module.allocId();
2870 const carry1 = cg.allocId();
25262871 try cg.body.emit(gpa, .OpCompositeExtract, .{
25272872 .id_result_type = u32_ty_id,
25282873 .id_result = carry1,
......@@ -2530,21 +2875,21 @@ const CompositeInt = struct {
25302875 .indexes = &.{1},
25312876 });
25322877
2533 const op2 = cg.module.allocId();
2878 const op2 = cg.allocId();
25342879 try cg.body.emitRaw(gpa, opcode, 4);
25352880 cg.body.writeOperand(Id, carry_struct_ty_id);
25362881 cg.body.writeOperand(Id, op2);
25372882 cg.body.writeOperand(Id, sum1);
25382883 cg.body.writeOperand(Id, carry_id);
25392884
2540 result_limbs[i] = cg.module.allocId();
2885 result_limbs[i] = cg.allocId();
25412886 try cg.body.emit(gpa, .OpCompositeExtract, .{
25422887 .id_result_type = u32_ty_id,
25432888 .id_result = result_limbs[i],
25442889 .composite = op2,
25452890 .indexes = &.{0},
25462891 });
2547 const carry2 = cg.module.allocId();
2892 const carry2 = cg.allocId();
25482893 try cg.body.emit(gpa, .OpCompositeExtract, .{
25492894 .id_result_type = u32_ty_id,
25502895 .id_result = carry2,
......@@ -2560,7 +2905,7 @@ const CompositeInt = struct {
25602905
25612906 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {
25622907 const cg = ci.cg;
2563 const gpa = cg.module.gpa;
2908 const gpa = cg.gpa;
25642909 const u32_ty_id = try cg.resolveType(.u32, .direct);
25652910 const bool_ty_id = try cg.resolveType(.bool, .direct);
25662911 const zero_id = try cg.constInt(.u32, @as(u32, 0));
......@@ -2572,12 +2917,13 @@ const CompositeInt = struct {
25722917 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
25732918 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
25742919 const frac_is_zero = blk: {
2575 const r = cg.module.allocId();
2576 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2577 cg.body.writeOperand(Id, bool_ty_id);
2578 cg.body.writeOperand(Id, r);
2579 cg.body.writeOperand(Id, frac);
2580 cg.body.writeOperand(Id, zero_id);
2920 const r = cg.allocId();
2921 try cg.body.emit(gpa, .OpIEqual, .{
2922 .id_result_type = bool_ty_id,
2923 .id_result = r,
2924 .operand_1 = frac,
2925 .operand_2 = zero_id,
2926 });
25812927 break :blk r;
25822928 };
25832929
......@@ -2593,17 +2939,18 @@ const CompositeInt = struct {
25932939 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);
25942940
25952941 const is_main = blk: {
2596 const r = cg.module.allocId();
2597 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2598 cg.body.writeOperand(Id, bool_ty_id);
2599 cg.body.writeOperand(Id, r);
2600 cg.body.writeOperand(Id, j_plus_whole);
2601 cg.body.writeOperand(Id, i_id);
2942 const r = cg.allocId();
2943 try cg.body.emit(gpa, .OpIEqual, .{
2944 .id_result_type = bool_ty_id,
2945 .id_result = r,
2946 .operand_1 = j_plus_whole,
2947 .operand_2 = i_id,
2948 });
26022949 break :blk r;
26032950 };
26042951 const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac);
26052952 main_val = blk: {
2606 const r = cg.module.allocId();
2953 const r = cg.allocId();
26072954 try cg.body.emit(gpa, .OpSelect, .{
26082955 .id_result_type = u32_ty_id,
26092956 .id_result = r,
......@@ -2617,17 +2964,18 @@ const CompositeInt = struct {
26172964 const one_id = try cg.constInt(.u32, @as(u32, 1));
26182965 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);
26192966 const is_carry = blk: {
2620 const r = cg.module.allocId();
2621 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2622 cg.body.writeOperand(Id, bool_ty_id);
2623 cg.body.writeOperand(Id, r);
2624 cg.body.writeOperand(Id, j_plus_whole_plus_1);
2625 cg.body.writeOperand(Id, i_id);
2967 const r = cg.allocId();
2968 try cg.body.emit(gpa, .OpIEqual, .{
2969 .id_result_type = bool_ty_id,
2970 .id_result = r,
2971 .operand_1 = j_plus_whole_plus_1,
2972 .operand_2 = i_id,
2973 });
26262974 break :blk r;
26272975 };
26282976 const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac);
26292977 const guarded_carry = blk: {
2630 const r = cg.module.allocId();
2978 const r = cg.allocId();
26312979 try cg.body.emit(gpa, .OpSelect, .{
26322980 .id_result_type = u32_ty_id,
26332981 .id_result = r,
......@@ -2638,7 +2986,7 @@ const CompositeInt = struct {
26382986 break :blk r;
26392987 };
26402988 carry_val = blk: {
2641 const r = cg.module.allocId();
2989 const r = cg.allocId();
26422990 try cg.body.emit(gpa, .OpSelect, .{
26432991 .id_result_type = u32_ty_id,
26442992 .id_result = r,
......@@ -2658,7 +3006,7 @@ const CompositeInt = struct {
26583006
26593007 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {
26603008 const cg = ci.cg;
2661 const gpa = cg.module.gpa;
3009 const gpa = cg.gpa;
26623010 const u32_ty_id = try cg.resolveType(.u32, .direct);
26633011 const bool_ty_id = try cg.resolveType(.bool, .direct);
26643012 const zero_id = try cg.constInt(.u32, @as(u32, 0));
......@@ -2670,31 +3018,33 @@ const CompositeInt = struct {
26703018 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
26713019 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
26723020 const frac_is_zero = blk: {
2673 const r = cg.module.allocId();
2674 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2675 cg.body.writeOperand(Id, bool_ty_id);
2676 cg.body.writeOperand(Id, r);
2677 cg.body.writeOperand(Id, frac);
2678 cg.body.writeOperand(Id, zero_id);
3021 const r = cg.allocId();
3022 try cg.body.emit(gpa, .OpIEqual, .{
3023 .id_result_type = bool_ty_id,
3024 .id_result = r,
3025 .operand_1 = frac,
3026 .operand_2 = zero_id,
3027 });
26793028 break :blk r;
26803029 };
26813030
26823031 const fill_id = if (is_arithmetic) blk: {
26833032 const i32_ty_id = try cg.resolveType(.i32, .direct);
2684 const msb_signed = cg.module.allocId();
3033 const msb_signed = cg.allocId();
26853034 try cg.body.emit(gpa, .OpBitcast, .{
26863035 .id_result_type = i32_ty_id,
26873036 .id_result = msb_signed,
26883037 .operand = ci.limbs[ci.n_limbs - 1],
26893038 });
26903039 const shift31 = try cg.constInt(.i32, @as(i32, 31));
2691 const sign_ext = cg.module.allocId();
2692 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
2693 cg.body.writeOperand(Id, i32_ty_id);
2694 cg.body.writeOperand(Id, sign_ext);
2695 cg.body.writeOperand(Id, msb_signed);
2696 cg.body.writeOperand(Id, shift31);
2697 const back = cg.module.allocId();
3040 const sign_ext = cg.allocId();
3041 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
3042 .id_result_type = i32_ty_id,
3043 .id_result = sign_ext,
3044 .base = msb_signed,
3045 .shift = shift31,
3046 });
3047 const back = cg.allocId();
26983048 try cg.body.emit(gpa, .OpBitcast, .{
26993049 .id_result_type = u32_ty_id,
27003050 .id_result = back,
......@@ -2707,7 +3057,7 @@ const CompositeInt = struct {
27073057
27083058 const arith_carry_init = if (is_arithmetic) blk: {
27093059 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);
2710 const guarded = cg.module.allocId();
3060 const guarded = cg.allocId();
27113061 try cg.body.emit(gpa, .OpSelect, .{
27123062 .id_result_type = u32_ty_id,
27133063 .id_result = guarded,
......@@ -2727,17 +3077,18 @@ const CompositeInt = struct {
27273077 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));
27283078 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);
27293079 const is_main = blk: {
2730 const r = cg.module.allocId();
2731 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2732 cg.body.writeOperand(Id, bool_ty_id);
2733 cg.body.writeOperand(Id, r);
2734 cg.body.writeOperand(Id, j_id);
2735 cg.body.writeOperand(Id, i_plus_whole);
3080 const r = cg.allocId();
3081 try cg.body.emit(gpa, .OpIEqual, .{
3082 .id_result_type = bool_ty_id,
3083 .id_result = r,
3084 .operand_1 = j_id,
3085 .operand_2 = i_plus_whole,
3086 });
27363087 break :blk r;
27373088 };
27383089 const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac);
27393090 main_val = blk: {
2740 const r = cg.module.allocId();
3091 const r = cg.allocId();
27413092 try cg.body.emit(gpa, .OpSelect, .{
27423093 .id_result_type = u32_ty_id,
27433094 .id_result = r,
......@@ -2751,17 +3102,18 @@ const CompositeInt = struct {
27513102 const one_id = try cg.constInt(.u32, @as(u32, 1));
27523103 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);
27533104 const is_carry = blk: {
2754 const r = cg.module.allocId();
2755 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2756 cg.body.writeOperand(Id, bool_ty_id);
2757 cg.body.writeOperand(Id, r);
2758 cg.body.writeOperand(Id, j_id);
2759 cg.body.writeOperand(Id, i_plus_whole_plus_1);
3105 const r = cg.allocId();
3106 try cg.body.emit(gpa, .OpIEqual, .{
3107 .id_result_type = bool_ty_id,
3108 .id_result = r,
3109 .operand_1 = j_id,
3110 .operand_2 = i_plus_whole_plus_1,
3111 });
27603112 break :blk r;
27613113 };
27623114 const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac);
27633115 const guarded_carry = blk: {
2764 const r = cg.module.allocId();
3116 const r = cg.allocId();
27653117 try cg.body.emit(gpa, .OpSelect, .{
27663118 .id_result_type = u32_ty_id,
27673119 .id_result = r,
......@@ -2772,7 +3124,7 @@ const CompositeInt = struct {
27723124 break :blk r;
27733125 };
27743126 carry_val = blk: {
2775 const r = cg.module.allocId();
3127 const r = cg.allocId();
27763128 try cg.body.emit(gpa, .OpSelect, .{
27773129 .id_result_type = u32_ty_id,
27783130 .id_result = r,
......@@ -2792,9 +3144,9 @@ const CompositeInt = struct {
27923144
27933145 fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id {
27943146 const cg = ci.cg;
2795 const gpa = cg.module.gpa;
3147 const gpa = cg.gpa;
27963148 const pt = cg.pt;
2797 const zcu = cg.module.zcu;
3149 const zcu = cg.zcu;
27983150 const ip = &zcu.intern_pool;
27993151 const comp = zcu.comp;
28003152 const io = comp.io;
......@@ -2825,15 +3177,16 @@ const CompositeInt = struct {
28253177 var hi: Id = undefined;
28263178 switch (target.os.tag) {
28273179 .opencl => {
2828 lo = cg.module.allocId();
2829 try cg.body.emitRaw(gpa, .OpIMul, 4);
2830 cg.body.writeOperand(Id, u32_ty_id);
2831 cg.body.writeOperand(Id, lo);
2832 cg.body.writeOperand(Id, ci.limbs[i]);
2833 cg.body.writeOperand(Id, other.limbs[j]);
3180 lo = cg.allocId();
3181 try cg.body.emit(gpa, .OpIMul, .{
3182 .id_result_type = u32_ty_id,
3183 .id_result = lo,
3184 .operand_1 = ci.limbs[i],
3185 .operand_2 = other.limbs[j],
3186 });
28343187
28353188 const set = try cg.importExtendedSet();
2836 hi = cg.module.allocId();
3189 hi = cg.allocId();
28373190 try cg.body.emit(gpa, .OpExtInst, .{
28383191 .id_result_type = u32_ty_id,
28393192 .id_result = hi,
......@@ -2843,21 +3196,22 @@ const CompositeInt = struct {
28433196 });
28443197 },
28453198 else => {
2846 const mul_result = cg.module.allocId();
2847 try cg.body.emitRaw(gpa, .OpUMulExtended, 4);
2848 cg.body.writeOperand(Id, pair_struct_ty_id);
2849 cg.body.writeOperand(Id, mul_result);
2850 cg.body.writeOperand(Id, ci.limbs[i]);
2851 cg.body.writeOperand(Id, other.limbs[j]);
2852
2853 lo = cg.module.allocId();
3199 const mul_result = cg.allocId();
3200 try cg.body.emit(gpa, .OpUMulExtended, .{
3201 .id_result_type = pair_struct_ty_id,
3202 .id_result = mul_result,
3203 .operand_1 = ci.limbs[i],
3204 .operand_2 = other.limbs[j],
3205 });
3206
3207 lo = cg.allocId();
28543208 try cg.body.emit(gpa, .OpCompositeExtract, .{
28553209 .id_result_type = u32_ty_id,
28563210 .id_result = lo,
28573211 .composite = mul_result,
28583212 .indexes = &.{0},
28593213 });
2860 hi = cg.module.allocId();
3214 hi = cg.allocId();
28613215 try cg.body.emit(gpa, .OpCompositeExtract, .{
28623216 .id_result_type = u32_ty_id,
28633217 .id_result = hi,
......@@ -2867,21 +3221,22 @@ const CompositeInt = struct {
28673221 },
28683222 }
28693223
2870 const add1 = cg.module.allocId();
2871 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);
2872 cg.body.writeOperand(Id, pair_struct_ty_id);
2873 cg.body.writeOperand(Id, add1);
2874 cg.body.writeOperand(Id, result_limbs[k]);
2875 cg.body.writeOperand(Id, lo);
3224 const add1 = cg.allocId();
3225 try cg.body.emit(gpa, .OpIAddCarry, .{
3226 .id_result_type = pair_struct_ty_id,
3227 .id_result = add1,
3228 .operand_1 = result_limbs[k],
3229 .operand_2 = lo,
3230 });
28763231
2877 const sum1 = cg.module.allocId();
3232 const sum1 = cg.allocId();
28783233 try cg.body.emit(gpa, .OpCompositeExtract, .{
28793234 .id_result_type = u32_ty_id,
28803235 .id_result = sum1,
28813236 .composite = add1,
28823237 .indexes = &.{0},
28833238 });
2884 const c1 = cg.module.allocId();
3239 const c1 = cg.allocId();
28853240 try cg.body.emit(gpa, .OpCompositeExtract, .{
28863241 .id_result_type = u32_ty_id,
28873242 .id_result = c1,
......@@ -2889,21 +3244,22 @@ const CompositeInt = struct {
28893244 .indexes = &.{1},
28903245 });
28913246
2892 const add2 = cg.module.allocId();
2893 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);
2894 cg.body.writeOperand(Id, pair_struct_ty_id);
2895 cg.body.writeOperand(Id, add2);
2896 cg.body.writeOperand(Id, sum1);
2897 cg.body.writeOperand(Id, carry_id);
3247 const add2 = cg.allocId();
3248 try cg.body.emit(gpa, .OpIAddCarry, .{
3249 .id_result_type = pair_struct_ty_id,
3250 .id_result = add2,
3251 .operand_1 = sum1,
3252 .operand_2 = carry_id,
3253 });
28983254
2899 result_limbs[k] = cg.module.allocId();
3255 result_limbs[k] = cg.allocId();
29003256 try cg.body.emit(gpa, .OpCompositeExtract, .{
29013257 .id_result_type = u32_ty_id,
29023258 .id_result = result_limbs[k],
29033259 .composite = add2,
29043260 .indexes = &.{0},
29053261 });
2906 const c2 = cg.module.allocId();
3262 const c2 = cg.allocId();
29073263 try cg.body.emit(gpa, .OpCompositeExtract, .{
29083264 .id_result_type = u32_ty_id,
29093265 .id_result = c2,
......@@ -2925,8 +3281,8 @@ const CompositeInt = struct {
29253281 fn normalize(ci: CompositeInt) !CompositeInt {
29263282 if (ci.info.bits == ci.info.backing_bits) return ci;
29273283 const cg = ci.cg;
2928 const gpa = cg.module.gpa;
2929 const top_bits: u16 = ci.info.bits % Module.big_int_bits;
3284 const gpa = cg.gpa;
3285 const top_bits: u16 = ci.info.bits % big_int_bits;
29303286 assert(top_bits != 0);
29313287
29323288 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
......@@ -2947,25 +3303,27 @@ const CompositeInt = struct {
29473303 const shift_amt: u32 = 32 - top_bits;
29483304 const shift_id = try cg.constInt(.u32, shift_amt);
29493305
2950 const as_signed = cg.module.allocId();
3306 const as_signed = cg.allocId();
29513307 try cg.body.emit(gpa, .OpBitcast, .{
29523308 .id_result_type = i32_ty_id,
29533309 .id_result = as_signed,
29543310 .operand = top_limb,
29553311 });
2956 const shifted_left = cg.module.allocId();
2957 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);
2958 cg.body.writeOperand(Id, i32_ty_id);
2959 cg.body.writeOperand(Id, shifted_left);
2960 cg.body.writeOperand(Id, as_signed);
2961 cg.body.writeOperand(Id, shift_id);
2962 const shifted_right = cg.module.allocId();
2963 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
2964 cg.body.writeOperand(Id, i32_ty_id);
2965 cg.body.writeOperand(Id, shifted_right);
2966 cg.body.writeOperand(Id, shifted_left);
2967 cg.body.writeOperand(Id, shift_id);
2968 const back = cg.module.allocId();
3312 const shifted_left = cg.allocId();
3313 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
3314 .id_result_type = i32_ty_id,
3315 .id_result = shifted_left,
3316 .base = as_signed,
3317 .shift = shift_id,
3318 });
3319 const shifted_right = cg.allocId();
3320 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
3321 .id_result_type = i32_ty_id,
3322 .id_result = shifted_right,
3323 .base = shifted_left,
3324 .shift = shift_id,
3325 });
3326 const back = cg.allocId();
29693327 try cg.body.emit(gpa, .OpBitcast, .{
29703328 .id_result_type = u32_ty_id,
29713329 .id_result = back,
......@@ -3000,7 +3358,7 @@ const Vectorization = union(enum) {
30003358
30013359 /// Derive a vectorization from a particular type
30023360 fn fromType(ty: Type, cg: *CodeGen) Vectorization {
3003 const zcu = cg.module.zcu;
3361 const zcu = cg.zcu;
30043362 if (!ty.isVector(zcu)) return .scalar;
30053363 return .{ .unrolled = ty.vectorLen(zcu) };
30063364 }
......@@ -3034,7 +3392,7 @@ const Vectorization = union(enum) {
30343392 /// `ty` may be a scalar or vector, it doesn't matter.
30353393 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {
30363394 const pt = cg.pt;
3037 const zcu = cg.module.zcu;
3395 const zcu = cg.zcu;
30383396 const scalar_ty = ty.scalarType(zcu);
30393397 return switch (vec) {
30403398 .scalar => scalar_ty,
......@@ -3046,7 +3404,7 @@ const Vectorization = union(enum) {
30463404 /// this setup, and returns a new type that holds the relevant information on how to access
30473405 /// elements of the input.
30483406 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {
3049 const zcu = cg.module.zcu;
3407 const zcu = cg.zcu;
30503408 const is_vector = tmp.ty.isVector(zcu);
30513409 const value: PreparedOperand.Value = switch (tmp.value) {
30523410 .singleton => |id| switch (vec) {
......@@ -3146,26 +3504,28 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {
31463504/// This function builds an OpSConvert of OpUConvert depending on the
31473505/// signedness of the types.
31483506fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3149 const zcu = cg.module.zcu;
3150
3151 const dst_ty_id = try cg.resolveType(dst_ty.scalarType(zcu), .direct);
3152 const src_ty_id = try cg.resolveType(src.ty.scalarType(zcu), .direct);
3507 const zcu = cg.zcu;
31533508
31543509 const v = cg.vectorization(.{ dst_ty, src });
31553510 const result_ty = try v.resultType(cg, dst_ty);
31563511
3157 // We can directly compare integers, because those type-IDs are cached.
3158 if (dst_ty_id == src_ty_id) {
3159 // Nothing to do, type-pun to the right value.
3160 // Note, Caller guarantees that the types fit (or caller will normalize after),
3161 // so we don't have to normalize here.
3162 // Note, dst_ty may be a scalar type even if we expect a vector, so we have to
3163 // convert to the right type here.
3512 const dst_scalar = dst_ty.scalarType(zcu);
3513 const src_scalar = src.ty.scalarType(zcu);
3514 if (dst_scalar.toIntern() == src_scalar.toIntern()) {
31643515 return src.pun(result_ty);
31653516 }
3517 if (dst_scalar.isInt(zcu) and src_scalar.isInt(zcu)) {
3518 const dst_info = dst_scalar.intInfo(zcu);
3519 const src_info = src_scalar.intInfo(zcu);
3520 if (cg.backingIntBits(dst_info.bits).@"0" == cg.backingIntBits(src_info.bits).@"0" and
3521 dst_info.signedness == src_info.signedness)
3522 {
3523 return src.pun(result_ty);
3524 }
3525 }
31663526
31673527 const ops = v.components();
3168 const results = cg.module.allocIds(ops);
3528 const results = cg.allocIds(ops);
31693529
31703530 const op_result_ty = dst_ty.scalarType(zcu);
31713531 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
......@@ -3179,7 +3539,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
31793539 const op_src = try v.prepare(cg, src);
31803540
31813541 for (0..ops) |i| {
3182 try cg.body.emitRaw(cg.module.gpa, opcode, 3);
3542 try cg.body.emitRaw(cg.gpa, opcode, 3);
31833543 cg.body.writeOperand(Id, op_result_ty_id);
31843544 cg.body.writeOperand(Id, results.at(i));
31853545 cg.body.writeOperand(Id, op_src.at(i));
......@@ -3188,51 +3548,12 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
31883548 return v.finalize(result_ty, results);
31893549}
31903550
3191fn buildFma(cg: *CodeGen, a: Temporary, b: Temporary, c: Temporary) !Temporary {
3192 const zcu = cg.module.zcu;
3193 const target = cg.module.zcu.getTarget();
3194
3195 const v = cg.vectorization(.{ a, b, c });
3196 const ops = v.components();
3197 const results = cg.module.allocIds(ops);
3198
3199 const op_result_ty = a.ty.scalarType(zcu);
3200 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
3201 const result_ty = try v.resultType(cg, a.ty);
3202
3203 const op_a = try v.prepare(cg, a);
3204 const op_b = try v.prepare(cg, b);
3205 const op_c = try v.prepare(cg, c);
3206
3207 const set = try cg.importExtendedSet();
3208 const opcode: u32 = switch (target.os.tag) {
3209 .opencl => @intFromEnum(spec.OpenClOpcode.fma),
3210 // NOTE: Vulkan's FMA instruction does *NOT* produce the right values!
3211 // its precision guarantees do NOT match zigs and it does NOT match OpenCLs!
3212 // it needs to be emulated!
3213 .vulkan, .opengl => @intFromEnum(spec.GlslOpcode.Fma),
3214 else => unreachable,
3215 };
3216
3217 for (0..ops) |i| {
3218 try cg.body.emit(cg.module.gpa, .OpExtInst, .{
3219 .id_result_type = op_result_ty_id,
3220 .id_result = results.at(i),
3221 .set = set,
3222 .instruction = .{ .inst = opcode },
3223 .id_ref_4 = &.{ op_a.at(i), op_b.at(i), op_c.at(i) },
3224 });
3225 }
3226
3227 return v.finalize(result_ty, results);
3228}
3229
32303551fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary {
3231 const zcu = cg.module.zcu;
3552 const zcu = cg.zcu;
32323553
32333554 const v = cg.vectorization(.{ condition, lhs, rhs });
32343555 const ops = v.components();
3235 const results = cg.module.allocIds(ops);
3556 const results = cg.allocIds(ops);
32363557
32373558 const op_result_ty = lhs.ty.scalarType(zcu);
32383559 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
......@@ -3245,7 +3566,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar
32453566 const object_2 = try v.prepare(cg, rhs);
32463567
32473568 for (0..ops) |i| {
3248 try cg.body.emit(cg.module.gpa, .OpSelect, .{
3569 try cg.body.emit(cg.gpa, .OpSelect, .{
32493570 .id_result_type = op_result_ty_id,
32503571 .id_result = results.at(i),
32513572 .condition = cond.at(i),
......@@ -3260,7 +3581,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar
32603581fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
32613582 const v = cg.vectorization(.{ lhs, rhs });
32623583 const ops = v.components();
3263 const results = cg.module.allocIds(ops);
3584 const results = cg.allocIds(ops);
32643585
32653586 const op_result_ty: Type = .bool;
32663587 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
......@@ -3270,7 +3591,7 @@ fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Tempo
32703591 const op_rhs = try v.prepare(cg, rhs);
32713592
32723593 for (0..ops) |i| {
3273 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
3594 try cg.body.emitRaw(cg.gpa, opcode, 4);
32743595 cg.body.writeOperand(Id, op_result_ty_id);
32753596 cg.body.writeOperand(Id, results.at(i));
32763597 cg.body.writeOperand(Id, op_lhs.at(i));
......@@ -3351,11 +3672,11 @@ const UnaryOp = enum {
33513672};
33523673
33533674fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3354 const zcu = cg.module.zcu;
3355 const target = cg.module.zcu.getTarget();
3675 const zcu = cg.zcu;
3676 const target = cg.zcu.getTarget();
33563677 const v = cg.vectorization(.{operand});
33573678 const ops = v.components();
3358 const results = cg.module.allocIds(ops);
3679 const results = cg.allocIds(ops);
33593680 const op_result_ty = operand.ty.scalarType(zcu);
33603681 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
33613682 const result_ty = try v.resultType(cg, operand.ty);
......@@ -3364,7 +3685,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
33643685 if (op.extInstOpcode(target)) |opcode| {
33653686 const set = try cg.importExtendedSet();
33663687 for (0..ops) |i| {
3367 try cg.body.emit(cg.module.gpa, .OpExtInst, .{
3688 try cg.body.emit(cg.gpa, .OpExtInst, .{
33683689 .id_result_type = op_result_ty_id,
33693690 .id_result = results.at(i),
33703691 .set = set,
......@@ -3384,7 +3705,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
33843705 ),
33853706 };
33863707 for (0..ops) |i| {
3387 try cg.body.emitRaw(cg.module.gpa, opcode, 3);
3708 try cg.body.emitRaw(cg.gpa, opcode, 3);
33883709 cg.body.writeOperand(Id, op_result_ty_id);
33893710 cg.body.writeOperand(Id, results.at(i));
33903711 cg.body.writeOperand(Id, op_operand.at(i));
......@@ -3395,11 +3716,11 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
33953716}
33963717
33973718fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
3398 const zcu = cg.module.zcu;
3719 const zcu = cg.zcu;
33993720
34003721 const v = cg.vectorization(.{ lhs, rhs });
34013722 const ops = v.components();
3402 const results = cg.module.allocIds(ops);
3723 const results = cg.allocIds(ops);
34033724
34043725 const op_result_ty = lhs.ty.scalarType(zcu);
34053726 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
......@@ -3409,7 +3730,7 @@ fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Te
34093730 const op_rhs = try v.prepare(cg, rhs);
34103731
34113732 for (0..ops) |i| {
3412 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
3733 try cg.body.emitRaw(cg.gpa, opcode, 4);
34133734 cg.body.writeOperand(Id, op_result_ty_id);
34143735 cg.body.writeOperand(Id, results.at(i));
34153736 cg.body.writeOperand(Id, op_lhs.at(i));
......@@ -3428,11 +3749,11 @@ fn buildWideMul(
34283749 rhs: Temporary,
34293750) !struct { Temporary, Temporary } {
34303751 const pt = cg.pt;
3431 const zcu = cg.module.zcu;
3752 const zcu = cg.zcu;
34323753 const comp = zcu.comp;
34333754 const gpa = comp.gpa;
34343755 const io = comp.io;
3435 const target = cg.module.zcu.getTarget();
3756 const target = cg.zcu.getTarget();
34363757 const ip = &zcu.intern_pool;
34373758
34383759 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));
......@@ -3444,8 +3765,8 @@ fn buildWideMul(
34443765 const lhs_op = try v.prepare(cg, lhs);
34453766 const rhs_op = try v.prepare(cg, rhs);
34463767
3447 const value_results = cg.module.allocIds(ops);
3448 const overflow_results = cg.module.allocIds(ops);
3768 const value_results = cg.allocIds(ops);
3769 const overflow_results = cg.allocIds(ops);
34493770
34503771 switch (target.os.tag) {
34513772 .opencl => {
......@@ -3490,7 +3811,7 @@ fn buildWideMul(
34903811 };
34913812
34923813 for (0..ops) |i| {
3493 const op_result = cg.module.allocId();
3814 const op_result = cg.allocId();
34943815
34953816 try cg.body.emitRaw(gpa, opcode, 4);
34963817 cg.body.writeOperand(Id, op_result_ty_id);
......@@ -3550,12 +3871,12 @@ fn buildWideMul(
35503871fn generateTestEntryPoint(
35513872 cg: *CodeGen,
35523873 name: []const u8,
3553 spv_decl_index: Module.Decl.Index,
3874 spv_decl_index: Decl.Index,
35543875 test_id: Id,
35553876) !void {
3556 const gpa = cg.module.gpa;
3557 const zcu = cg.module.zcu;
3558 const target = cg.module.zcu.getTarget();
3877 const gpa = cg.gpa;
3878 const zcu = cg.zcu;
3879 const target = cg.zcu.getTarget();
35593880
35603881 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);
35613882 const ptr_anyerror_ty = try cg.pt.ptrType(.{
......@@ -3564,15 +3885,15 @@ fn generateTestEntryPoint(
35643885 });
35653886 const ptr_anyerror_ty_id = try cg.resolveType(ptr_anyerror_ty, .direct);
35663887
3567 const kernel_id = cg.module.declPtr(spv_decl_index).result_id;
3888 const kernel_id = cg.declPtr(spv_decl_index).result_id;
35683889
3569 const section = &cg.module.sections.functions;
3890 const section = &cg.sections.functions;
35703891
3571 const p_error_id = cg.module.allocId();
3892 const p_error_id = cg.allocId();
35723893 switch (target.os.tag) {
35733894 .opencl, .amdhsa => {
35743895 const void_ty_id = try cg.resolveType(.void, .direct);
3575 const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{ptr_anyerror_ty_id});
3896 const kernel_proto_ty_id = try cg.functionType(void_ty_id, &.{ptr_anyerror_ty_id});
35763897
35773898 try section.emit(gpa, .OpFunction, .{
35783899 .id_result_type = try cg.resolveType(.void, .direct),
......@@ -3587,43 +3908,43 @@ fn generateTestEntryPoint(
35873908 });
35883909
35893910 try section.emit(gpa, .OpLabel, .{
3590 .id_result = cg.module.allocId(),
3911 .id_result = cg.allocId(),
35913912 });
35923913 },
35933914 .vulkan, .opengl => {
3594 if (cg.module.error_buffer == null) {
3595 const spv_err_decl_index = try cg.module.allocDecl(.global);
3596 const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id;
3915 if (cg.error_buffer == null) {
3916 const spv_err_decl_index = try cg.allocDecl(.global);
3917 const err_buf_result_id = cg.declPtr(spv_err_decl_index).result_id;
35973918
3598 const buffer_struct_ty_id = cg.module.allocId();
3599 try cg.module.sections.globals.emit(gpa, .OpTypeStruct, .{
3919 const buffer_struct_ty_id = cg.allocId();
3920 try cg.sections.globals.emit(gpa, .OpTypeStruct, .{
36003921 .id_result = buffer_struct_ty_id,
36013922 .id_ref = &.{anyerror_ty_id},
36023923 });
3603 try cg.module.memberDebugName(buffer_struct_ty_id, 0, "error_out");
3604 try cg.module.decorate(buffer_struct_ty_id, .block);
3605 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
3924 try cg.memberDebugName(buffer_struct_ty_id, 0, "error_out");
3925 try cg.decorate(buffer_struct_ty_id, .block);
3926 try cg.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
36063927
3607 const ptr_buffer_struct_ty_id = cg.module.allocId();
3608 try cg.module.sections.globals.emit(gpa, .OpTypePointer, .{
3928 const ptr_buffer_struct_ty_id = cg.allocId();
3929 try cg.sections.globals.emit(gpa, .OpTypePointer, .{
36093930 .id_result = ptr_buffer_struct_ty_id,
3610 .storage_class = cg.module.storageClass(.global),
3931 .storage_class = cg.storageClass(.global),
36113932 .type = buffer_struct_ty_id,
36123933 });
36133934
3614 try cg.module.sections.globals.emit(gpa, .OpVariable, .{
3935 try cg.sections.globals.emit(gpa, .OpVariable, .{
36153936 .id_result_type = ptr_buffer_struct_ty_id,
36163937 .id_result = err_buf_result_id,
3617 .storage_class = cg.module.storageClass(.global),
3938 .storage_class = cg.storageClass(.global),
36183939 });
3619 try cg.module.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } });
3620 try cg.module.decorate(err_buf_result_id, .{ .binding = .{ .binding_point = 0 } });
3940 try cg.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } });
3941 try cg.decorate(err_buf_result_id, .{ .binding = .{ .binding_point = 0 } });
36213942
3622 cg.module.error_buffer = spv_err_decl_index;
3943 cg.error_buffer = spv_err_decl_index;
36233944 }
36243945
36253946 const void_ty_id = try cg.resolveType(.void, .direct);
3626 const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
3947 const kernel_proto_ty_id = try cg.functionType(void_ty_id, &.{});
36273948 try section.emit(gpa, .OpFunction, .{
36283949 .id_result_type = try cg.resolveType(.void, .direct),
36293950 .id_result = kernel_id,
......@@ -3631,12 +3952,12 @@ fn generateTestEntryPoint(
36313952 .function_type = kernel_proto_ty_id,
36323953 });
36333954 try section.emit(gpa, .OpLabel, .{
3634 .id_result = cg.module.allocId(),
3955 .id_result = cg.allocId(),
36353956 });
36363957
3637 const spv_err_decl_index = cg.module.error_buffer.?;
3638 const buffer_id = cg.module.declPtr(spv_err_decl_index).result_id;
3639 try cg.module.decl_deps.append(gpa, spv_err_decl_index);
3958 const spv_err_decl_index = cg.error_buffer.?;
3959 const buffer_id = cg.declPtr(spv_err_decl_index).result_id;
3960 try cg.decl_deps.append(gpa, spv_err_decl_index);
36403961
36413962 const zero_id = try cg.constInt(.u32, 0);
36423963 try section.emit(gpa, .OpInBoundsAccessChain, .{
......@@ -3649,7 +3970,7 @@ fn generateTestEntryPoint(
36493970 else => unreachable,
36503971 }
36513972
3652 const error_id = cg.module.allocId();
3973 const error_id = cg.allocId();
36533974 try section.emit(gpa, .OpFunctionCall, .{
36543975 .id_result_type = anyerror_ty_id,
36553976 .id_result = error_id,
......@@ -3668,9 +3989,14 @@ fn generateTestEntryPoint(
36683989
36693990 // Just generate a quick other name because the intel runtime crashes when the entry-
36703991 // point name is the same as a different OpName.
3671 const test_name = try std.fmt.allocPrint(cg.module.arena, "test {s}", .{name});
3992 const test_name = try std.fmt.allocPrint(cg.arena, "test {s}", .{name});
36723993
3673 try cg.module.declareEntryPoint(spv_decl_index, test_name, .{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } });
3994 const ep_gop = try cg.entry_points.getOrPut(cg.gpa, cg.declPtr(spv_decl_index).result_id);
3995 ep_gop.value_ptr.* = .{
3996 .decl_index = spv_decl_index,
3997 .name = test_name,
3998 .cc = .{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } },
3999 };
36744000}
36754001
36764002fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
......@@ -3688,7 +4014,7 @@ fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
36884014/// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct).
36894015fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
36904016 const pt = cg.pt;
3691 const zcu = cg.module.zcu;
4017 const zcu = cg.zcu;
36924018 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
36934019 .bool => {
36944020 const false_id = try cg.constBool(false, .indirect);
......@@ -3714,7 +4040,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
37144040/// Convert representation from direct (in 'register) to direct (in memory)
37154041/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).
37164042fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3717 const zcu = cg.module.zcu;
4043 const zcu = cg.zcu;
37184044 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
37194045 .bool => {
37204046 const result = try cg.intFromBool(.init(ty, operand_id), .u1);
......@@ -3726,9 +4052,9 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
37264052
37274053fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
37284054 const result_ty_id = try cg.resolveType(result_ty, .indirect);
3729 const result_id = cg.module.allocId();
4055 const result_id = cg.allocId();
37304056 const indexes = [_]u32{field};
3731 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
4057 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
37324058 .id_result_type = result_ty_id,
37334059 .id_result = result_id,
37344060 .composite = object,
......@@ -3740,9 +4066,9 @@ fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
37404066
37414067fn extractVectorComponent(cg: *CodeGen, result_ty: Type, vector_id: Id, field: u32) !Id {
37424068 const result_ty_id = try cg.resolveType(result_ty, .direct);
3743 const result_id = cg.module.allocId();
4069 const result_id = cg.allocId();
37444070 const indexes = [_]u32{field};
3745 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
4071 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
37464072 .id_result_type = result_ty_id,
37474073 .id_result = result_id,
37484074 .composite = vector_id,
......@@ -3757,15 +4083,15 @@ const MemoryOptions = struct {
37574083};
37584084
37594085fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
3760 const zcu = cg.module.zcu;
4086 const zcu = cg.zcu;
37614087 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);
37624088 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);
3763 const result_id = cg.module.allocId();
4089 const result_id = cg.allocId();
37644090 const access: spec.MemoryAccess.Extended = .{
37654091 .@"volatile" = options.is_volatile,
37664092 .aligned = .{ .literal_integer = alignment },
37674093 };
3768 try cg.body.emit(cg.module.gpa, .OpLoad, .{
4094 try cg.body.emit(cg.gpa, .OpLoad, .{
37694095 .id_result_type = indirect_value_ty_id,
37704096 .id_result = result_id,
37714097 .pointer = ptr_id,
......@@ -3777,7 +4103,7 @@ fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
37774103fn store(cg: *CodeGen, value_ty: Type, ptr_id: Id, value_id: Id, options: MemoryOptions) !void {
37784104 const indirect_value_id = try cg.convertToIndirect(value_ty, value_id);
37794105 const access: spec.MemoryAccess.Extended = .{ .@"volatile" = options.is_volatile };
3780 try cg.body.emit(cg.module.gpa, .OpStore, .{
4106 try cg.body.emit(cg.gpa, .OpStore, .{
37814107 .pointer = ptr_id,
37824108 .object = indirect_value_id,
37834109 .memory_access = access,
......@@ -3791,8 +4117,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {
37914117}
37924118
37934119fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
3794 const gpa = cg.module.gpa;
3795 const zcu = cg.module.zcu;
4120 const gpa = cg.gpa;
4121 const zcu = cg.zcu;
37964122 const ip = &zcu.intern_pool;
37974123 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))
37984124 return;
......@@ -4028,7 +4354,7 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {
40284354}
40294355
40304356fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id {
4031 const zcu = cg.module.zcu;
4357 const zcu = cg.zcu;
40324358 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
40334359
40344360 if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) {
......@@ -4048,8 +4374,8 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
40484374 .composite_integer => blk: {
40494375 const shift_id = try shift.materialize(cg);
40504376 const u32_ty_id = try cg.resolveType(.u32, .direct);
4051 const result_id = cg.module.allocId();
4052 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
4377 const result_id = cg.allocId();
4378 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
40534379 .id_result_type = u32_ty_id,
40544380 .id_result = result_id,
40554381 .composite = shift_id,
......@@ -4156,13 +4482,13 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id {
41564482}
41574483
41584484fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4159 const zcu = cg.module.zcu;
4485 const zcu = cg.zcu;
41604486 const target = zcu.getTarget();
41614487 const info = cg.arithmeticTypeInfo(lhs.ty);
41624488
41634489 const v = cg.vectorization(.{ lhs, rhs });
41644490 const ops = v.components();
4165 const results = cg.module.allocIds(ops);
4491 const results = cg.allocIds(ops);
41664492
41674493 const op_result_ty = lhs.ty.scalarType(zcu);
41684494 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
......@@ -4174,7 +4500,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
41744500 const set = try cg.importExtendedSet();
41754501 const opcode = op.extInstOpcode(target, info);
41764502 for (0..ops) |i| {
4177 try cg.body.emit(cg.module.gpa, .OpExtInst, .{
4503 try cg.body.emit(cg.gpa, .OpExtInst, .{
41784504 .id_result_type = op_result_ty_id,
41794505 .id_result = results.at(i),
41804506 .set = set,
......@@ -4195,7 +4521,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
41954521/// All other values are returned unmodified (this makes strange integer
41964522/// wrapping easier to use in generic operations).
41974523fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {
4198 const zcu = cg.module.zcu;
4524 const zcu = cg.zcu;
41994525 const ty = value.ty;
42004526 switch (info.class) {
42014527 .integer, .bool, .float => return value,
......@@ -4341,29 +4667,24 @@ fn airArithOp(
43414667}
43424668
43434669fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4670 const zcu = cg.zcu;
4671 const target = zcu.getTarget();
43444672 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4345 const operand = try cg.temporary(ty_op.operand);
4346 // Note: operand_ty may be signed, while ty is always unsigned!
4673 const value = try cg.temporary(ty_op.operand);
4674 // Note: operand_ty may be signed, while ty is always unsigned.
43474675 const result_ty = cg.typeOfIndex(inst);
4348 const result = try cg.abs(result_ty, operand);
4349 return try result.materialize(cg);
4350}
4351
4352fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
4353 const zcu = cg.module.zcu;
4354 const target = cg.module.zcu.getTarget();
43554676 const operand_info = cg.arithmeticTypeInfo(value.ty);
4356 switch (operand_info.class) {
4357 .float => return try cg.buildUnary(.f_abs, value),
4358 .integer, .strange_integer => {
4677 const result: Temporary = switch (operand_info.class) {
4678 .float => try cg.buildUnary(.f_abs, value),
4679 .integer, .strange_integer => abs: {
43594680 var abs_value = try cg.buildUnary(.i_abs, value);
43604681 switch (target.os.tag) {
43614682 .vulkan, .opengl => {
43624683 if (value.ty.intInfo(zcu).signedness == .signed) {
43634684 const abs_id = try abs_value.materialize(cg);
43644685 const dst_ty_id = try cg.resolveType(result_ty, .direct);
4365 const cast_id = cg.module.allocId();
4366 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
4686 const cast_id = cg.allocId();
4687 try cg.body.emit(cg.gpa, .OpBitcast, .{
43674688 .id_result_type = dst_ty_id,
43684689 .id_result = cast_id,
43694690 .operand = abs_id,
......@@ -4373,9 +4694,9 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
43734694 },
43744695 else => {},
43754696 }
4376 return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
4697 break :abs try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
43774698 },
4378 .composite_integer => {
4699 .composite_integer => abs: {
43794700 const val_id = try value.materialize(cg);
43804701 const scratch_top = cg.id_scratch.items.len;
43814702 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
......@@ -4385,10 +4706,10 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
43854706 const ci_neg = try ci_z.addSub(ci, false);
43864707 const result_info = cg.arithmeticTypeInfo(result_ty);
43874708 const u32_ty_id = try cg.resolveType(.u32, .direct);
4388 const result_limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, ci.n_limbs);
4709 const result_limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, ci.n_limbs);
43894710 for (0..ci.n_limbs) |i| {
4390 result_limbs[i] = cg.module.allocId();
4391 try cg.body.emit(cg.module.gpa, .OpSelect, .{
4711 result_limbs[i] = cg.allocId();
4712 try cg.body.emit(cg.gpa, .OpSelect, .{
43924713 .id_result_type = u32_ty_id,
43934714 .id_result = result_limbs[i],
43944715 .condition = is_neg,
......@@ -4398,10 +4719,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
43984719 }
43994720 const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info);
44004721 const normalized = try ci_result.normalize();
4401 return .init(result_ty, try normalized.materialize(result_ty));
4722 break :abs .init(result_ty, try normalized.materialize(result_ty));
44024723 },
44034724 .bool => unreachable,
4404 }
4725 };
4726 return try result.materialize(cg);
44054727}
44064728
44074729fn airAddSubOverflow(
......@@ -4457,32 +4779,36 @@ fn airAddSubOverflow(
44574779 const res_neg = try ci_res2.cmp(ci_z, .lt);
44584780
44594781 const bool_ty_id = try cg.resolveType(.bool, .direct);
4460 const signs_match = cg.module.allocId();
4461 try cg.body.emitRaw(cg.module.gpa, .OpLogicalEqual, 4);
4462 cg.body.writeOperand(Id, bool_ty_id);
4463 cg.body.writeOperand(Id, signs_match);
4464 cg.body.writeOperand(Id, lhs_neg);
4465 cg.body.writeOperand(Id, rhs_neg);
4466 const res_sign_diff = cg.module.allocId();
4467 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNotEqual, 4);
4468 cg.body.writeOperand(Id, bool_ty_id);
4469 cg.body.writeOperand(Id, res_sign_diff);
4470 cg.body.writeOperand(Id, lhs_neg);
4471 cg.body.writeOperand(Id, res_neg);
4782 const signs_match = cg.allocId();
4783 try cg.body.emit(cg.gpa, .OpLogicalEqual, .{
4784 .id_result_type = bool_ty_id,
4785 .id_result = signs_match,
4786 .operand_1 = lhs_neg,
4787 .operand_2 = rhs_neg,
4788 });
4789 const res_sign_diff = cg.allocId();
4790 try cg.body.emit(cg.gpa, .OpLogicalNotEqual, .{
4791 .id_result_type = bool_ty_id,
4792 .id_result = res_sign_diff,
4793 .operand_1 = lhs_neg,
4794 .operand_2 = res_neg,
4795 });
44724796 const ov_cond = if (add == .OpIAdd) signs_match else blk2: {
4473 const not_match = cg.module.allocId();
4474 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNot, 3);
4475 cg.body.writeOperand(Id, bool_ty_id);
4476 cg.body.writeOperand(Id, not_match);
4477 cg.body.writeOperand(Id, signs_match);
4797 const not_match = cg.allocId();
4798 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
4799 .id_result_type = bool_ty_id,
4800 .id_result = not_match,
4801 .operand = signs_match,
4802 });
44784803 break :blk2 not_match;
44794804 };
4480 const ov_result = cg.module.allocId();
4481 try cg.body.emitRaw(cg.module.gpa, .OpLogicalAnd, 4);
4482 cg.body.writeOperand(Id, bool_ty_id);
4483 cg.body.writeOperand(Id, ov_result);
4484 cg.body.writeOperand(Id, ov_cond);
4485 cg.body.writeOperand(Id, res_sign_diff);
4805 const ov_result = cg.allocId();
4806 try cg.body.emit(cg.gpa, .OpLogicalAnd, .{
4807 .id_result_type = bool_ty_id,
4808 .id_result = ov_result,
4809 .operand_1 = ov_cond,
4810 .operand_2 = res_sign_diff,
4811 });
44864812 break :blk ov_result;
44874813 },
44884814 };
......@@ -4531,7 +4857,7 @@ fn airAddSubOverflow(
45314857
45324858fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45334859 const pt = cg.pt;
4534 const gpa = cg.module.gpa;
4860 const gpa = cg.gpa;
45354861 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
45364862 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
45374863 const lhs = try cg.temporary(extra.lhs);
......@@ -4559,32 +4885,35 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45594885
45604886 const bool_ty_id = try cg.resolveType(.bool, .direct);
45614887 const u32_ty_id = try cg.resolveType(.u32, .direct);
4562 const n: usize = info.backing_bits / Module.big_int_bits;
4888 const n: usize = info.backing_bits / big_int_bits;
45634889
45644890 const ov_bool = switch (info.signedness) {
45654891 .unsigned => blk: {
45664892 const zero_id = try cg.constInt(.u32, @as(u32, 0));
4567 var any_nonzero = cg.module.allocId();
4568 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4569 cg.body.writeOperand(Id, bool_ty_id);
4570 cg.body.writeOperand(Id, any_nonzero);
4571 cg.body.writeOperand(Id, high_limbs[0]);
4572 cg.body.writeOperand(Id, zero_id);
4893 var any_nonzero = cg.allocId();
4894 try cg.body.emit(gpa, .OpINotEqual, .{
4895 .id_result_type = bool_ty_id,
4896 .id_result = any_nonzero,
4897 .operand_1 = high_limbs[0],
4898 .operand_2 = zero_id,
4899 });
45734900
45744901 for (1..n) |i| {
4575 const limb_nz = cg.module.allocId();
4576 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4577 cg.body.writeOperand(Id, bool_ty_id);
4578 cg.body.writeOperand(Id, limb_nz);
4579 cg.body.writeOperand(Id, high_limbs[i]);
4580 cg.body.writeOperand(Id, zero_id);
4581
4582 const combined = cg.module.allocId();
4583 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4584 cg.body.writeOperand(Id, bool_ty_id);
4585 cg.body.writeOperand(Id, combined);
4586 cg.body.writeOperand(Id, any_nonzero);
4587 cg.body.writeOperand(Id, limb_nz);
4902 const limb_nz = cg.allocId();
4903 try cg.body.emit(gpa, .OpINotEqual, .{
4904 .id_result_type = bool_ty_id,
4905 .id_result = limb_nz,
4906 .operand_1 = high_limbs[i],
4907 .operand_2 = zero_id,
4908 });
4909
4910 const combined = cg.allocId();
4911 try cg.body.emit(gpa, .OpLogicalOr, .{
4912 .id_result_type = bool_ty_id,
4913 .id_result = combined,
4914 .operand_1 = any_nonzero,
4915 .operand_2 = limb_nz,
4916 });
45884917 any_nonzero = combined;
45894918 }
45904919
......@@ -4595,92 +4924,99 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45954924 const top_limb = ci_res.limbs[n - 1];
45964925 const i32_ty_id = try cg.resolveType(.i32, .direct);
45974926
4598 const top_bits: u16 = if (info.bits % Module.big_int_bits == 0)
4599 Module.big_int_bits
4927 const top_bits: u16 = if (info.bits % big_int_bits == 0)
4928 big_int_bits
46004929 else
4601 info.bits % Module.big_int_bits;
4930 info.bits % big_int_bits;
46024931
46034932 const shift_amt: u32 = top_bits - 1;
46044933 const shift_id = try cg.constInt(.u32, shift_amt);
46054934
4606 const as_signed = cg.module.allocId();
4935 const as_signed = cg.allocId();
46074936 try cg.body.emit(gpa, .OpBitcast, .{
46084937 .id_result_type = i32_ty_id,
46094938 .id_result = as_signed,
46104939 .operand = top_limb,
46114940 });
4612 const sign_ext = cg.module.allocId();
4613 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
4614 cg.body.writeOperand(Id, i32_ty_id);
4615 cg.body.writeOperand(Id, sign_ext);
4616 cg.body.writeOperand(Id, as_signed);
4617 cg.body.writeOperand(Id, shift_id);
4618 const expected = cg.module.allocId();
4941 const sign_ext = cg.allocId();
4942 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4943 .id_result_type = i32_ty_id,
4944 .id_result = sign_ext,
4945 .base = as_signed,
4946 .shift = shift_id,
4947 });
4948 const expected = cg.allocId();
46194949 try cg.body.emit(gpa, .OpBitcast, .{
46204950 .id_result_type = u32_ty_id,
46214951 .id_result = expected,
46224952 .operand = sign_ext,
46234953 });
46244954
4625 var any_mismatch = cg.module.allocId();
4626 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4627 cg.body.writeOperand(Id, bool_ty_id);
4628 cg.body.writeOperand(Id, any_mismatch);
4629 cg.body.writeOperand(Id, high_limbs[0]);
4630 cg.body.writeOperand(Id, expected);
4955 var any_mismatch = cg.allocId();
4956 try cg.body.emit(gpa, .OpINotEqual, .{
4957 .id_result_type = bool_ty_id,
4958 .id_result = any_mismatch,
4959 .operand_1 = high_limbs[0],
4960 .operand_2 = expected,
4961 });
46314962
46324963 for (1..n) |i| {
4633 const limb_ne = cg.module.allocId();
4634 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4635 cg.body.writeOperand(Id, bool_ty_id);
4636 cg.body.writeOperand(Id, limb_ne);
4637 cg.body.writeOperand(Id, high_limbs[i]);
4638 cg.body.writeOperand(Id, expected);
4639
4640 const combined = cg.module.allocId();
4641 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4642 cg.body.writeOperand(Id, bool_ty_id);
4643 cg.body.writeOperand(Id, combined);
4644 cg.body.writeOperand(Id, any_mismatch);
4645 cg.body.writeOperand(Id, limb_ne);
4964 const limb_ne = cg.allocId();
4965 try cg.body.emit(gpa, .OpINotEqual, .{
4966 .id_result_type = bool_ty_id,
4967 .id_result = limb_ne,
4968 .operand_1 = high_limbs[i],
4969 .operand_2 = expected,
4970 });
4971
4972 const combined = cg.allocId();
4973 try cg.body.emit(gpa, .OpLogicalOr, .{
4974 .id_result_type = bool_ty_id,
4975 .id_result = combined,
4976 .operand_1 = any_mismatch,
4977 .operand_2 = limb_ne,
4978 });
46464979 any_mismatch = combined;
46474980 }
46484981
46494982 if (info.bits != info.backing_bits) {
4650 const top_bits_s: u16 = info.bits % Module.big_int_bits;
4983 const top_bits_s: u16 = info.bits % big_int_bits;
46514984 const s_shift_id = try cg.constInt(.u32, top_bits_s - 1);
46524985
4653 const top_as_signed = cg.module.allocId();
4986 const top_as_signed = cg.allocId();
46544987 try cg.body.emit(gpa, .OpBitcast, .{
46554988 .id_result_type = i32_ty_id,
46564989 .id_result = top_as_signed,
46574990 .operand = top_limb,
46584991 });
4659 const top_sign_ext = cg.module.allocId();
4660 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
4661 cg.body.writeOperand(Id, i32_ty_id);
4662 cg.body.writeOperand(Id, top_sign_ext);
4663 cg.body.writeOperand(Id, top_as_signed);
4664 cg.body.writeOperand(Id, s_shift_id);
4665 const top_expected = cg.module.allocId();
4992 const top_sign_ext = cg.allocId();
4993 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4994 .id_result_type = i32_ty_id,
4995 .id_result = top_sign_ext,
4996 .base = top_as_signed,
4997 .shift = s_shift_id,
4998 });
4999 const top_expected = cg.allocId();
46665000 try cg.body.emit(gpa, .OpBitcast, .{
46675001 .id_result_type = u32_ty_id,
46685002 .id_result = top_expected,
46695003 .operand = top_sign_ext,
46705004 });
4671 const top_mismatch = cg.module.allocId();
4672 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4673 cg.body.writeOperand(Id, bool_ty_id);
4674 cg.body.writeOperand(Id, top_mismatch);
4675 cg.body.writeOperand(Id, top_limb);
4676 cg.body.writeOperand(Id, top_expected);
4677
4678 const combined = cg.module.allocId();
4679 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4680 cg.body.writeOperand(Id, bool_ty_id);
4681 cg.body.writeOperand(Id, combined);
4682 cg.body.writeOperand(Id, any_mismatch);
4683 cg.body.writeOperand(Id, top_mismatch);
5005 const top_mismatch = cg.allocId();
5006 try cg.body.emit(gpa, .OpINotEqual, .{
5007 .id_result_type = bool_ty_id,
5008 .id_result = top_mismatch,
5009 .operand_1 = top_limb,
5010 .operand_2 = top_expected,
5011 });
5012
5013 const combined = cg.allocId();
5014 try cg.body.emit(gpa, .OpLogicalOr, .{
5015 .id_result_type = bool_ty_id,
5016 .id_result = combined,
5017 .operand_1 = any_mismatch,
5018 .operand_2 = top_mismatch,
5019 });
46845020 any_mismatch = combined;
46855021 }
46865022
......@@ -4702,7 +5038,8 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
47025038 // - Additionally, if info.bits != 32, we'll have to check the high bits
47035039 // of the result too.
47045040
4705 const largest_int_bits = cg.largestSupportedIntBits();
5041 const target = cg.zcu.getTarget();
5042 const largest_int_bits: u16 = if (target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64) 64 else 32;
47065043 // If non-null, the number of bits that the multiplication should be performed in. If
47075044 // null, we have to use wide multiplication.
47085045 const maybe_op_ty_bits: ?u16 = switch (info.bits) {
......@@ -4846,7 +5183,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
48465183}
48475184
48485185fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4849 const zcu = cg.module.zcu;
5186 const zcu = cg.zcu;
48505187
48515188 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
48525189 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -4898,14 +5235,48 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
48985235 const info = cg.arithmeticTypeInfo(result_ty);
48995236 assert(info.class == .float); // .mul_add is only emitted for floats
49005237
4901 const result = try cg.buildFma(a, b, c);
5238 const zcu = cg.zcu;
5239 const target = zcu.getTarget();
5240
5241 const v = cg.vectorization(.{ a, b, c });
5242 const ops = v.components();
5243 const results = cg.allocIds(ops);
5244
5245 const op_result_ty = a.ty.scalarType(zcu);
5246 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
5247 const result_temp_ty = try v.resultType(cg, a.ty);
5248
5249 const op_a = try v.prepare(cg, a);
5250 const op_b = try v.prepare(cg, b);
5251 const op_c = try v.prepare(cg, c);
5252
5253 const set = try cg.importExtendedSet();
5254 const opcode: u32 = switch (target.os.tag) {
5255 .opencl => @intFromEnum(spec.OpenClOpcode.fma),
5256 // NOTE: Vulkan's FMA does not meet Zig's nor OpenCL's precision guarantees and needs
5257 // to be emulated.
5258 .vulkan, .opengl => @intFromEnum(spec.GlslOpcode.Fma),
5259 else => unreachable,
5260 };
5261
5262 for (0..ops) |i| {
5263 try cg.body.emit(cg.gpa, .OpExtInst, .{
5264 .id_result_type = op_result_ty_id,
5265 .id_result = results.at(i),
5266 .set = set,
5267 .instruction = .{ .inst = opcode },
5268 .id_ref_4 = &.{ op_a.at(i), op_b.at(i), op_c.at(i) },
5269 });
5270 }
5271
5272 const result = v.finalize(result_temp_ty, results);
49025273 return try result.materialize(cg);
49035274}
49045275
49055276fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {
49065277 if (cg.liveness.isUnused(inst)) return null;
49075278
4908 const zcu = cg.module.zcu;
5279 const zcu = cg.zcu;
49095280 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
49105281 const operand = try cg.temporary(ty_op.operand);
49115282
......@@ -4948,7 +5319,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
49485319}
49495320
49505321fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4951 const zcu = cg.module.zcu;
5322 const zcu = cg.zcu;
49525323 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
49535324 const operand = try cg.resolve(reduce.operand);
49545325 const operand_ty = cg.typeOf(reduce.operand);
......@@ -5016,7 +5387,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
50165387}
50175388
50185389fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5019 const zcu = cg.module.zcu;
5390 const zcu = cg.zcu;
50205391 const gpa = zcu.gpa;
50215392
50225393 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);
......@@ -5041,7 +5412,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
50415412}
50425413
50435414fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5044 const zcu = cg.module.zcu;
5415 const zcu = cg.zcu;
50455416 const gpa = zcu.gpa;
50465417
50475418 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);
......@@ -5060,7 +5431,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
50605431 id.* = switch (mask_elem.unwrap()) {
50615432 .a_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_a, idx),
50625433 .b_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_b, idx),
5063 .undef => try cg.module.constUndef(elem_ty_id),
5434 .undef => try cg.constUndef(elem_ty_id),
50645435 };
50655436 }
50665437
......@@ -5074,8 +5445,8 @@ fn accessChainId(
50745445 base: Id,
50755446 indices: []const Id,
50765447) !Id {
5077 const result_id = cg.module.allocId();
5078 try cg.body.emit(cg.module.gpa, .OpInBoundsAccessChain, .{
5448 const result_id = cg.allocId();
5449 try cg.body.emit(cg.gpa, .OpInBoundsAccessChain, .{
50795450 .id_result_type = result_ty_id,
50805451 .id_result = result_id,
50815452 .base = base,
......@@ -5094,7 +5465,7 @@ fn accessChain(
50945465 base: Id,
50955466 indices: []const u32,
50965467) !Id {
5097 const gpa = cg.module.gpa;
5468 const gpa = cg.gpa;
50985469 const scratch_top = cg.id_scratch.items.len;
50995470 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
51005471 const ids = try cg.id_scratch.addManyAsSlice(gpa, indices.len);
......@@ -5111,8 +5482,8 @@ fn ptrAccessChain(
51115482 element: Id,
51125483 indices: []const u32,
51135484) !Id {
5114 const gpa = cg.module.gpa;
5115 const target = cg.module.zcu.getTarget();
5485 const gpa = cg.gpa;
5486 const target = cg.zcu.getTarget();
51165487
51175488 const scratch_top = cg.id_scratch.items.len;
51185489 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
......@@ -5121,7 +5492,7 @@ fn ptrAccessChain(
51215492 id.* = try cg.constInt(.u32, index);
51225493 }
51235494
5124 const result_id = cg.module.allocId();
5495 const result_id = cg.allocId();
51255496 switch (target.os.tag) {
51265497 .opencl, .amdhsa => {
51275498 try cg.body.emit(gpa, .OpInBoundsPtrAccessChain, .{
......@@ -5147,7 +5518,7 @@ fn ptrAccessChain(
51475518}
51485519
51495520fn ptrAdd(cg: *CodeGen, result_ty: Type, ptr_ty: Type, ptr_id: Id, offset_id: Id) !Id {
5150 const zcu = cg.module.zcu;
5521 const zcu = cg.zcu;
51515522 const result_ty_id = try cg.resolveType(result_ty, .direct);
51525523
51535524 switch (ptr_ty.ptrSize(zcu)) {
......@@ -5188,8 +5559,8 @@ fn airPtrSub(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
51885559 const offset_ty_id = try cg.resolveType(offset_ty, .direct);
51895560 const result_ty = cg.typeOfIndex(inst);
51905561
5191 const negative_offset_id = cg.module.allocId();
5192 try cg.body.emit(cg.module.gpa, .OpSNegate, .{
5562 const negative_offset_id = cg.allocId();
5563 try cg.body.emit(cg.gpa, .OpSNegate, .{
51935564 .id_result_type = offset_ty_id,
51945565 .id_result = negative_offset_id,
51955566 .operand = offset_id,
......@@ -5203,9 +5574,9 @@ fn cmp(
52035574 lhs: Temporary,
52045575 rhs: Temporary,
52055576) !Temporary {
5206 const gpa = cg.module.gpa;
5577 const gpa = cg.gpa;
52075578 const pt = cg.pt;
5208 const zcu = cg.module.zcu;
5579 const zcu = cg.zcu;
52095580 const scalar_ty = lhs.ty.scalarType(zcu);
52105581 const is_vector = lhs.ty.isVector(zcu);
52115582
......@@ -5234,14 +5605,14 @@ fn cmp(
52345605
52355606 const usize_ty_id = try cg.resolveType(.usize, .direct);
52365607
5237 const lhs_int_id = cg.module.allocId();
5608 const lhs_int_id = cg.allocId();
52385609 try cg.body.emit(gpa, .OpConvertPtrToU, .{
52395610 .id_result_type = usize_ty_id,
52405611 .id_result = lhs_int_id,
52415612 .pointer = try lhs.materialize(cg),
52425613 });
52435614
5244 const rhs_int_id = cg.module.allocId();
5615 const rhs_int_id = cg.allocId();
52455616 try cg.body.emit(gpa, .OpConvertPtrToU, .{
52465617 .id_result_type = usize_ty_id,
52475618 .id_result = rhs_int_id,
......@@ -5410,14 +5781,29 @@ fn bitCast(
54105781 src_ty: Type,
54115782 src_id: Id,
54125783) !Id {
5413 const gpa = cg.module.gpa;
5414 const zcu = cg.module.zcu;
5784 const gpa = cg.gpa;
5785 const zcu = cg.zcu;
54155786 const target = zcu.getTarget();
5416 const src_ty_id = try cg.resolveType(src_ty, .direct);
5417 const dst_ty_id = try cg.resolveType(dst_ty, .direct);
54185787
5788 if (src_ty.toIntern() == dst_ty.toIntern()) return src_id;
5789 if (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu)) switch (target.os.tag) {
5790 .vulkan, .opengl => if (src_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) return src_id,
5791 else => {},
5792 };
5793
5794 const dst_ty_id = try cg.resolveType(dst_ty, .direct);
54195795 const result_id = blk: {
5420 if (src_ty_id == dst_ty_id) break :blk src_id;
5796 // Big-int ↔ big-int bitcast: the indirect representation is an array,
5797 // which OpBitcast cannot operate on. The arrays are bitwise identical
5798 // apart from the top limb's padding; the normalize pass below fixes
5799 // the padding.
5800 if (src_ty.isInt(zcu) and dst_ty.isInt(zcu)) {
5801 const src_info = src_ty.intInfo(zcu);
5802 const dst_info = dst_ty.intInfo(zcu);
5803 const src_backing, const src_big = cg.backingIntBits(src_info.bits);
5804 const dst_backing, const dst_big = cg.backingIntBits(dst_info.bits);
5805 if (src_backing == dst_backing and src_big and dst_big) break :blk src_id;
5806 }
54215807
54225808 // TODO: Some more cases are missing here
54235809 // See fn bitCast in llvm.zig
......@@ -5432,7 +5818,7 @@ fn bitCast(
54325818 }
54335819 }
54345820
5435 const result_id = cg.module.allocId();
5821 const result_id = cg.allocId();
54365822 try cg.body.emit(gpa, .OpConvertUToPtr, .{
54375823 .id_result_type = dst_ty_id,
54385824 .id_result = result_id,
......@@ -5446,7 +5832,7 @@ fn bitCast(
54465832 // otherwise use a temporary and perform a pointer cast.
54475833 const can_bitcast = (src_ty.isNumeric(zcu) and dst_ty.isNumeric(zcu)) or (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu));
54485834 if (can_bitcast) {
5449 const result_id = cg.module.allocId();
5835 const result_id = cg.allocId();
54505836 try cg.body.emit(gpa, .OpBitcast, .{
54515837 .id_result_type = dst_ty_id,
54525838 .id_result = result_id,
......@@ -5456,12 +5842,24 @@ fn bitCast(
54565842 break :blk result_id;
54575843 }
54585844
5459 const dst_ptr_ty_id = try cg.module.ptrType(dst_ty_id, .function);
5845 switch (target.os.tag) {
5846 .vulkan, .opengl => {
5847 // Logical addressing forbids OpBitcast on pointers. Allocate
5848 // the temp with dst_ty so the load reads through a slot of the right type.
5849 const dst_ty_indirect_id = try cg.resolveType(dst_ty, .indirect);
5850 const tmp_id = try cg.alloc(dst_ty_indirect_id, null);
5851 try cg.store(dst_ty, tmp_id, src_id, .{});
5852 break :blk try cg.load(dst_ty, tmp_id, .{});
5853 },
5854 else => {},
5855 }
5856
5857 const dst_ptr_ty_id = try cg.ptrType(dst_ty_id, .function);
54605858
54615859 const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect);
54625860 const tmp_id = try cg.alloc(src_ty_indirect_id, null);
54635861 try cg.store(src_ty, tmp_id, src_id, .{});
5464 const casted_ptr_id = cg.module.allocId();
5862 const casted_ptr_id = cg.allocId();
54655863 try cg.body.emit(gpa, .OpBitcast, .{
54665864 .id_result_type = dst_ptr_ty_id,
54675865 .id_result = casted_ptr_id,
......@@ -5492,8 +5890,13 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
54925890 const result = try cg.intFromBool(operand, .u1);
54935891 return try result.materialize(cg);
54945892 }
5893 if (operand_ty.zigTypeTag(cg.zcu) == .pointer) {
5894 switch (try cg.resolvePtr(ty_op.operand)) {
5895 .tracked => |t| return t.id, // TODO
5896 .id => |operand_id| return try cg.bitCast(result_ty, operand_ty, operand_id),
5897 }
5898 }
54955899 const operand_id = try cg.resolve(ty_op.operand);
5496 if (cg.virtual_allocas.contains(operand_id)) return operand_id;
54975900 return try cg.bitCast(result_ty, operand_ty, operand_id);
54985901}
54995902
......@@ -5509,19 +5912,19 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55095912 const dst_composite = dst_info.class == .composite_integer;
55105913
55115914 if (src_composite or dst_composite) {
5512 const gpa = cg.module.gpa;
5915 const gpa = cg.gpa;
55135916 const scratch_top = cg.id_scratch.items.len;
55145917 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
55155918
55165919 if (src_composite and dst_composite) {
55175920 const src_id = try src.materialize(cg);
5518 const src_n: u16 = src_info.backing_bits / Module.big_int_bits;
5519 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;
5921 const src_n: u16 = src_info.backing_bits / big_int_bits;
5922 const dst_n: u16 = dst_info.backing_bits / big_int_bits;
55205923 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
55215924 const min_n = @min(src_n, dst_n);
55225925 const u32_ty_id = try cg.resolveType(.u32, .direct);
55235926 for (0..min_n) |i| {
5524 result_limbs[i] = cg.module.allocId();
5927 result_limbs[i] = cg.allocId();
55255928 try cg.body.emit(gpa, .OpCompositeExtract, .{
55265929 .id_result_type = u32_ty_id,
55275930 .id_result = result_limbs[i],
......@@ -5533,20 +5936,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55335936 const fill = if (src_info.signedness == .signed) blk: {
55345937 const i32_ty_id = try cg.resolveType(.i32, .direct);
55355938 const msb = result_limbs[src_n - 1];
5536 const msb_signed = cg.module.allocId();
5939 const msb_signed = cg.allocId();
55375940 try cg.body.emit(gpa, .OpBitcast, .{
55385941 .id_result_type = i32_ty_id,
55395942 .id_result = msb_signed,
55405943 .operand = msb,
55415944 });
55425945 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5543 const sign_ext = cg.module.allocId();
5544 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
5545 cg.body.writeOperand(Id, i32_ty_id);
5546 cg.body.writeOperand(Id, sign_ext);
5547 cg.body.writeOperand(Id, msb_signed);
5548 cg.body.writeOperand(Id, shift31);
5549 const back = cg.module.allocId();
5946 const sign_ext = cg.allocId();
5947 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5948 .id_result_type = i32_ty_id,
5949 .id_result = sign_ext,
5950 .base = msb_signed,
5951 .shift = shift31,
5952 });
5953 const back = cg.allocId();
55505954 try cg.body.emit(gpa, .OpBitcast, .{
55515955 .id_result_type = u32_ty_id,
55525956 .id_result = back,
......@@ -5565,7 +5969,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55655969 const src_id = try src.materialize(cg);
55665970 const u32_ty_id = try cg.resolveType(.u32, .direct);
55675971 if (dst_info.backing_bits <= 32) {
5568 const limb0 = cg.module.allocId();
5972 const limb0 = cg.allocId();
55695973 try cg.body.emit(gpa, .OpCompositeExtract, .{
55705974 .id_result_type = u32_ty_id,
55715975 .id_result = limb0,
......@@ -5580,14 +5984,14 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55805984 converted;
55815985 return try result.materialize(cg);
55825986 } else {
5583 const limb0 = cg.module.allocId();
5987 const limb0 = cg.allocId();
55845988 try cg.body.emit(gpa, .OpCompositeExtract, .{
55855989 .id_result_type = u32_ty_id,
55865990 .id_result = limb0,
55875991 .composite = src_id,
55885992 .indexes = &.{@as(u32, 0)},
55895993 });
5590 const limb1 = cg.module.allocId();
5994 const limb1 = cg.allocId();
55915995 try cg.body.emit(gpa, .OpCompositeExtract, .{
55925996 .id_result_type = u32_ty_id,
55935997 .id_result = limb1,
......@@ -5595,29 +5999,33 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55955999 .indexes = &.{@as(u32, 1)},
55966000 });
55976001 const u64_ty_id = try cg.resolveType(.u64, .direct);
5598 const lo = cg.module.allocId();
5599 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5600 cg.body.writeOperand(Id, u64_ty_id);
5601 cg.body.writeOperand(Id, lo);
5602 cg.body.writeOperand(Id, limb0);
5603 const hi = cg.module.allocId();
5604 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5605 cg.body.writeOperand(Id, u64_ty_id);
5606 cg.body.writeOperand(Id, hi);
5607 cg.body.writeOperand(Id, limb1);
6002 const lo = cg.allocId();
6003 try cg.body.emit(gpa, .OpUConvert, .{
6004 .id_result_type = u64_ty_id,
6005 .id_result = lo,
6006 .unsigned_value = limb0,
6007 });
6008 const hi = cg.allocId();
6009 try cg.body.emit(gpa, .OpUConvert, .{
6010 .id_result_type = u64_ty_id,
6011 .id_result = hi,
6012 .unsigned_value = limb1,
6013 });
56086014 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5609 const hi_shifted = cg.module.allocId();
5610 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);
5611 cg.body.writeOperand(Id, u64_ty_id);
5612 cg.body.writeOperand(Id, hi_shifted);
5613 cg.body.writeOperand(Id, hi);
5614 cg.body.writeOperand(Id, shift32);
5615 const combined = cg.module.allocId();
5616 try cg.body.emitRaw(gpa, .OpBitwiseOr, 4);
5617 cg.body.writeOperand(Id, u64_ty_id);
5618 cg.body.writeOperand(Id, combined);
5619 cg.body.writeOperand(Id, lo);
5620 cg.body.writeOperand(Id, hi_shifted);
6015 const hi_shifted = cg.allocId();
6016 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
6017 .id_result_type = u64_ty_id,
6018 .id_result = hi_shifted,
6019 .base = hi,
6020 .shift = shift32,
6021 });
6022 const combined = cg.allocId();
6023 try cg.body.emit(gpa, .OpBitwiseOr, .{
6024 .id_result_type = u64_ty_id,
6025 .id_result = combined,
6026 .operand_1 = lo,
6027 .operand_2 = hi_shifted,
6028 });
56216029 const tmp: Temporary = .init(.u64, combined);
56226030 const converted = try cg.buildConvert(dst_ty, tmp);
56236031 const result = if (dst_info.bits < src_info.bits)
......@@ -5627,7 +6035,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
56276035 return try result.materialize(cg);
56286036 }
56296037 } else {
5630 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;
6038 const dst_n: u16 = dst_info.backing_bits / big_int_bits;
56316039 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
56326040 const u32_ty_id = try cg.resolveType(.u32, .direct);
56336041
......@@ -5637,44 +6045,48 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
56376045 } else {
56386046 const src_as_u64 = try cg.buildConvert(.u64, src);
56396047 const src_id = try src_as_u64.materialize(cg);
5640 result_limbs[0] = cg.module.allocId();
5641 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5642 cg.body.writeOperand(Id, u32_ty_id);
5643 cg.body.writeOperand(Id, result_limbs[0]);
5644 cg.body.writeOperand(Id, src_id);
6048 result_limbs[0] = cg.allocId();
6049 try cg.body.emit(gpa, .OpUConvert, .{
6050 .id_result_type = u32_ty_id,
6051 .id_result = result_limbs[0],
6052 .unsigned_value = src_id,
6053 });
56456054 const u64_ty_id = try cg.resolveType(.u64, .direct);
56466055 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5647 const hi = cg.module.allocId();
5648 try cg.body.emitRaw(gpa, .OpShiftRightLogical, 4);
5649 cg.body.writeOperand(Id, u64_ty_id);
5650 cg.body.writeOperand(Id, hi);
5651 cg.body.writeOperand(Id, src_id);
5652 cg.body.writeOperand(Id, shift32);
5653 result_limbs[1] = cg.module.allocId();
5654 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5655 cg.body.writeOperand(Id, u32_ty_id);
5656 cg.body.writeOperand(Id, result_limbs[1]);
5657 cg.body.writeOperand(Id, hi);
6056 const hi = cg.allocId();
6057 try cg.body.emit(gpa, .OpShiftRightLogical, .{
6058 .id_result_type = u64_ty_id,
6059 .id_result = hi,
6060 .base = src_id,
6061 .shift = shift32,
6062 });
6063 result_limbs[1] = cg.allocId();
6064 try cg.body.emit(gpa, .OpUConvert, .{
6065 .id_result_type = u32_ty_id,
6066 .id_result = result_limbs[1],
6067 .unsigned_value = hi,
6068 });
56586069 }
56596070 // Sign/zero-extend remaining limbs.
56606071 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;
56616072 const fill = if (src_info.signedness == .signed) blk: {
56626073 const i32_ty_id = try cg.resolveType(.i32, .direct);
56636074 const msb = result_limbs[fill_start - 1];
5664 const msb_signed = cg.module.allocId();
6075 const msb_signed = cg.allocId();
56656076 try cg.body.emit(gpa, .OpBitcast, .{
56666077 .id_result_type = i32_ty_id,
56676078 .id_result = msb_signed,
56686079 .operand = msb,
56696080 });
56706081 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5671 const sign_ext = cg.module.allocId();
5672 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
5673 cg.body.writeOperand(Id, i32_ty_id);
5674 cg.body.writeOperand(Id, sign_ext);
5675 cg.body.writeOperand(Id, msb_signed);
5676 cg.body.writeOperand(Id, shift31);
5677 const back = cg.module.allocId();
6082 const sign_ext = cg.allocId();
6083 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
6084 .id_result_type = i32_ty_id,
6085 .id_result = sign_ext,
6086 .base = msb_signed,
6087 .shift = shift31,
6088 });
6089 const back = cg.allocId();
56786090 try cg.body.emit(gpa, .OpBitcast, .{
56796091 .id_result_type = u32_ty_id,
56806092 .id_result = back,
......@@ -5715,8 +6127,8 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
57156127
57166128fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
57176129 const result_type_id = try cg.resolveType(.usize, .direct);
5718 const result_id = cg.module.allocId();
5719 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{
6130 const result_id = cg.allocId();
6131 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
57206132 .id_result_type = result_type_id,
57216133 .id_result = result_id,
57226134 .pointer = operand_id,
......@@ -5725,17 +6137,13 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
57256137}
57266138
57276139fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6140 const gpa = cg.gpa;
57286141 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
57296142 const operand_ty = cg.typeOf(ty_op.operand);
57306143 const operand_id = try cg.resolve(ty_op.operand);
57316144 const result_ty = cg.typeOfIndex(inst);
5732 return try cg.floatFromInt(result_ty, operand_ty, operand_id);
5733}
5734
5735fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id) !Id {
5736 const gpa = cg.module.gpa;
57376145 const operand_info = cg.arithmeticTypeInfo(operand_ty);
5738 const result_id = cg.module.allocId();
6146 const result_id = cg.allocId();
57396147 const result_ty_id = try cg.resolveType(result_ty, .direct);
57406148 switch (operand_info.signedness) {
57416149 .signed => try cg.body.emit(gpa, .OpConvertSToF, .{
......@@ -5753,17 +6161,13 @@ fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id)
57536161}
57546162
57556163fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6164 const gpa = cg.gpa;
57566165 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
57576166 const operand_id = try cg.resolve(ty_op.operand);
57586167 const result_ty = cg.typeOfIndex(inst);
5759 return try cg.intFromFloat(result_ty, operand_id);
5760}
5761
5762fn intFromFloat(cg: *CodeGen, result_ty: Type, operand_id: Id) !Id {
5763 const gpa = cg.module.gpa;
57646168 const result_info = cg.arithmeticTypeInfo(result_ty);
57656169 const result_ty_id = try cg.resolveType(result_ty, .direct);
5766 const result_id = cg.module.allocId();
6170 const result_id = cg.allocId();
57676171 switch (result_info.signedness) {
57686172 .signed => try cg.body.emit(gpa, .OpConvertFToS, .{
57696173 .id_result_type = result_ty_id,
......@@ -5815,7 +6219,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
58156219}
58166220
58176221fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5818 const zcu = cg.module.zcu;
6222 const zcu = cg.zcu;
58196223 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
58206224 const array_ptr_ty = cg.typeOf(ty_op.operand);
58216225 const array_ty = array_ptr_ty.childType(zcu);
......@@ -5849,11 +6253,11 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
58496253}
58506254
58516255fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5852 const gpa = cg.module.gpa;
6256 const gpa = cg.gpa;
58536257 const pt = cg.pt;
5854 const zcu = cg.module.zcu;
6258 const zcu = cg.zcu;
58556259 const ip = &zcu.intern_pool;
5856 const target = cg.module.zcu.getTarget();
6260 const target = cg.zcu.getTarget();
58576261 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
58586262 const result_ty = cg.typeOfIndex(inst);
58596263 const len: usize = @intCast(result_ty.arrayLen(zcu));
......@@ -5978,23 +6382,8 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
59786382 }
59796383}
59806384
5981fn sliceOrArrayLen(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
5982 const zcu = cg.module.zcu;
5983 switch (ty.ptrSize(zcu)) {
5984 .slice => return cg.extractField(.usize, operand_id, 1),
5985 .one => {
5986 const array_ty = ty.childType(zcu);
5987 const elem_ty = array_ty.childType(zcu);
5988 const abi_size = elem_ty.abiSize(zcu);
5989 const size = array_ty.arrayLenIncludingSentinel(zcu) * abi_size;
5990 return try cg.constInt(.usize, size);
5991 },
5992 .many, .c => unreachable,
5993 }
5994}
5995
59966385fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
5997 const zcu = cg.module.zcu;
6386 const zcu = cg.zcu;
59986387 if (ty.isSlice(zcu)) {
59996388 const ptr_ty = ty.slicePtrFieldType(zcu);
60006389 return cg.extractField(ptr_ty, operand_id, 0);
......@@ -6010,8 +6399,17 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) !void {
60106399 const src_ty = cg.typeOf(bin_op.rhs);
60116400 const dest_ptr = try cg.sliceOrArrayPtr(dest_slice, dest_ty);
60126401 const src_ptr = try cg.sliceOrArrayPtr(src_slice, src_ty);
6013 const len = try cg.sliceOrArrayLen(dest_slice, dest_ty);
6014 try cg.body.emit(cg.module.gpa, .OpCopyMemorySized, .{
6402 const len = switch (dest_ty.ptrSize(cg.zcu)) {
6403 .slice => try cg.extractField(.usize, dest_slice, 1),
6404 .one => len: {
6405 const array_ty = dest_ty.childType(cg.zcu);
6406 const elem_ty = array_ty.childType(cg.zcu);
6407 const size = array_ty.arrayLenIncludingSentinel(cg.zcu) * elem_ty.abiSize(cg.zcu);
6408 break :len try cg.constInt(.usize, size);
6409 },
6410 .many, .c => unreachable,
6411 };
6412 try cg.body.emit(cg.gpa, .OpCopyMemorySized, .{
60156413 .target = dest_ptr,
60166414 .source = src_ptr,
60176415 .size = len,
......@@ -6031,12 +6429,12 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {
60316429}
60326430
60336431fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6034 const gpa = cg.module.gpa;
6432 const gpa = cg.gpa;
60356433 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
60366434 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
60376435 const struct_ptr_id = try cg.resolve(extra.struct_operand);
6038 const u32_ty_id = try cg.module.intType(.unsigned, 32);
6039 const result_id = cg.module.allocId();
6436 const u32_ty_id = try cg.intType(.unsigned, 32);
6437 const result_id = cg.allocId();
60406438 try cg.body.emit(gpa, .OpArrayLength, .{
60416439 .id_result_type = u32_ty_id,
60426440 .id_result = result_id,
......@@ -6047,7 +6445,7 @@ fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
60476445}
60486446
60496447fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6050 const zcu = cg.module.zcu;
6448 const zcu = cg.zcu;
60516449 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
60526450 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
60536451 const slice_ty = cg.typeOf(bin_op.lhs);
......@@ -6064,7 +6462,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
60646462}
60656463
60666464fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6067 const zcu = cg.module.zcu;
6465 const zcu = cg.zcu;
60686466 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
60696467 const slice_ty = cg.typeOf(bin_op.lhs);
60706468 if (!slice_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;
......@@ -6081,11 +6479,11 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
60816479}
60826480
60836481fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
6084 const zcu = cg.module.zcu;
6482 const zcu = cg.zcu;
60856483 // Construct new pointer type for the resulting pointer
60866484 const elem_ty = ptr_ty.indexableElem(zcu);
60876485 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
6088 const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));
6486 const elem_ptr_ty_id = try cg.ptrType(elem_ty_id, cg.storageClass(ptr_ty.ptrAddressSpace(zcu)));
60896487 if (ptr_ty.isSinglePointer(zcu)) {
60906488 // Pointer-to-array. In this case, the resulting pointer is not of the same type
60916489 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.
......@@ -6097,7 +6495,7 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
60976495}
60986496
60996497fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6100 const zcu = cg.module.zcu;
6498 const zcu = cg.zcu;
61016499 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
61026500 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
61036501 const src_ptr_ty = cg.typeOf(bin_op.lhs);
......@@ -6111,8 +6509,8 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61116509}
61126510
61136511fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6114 const gpa = cg.module.gpa;
6115 const zcu = cg.module.zcu;
6512 const gpa = cg.gpa;
6513 const zcu = cg.zcu;
61166514 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
61176515 const array_ty = cg.typeOf(bin_op.lhs);
61186516 const elem_ty = array_ty.childType(zcu);
......@@ -6127,10 +6525,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61276525 const elem_repr: Repr = if (is_vector) .direct else .indirect;
61286526 const array_ty_id = try cg.resolveType(array_ty, .direct);
61296527 const elem_ty_id = try cg.resolveType(elem_ty, elem_repr);
6130 const ptr_array_ty_id = try cg.module.ptrType(array_ty_id, .function);
6131 const ptr_elem_ty_id = try cg.module.ptrType(elem_ty_id, .function);
6528 const ptr_array_ty_id = try cg.ptrType(array_ty_id, .function);
6529 const ptr_elem_ty_id = try cg.ptrType(elem_ty_id, .function);
61326530
6133 const tmp_id = cg.module.allocId();
6531 const tmp_id = cg.allocId();
61346532 try cg.prologue.emit(gpa, .OpVariable, .{
61356533 .id_result_type = ptr_array_ty_id,
61366534 .id_result = tmp_id,
......@@ -6144,7 +6542,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61446542
61456543 const elem_ptr_id = try cg.accessChainId(ptr_elem_ty_id, tmp_id, &.{index_id});
61466544
6147 const result_id = cg.module.allocId();
6545 const result_id = cg.allocId();
61486546 try cg.body.emit(gpa, .OpLoad, .{
61496547 .id_result_type = try cg.resolveType(elem_ty, elem_repr),
61506548 .id_result = result_id,
......@@ -6163,7 +6561,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61636561}
61646562
61656563fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6166 const zcu = cg.module.zcu;
6564 const zcu = cg.zcu;
61676565 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
61686566 const ptr_ty = cg.typeOf(bin_op.lhs);
61696567 const elem_ty = cg.typeOfIndex(inst);
......@@ -6174,7 +6572,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61746572}
61756573
61766574fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
6177 const zcu = cg.module.zcu;
6575 const zcu = cg.zcu;
61786576 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
61796577 const un_ptr_ty = cg.typeOf(bin_op.lhs);
61806578 const un_ty = un_ptr_ty.childType(zcu);
......@@ -6184,7 +6582,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
61846582
61856583 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
61866584 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
6187 const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, cg.module.storageClass(un_ptr_ty.ptrAddressSpace(zcu)));
6585 const tag_ptr_ty_id = try cg.ptrType(tag_ty_id, cg.storageClass(un_ptr_ty.ptrAddressSpace(zcu)));
61886586
61896587 const union_ptr_id = try cg.resolve(bin_op.lhs);
61906588 const new_tag_id = try cg.resolve(bin_op.rhs);
......@@ -6201,7 +6599,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
62016599 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
62026600 const un_ty = cg.typeOf(ty_op.operand);
62036601
6204 const zcu = cg.module.zcu;
6602 const zcu = cg.zcu;
62056603 const layout = cg.unionLayout(un_ty);
62066604 if (layout.tag_size == 0) return null;
62076605
......@@ -6225,7 +6623,7 @@ fn unionInit(
62256623 // Note: The result here is not cached, because it generates runtime code.
62266624
62276625 const pt = cg.pt;
6228 const zcu = cg.module.zcu;
6626 const zcu = cg.zcu;
62296627 const ip = &zcu.intern_pool;
62306628 const union_ty = zcu.typeToUnion(ty).?;
62316629 const tag_ty: Type = .fromInterned(union_ty.enum_tag_type);
......@@ -6250,7 +6648,7 @@ fn unionInit(
62506648
62516649 if (layout.tag_size != 0) {
62526650 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
6253 const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, .function);
6651 const tag_ptr_ty_id = try cg.ptrType(tag_ty_id, .function);
62546652 const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
62556653 const tag_id = try cg.constInt(tag_ty, tag_int);
62566654 try cg.store(tag_ty, ptr_id, tag_id, .{});
......@@ -6258,13 +6656,13 @@ fn unionInit(
62586656
62596657 if (payload_ty.hasRuntimeBits(zcu)) {
62606658 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
6261 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, .function);
6659 const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, .function);
62626660 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
62636661 const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty)) blk: {
62646662 const payload_ty_id = try cg.resolveType(payload_ty, .indirect);
6265 const active_pl_ptr_ty_id = try cg.module.ptrType(payload_ty_id, .function);
6266 const active_pl_ptr_id = cg.module.allocId();
6267 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
6663 const active_pl_ptr_ty_id = try cg.ptrType(payload_ty_id, .function);
6664 const active_pl_ptr_id = cg.allocId();
6665 try cg.body.emit(cg.gpa, .OpBitcast, .{
62686666 .id_result_type = active_pl_ptr_ty_id,
62696667 .id_result = active_pl_ptr_id,
62706668 .operand = pl_ptr_id,
......@@ -6284,7 +6682,7 @@ fn unionInit(
62846682}
62856683
62866684fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6287 const zcu = cg.module.zcu;
6685 const zcu = cg.zcu;
62886686 const ip = &zcu.intern_pool;
62896687 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
62906688 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
......@@ -6301,7 +6699,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63016699
63026700fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63036701 const pt = cg.pt;
6304 const zcu = cg.module.zcu;
6702 const zcu = cg.zcu;
63056703 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
63066704 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
63076705
......@@ -6316,7 +6714,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63166714 .@"struct" => switch (object_ty.containerLayout(zcu)) {
63176715 .@"packed" => {
63186716 const struct_ty = zcu.typeToPackedStruct(object_ty).?;
6319 const struct_backing_int_bits = cg.module.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0";
6717 const struct_backing_int_bits = cg.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0";
63206718 const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index);
63216719 // We use the same int type the packed struct is backed by, because even though it would
63226720 // be valid SPIR-V to use an smaller type like u16, some implementations like PoCL will complain.
......@@ -6329,7 +6727,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63296727 const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1);
63306728 const masked = try cg.buildBinary(.OpBitwiseAnd, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });
63316729 const result_id = blk: {
6332 if (cg.module.backingIntBits(field_bit_size).@"0" == struct_backing_int_bits)
6730 if (cg.backingIntBits(field_bit_size).@"0" == struct_backing_int_bits)
63336731 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));
63346732 const trunc = try cg.buildConvert(field_int_ty, masked);
63356733 break :blk try trunc.materialize(cg);
......@@ -6353,7 +6751,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63536751 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },
63546752 );
63556753 const result_id = blk: {
6356 if (cg.module.backingIntBits(field_bit_size).@"0" == cg.module.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0")
6754 if (cg.backingIntBits(field_bit_size).@"0" == cg.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0")
63576755 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));
63586756 const trunc = try cg.buildConvert(int_ty, masked);
63596757 break :blk try trunc.materialize(cg);
......@@ -6372,13 +6770,13 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63726770 try cg.store(object_ty, tmp_id, object_id, .{});
63736771
63746772 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
6375 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, .function);
6773 const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, .function);
63766774 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
63776775
63786776 const field_ty_id = try cg.resolveType(field_ty, .indirect);
6379 const active_pl_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);
6380 const active_pl_ptr_id = cg.module.allocId();
6381 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
6777 const active_pl_ptr_ty_id = try cg.ptrType(field_ty_id, .function);
6778 const active_pl_ptr_id = cg.allocId();
6779 try cg.body.emit(cg.gpa, .OpBitcast, .{
63826780 .id_result_type = active_pl_ptr_ty_id,
63836781 .id_result = active_pl_ptr_id,
63846782 .operand = pl_ptr_id,
......@@ -6391,7 +6789,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63916789}
63926790
63936791fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6394 const zcu = cg.module.zcu;
6792 const zcu = cg.zcu;
63956793 const target = zcu.getTarget();
63966794 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
63976795 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
......@@ -6424,8 +6822,8 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
64246822 }
64256823 }
64266824
6427 const base_ptr = cg.module.allocId();
6428 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{
6825 const base_ptr = cg.allocId();
6826 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
64296827 .id_result_type = result_ty_id,
64306828 .id_result = base_ptr,
64316829 .integer_value = base_ptr_int,
......@@ -6443,7 +6841,7 @@ fn structFieldPtr(
64436841) !Id {
64446842 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);
64456843
6446 const zcu = cg.module.zcu;
6844 const zcu = cg.zcu;
64476845 const object_ty = object_ptr_ty.childType(zcu);
64486846 switch (object_ty.zigTypeTag(zcu)) {
64496847 .pointer => {
......@@ -6455,8 +6853,8 @@ fn structFieldPtr(
64556853 const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu);
64566854 if (byte_offset == 0) return object_ptr;
64576855 const usize_ty_id = try cg.resolveType(.usize, .direct);
6458 const base_int = cg.module.allocId();
6459 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{
6856 const base_int = cg.allocId();
6857 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
64606858 .id_result_type = usize_ty_id,
64616859 .id_result = base_int,
64626860 .pointer = object_ptr,
......@@ -6464,8 +6862,8 @@ fn structFieldPtr(
64646862 const offset_id = try cg.constInt(.usize, byte_offset);
64656863 const adjusted = try cg.buildBinary(.OpIAdd, .{ .ty = .usize, .value = .{ .singleton = base_int } }, .{ .ty = .usize, .value = .{ .singleton = offset_id } });
64666864 const adjusted_id = try adjusted.materialize(cg);
6467 const result_id = cg.module.allocId();
6468 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{
6865 const result_id = cg.allocId();
6866 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
64696867 .id_result_type = result_ty_id,
64706868 .id_result = result_id,
64716869 .integer_value = adjusted_id,
......@@ -6483,19 +6881,19 @@ fn structFieldPtr(
64836881 if (!layout.has_payload) {
64846882 // Asked to get a pointer to a zero-sized field. Just lower this
64856883 // to undefined, there is no reason to make it be a valid pointer.
6486 return try cg.module.constUndef(result_ty_id);
6884 return try cg.constUndef(result_ty_id);
64876885 }
64886886
6489 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
6887 const storage_class = cg.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
64906888 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
6491 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, storage_class);
6889 const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, storage_class);
64926890 const pl_ptr_id = blk: {
64936891 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
64946892 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
64956893 };
64966894
6497 const active_pl_ptr_id = cg.module.allocId();
6498 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
6895 const active_pl_ptr_id = cg.allocId();
6896 try cg.body.emit(cg.gpa, .OpBitcast, .{
64996897 .id_result_type = result_ty_id,
65006898 .id_result = active_pl_ptr_id,
65016899 .operand = pl_ptr_id,
......@@ -6525,9 +6923,9 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32)
65256923}
65266924
65276925fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
6528 const ptr_ty_id = try cg.module.ptrType(ty_id, .function);
6529 const result_id = cg.module.allocId();
6530 try cg.prologue.emit(cg.module.gpa, .OpVariable, .{
6926 const ptr_ty_id = try cg.ptrType(ty_id, .function);
6927 const result_id = cg.allocId();
6928 try cg.prologue.emit(cg.gpa, .OpVariable, .{
65316929 .id_result_type = ptr_ty_id,
65326930 .id_result = result_id,
65336931 .storage_class = .function,
......@@ -6537,7 +6935,7 @@ fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
65376935}
65386936
65396937fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6540 const zcu = cg.module.zcu;
6938 const zcu = cg.zcu;
65416939 const target = zcu.getTarget();
65426940 const ptr_ty = cg.typeOfIndex(inst);
65436941 const child_ty = ptr_ty.childType(zcu);
......@@ -6546,9 +6944,9 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
65466944 .vulkan, .opengl => {
65476945 if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) {
65486946 const as = child_ty.ptrAddressSpace(zcu);
6549 if (cg.module.storageClass(as) == .function) {
6550 const result_id = cg.module.allocId();
6551 try cg.virtual_allocas.put(cg.module.gpa, result_id, null);
6947 if (cg.storageClass(as) == .function) {
6948 const result_id = cg.allocId();
6949 try cg.tracked_allocas.put(cg.gpa, result_id, null);
65526950 return result_id;
65536951 }
65546952 }
......@@ -6561,7 +6959,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
65616959 const result_id = try cg.alloc(child_ty_id, null);
65626960 if (ptr_align != child_ty.abiAlignment(zcu)) {
65636961 if (target.os.tag != .opencl) return cg.fail("cannot apply alignment to variables", .{});
6564 try cg.module.decorate(result_id, .{
6962 try cg.decorate(result_id, .{
65656963 .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) },
65666964 });
65676965 }
......@@ -6578,9 +6976,9 @@ fn airArg(cg: *CodeGen) Id {
65786976/// inside the merge block of the block.
65796977/// This function should only be called with structured control flow generation.
65806978fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
6581 const result_id = cg.module.allocId();
6979 const result_id = cg.allocId();
65826980 const block_id_ty_id = try cg.resolveType(.u32, .direct);
6583 try cg.body.emitRaw(cg.module.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...
6981 try cg.body.emitRaw(cg.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...
65846982 cg.body.writeOperand(Id, block_id_ty_id);
65856983 cg.body.writeOperand(Id, result_id);
65866984
......@@ -6597,11 +6995,11 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
65976995fn structuredBreak(cg: *CodeGen, target_block: Id) !void {
65986996 if (cg.block_terminated) return;
65996997
6600 const gpa = cg.module.gpa;
6998 const gpa = cg.gpa;
66016999 const sblock = cg.block_stack.getLast().?;
66027000 const merge_block = switch (sblock.*) {
66037001 .selection => |*merge| blk: {
6604 const merge_label = cg.module.allocId();
7002 const merge_label = cg.allocId();
66057003 try merge.merge_stack.append(gpa, .{
66067004 .incoming = .{
66077005 .src_label = cg.block_label,
......@@ -6641,7 +7039,7 @@ fn genStructuredBody(
66417039 },
66427040 body: []const Air.Inst.Index,
66437041) !Id {
6644 const gpa = cg.module.gpa;
7042 const gpa = cg.gpa;
66457043
66467044 var sblock: Block = switch (block_merge_type) {
66477045 .loop => |merge| .{ .loop = .{
......@@ -6679,9 +7077,9 @@ fn genStructuredBody(
66797077
66807078 // Make sure that we are still in a block when exiting the function.
66817079 // TODO: Can we get rid of that?
6682 try cg.beginSpvBlock(cg.module.allocId());
7080 try cg.beginSpvBlock(cg.allocId());
66837081 const block_id_ty_id = try cg.resolveType(.u32, .direct);
6684 return try cg.module.constUndef(block_id_ty_id);
7082 return try cg.constUndef(block_id_ty_id);
66857083 }
66867084
66877085 // The top-most merge actually only has a single source, the
......@@ -6735,8 +7133,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
67357133 // of the block, then a label, and then generate the rest of the current
67367134 // ir.Block in a different SPIR-V block.
67377135
6738 const gpa = cg.module.gpa;
6739 const zcu = cg.module.zcu;
7136 const gpa = cg.gpa;
7137 const zcu = cg.zcu;
67407138 const ty = cg.typeOfIndex(inst);
67417139 const have_block_result = ty.hasRuntimeBits(zcu);
67427140
......@@ -6756,7 +7154,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
67567154
67577155 // Check if the target of the branch was this current block.
67587156 const this_block = try cg.constInt(.u32, @intFromEnum(inst));
6759 const jump_to_this_block_id = cg.module.allocId();
7157 const jump_to_this_block_id = cg.allocId();
67607158 const bool_ty_id = try cg.resolveType(.bool, .direct);
67617159 try cg.body.emit(gpa, .OpIEqual, .{
67627160 .id_result_type = bool_ty_id,
......@@ -6776,8 +7174,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
67767174 .selection => |*merge| {
67777175 // To jump out of a selection block, push a new entry onto its merge stack and
67787176 // generate a conditional branch to there and to the instructions following this block.
6779 const merge_label = cg.module.allocId();
6780 const then_label = cg.module.allocId();
7177 const merge_label = cg.allocId();
7178 const then_label = cg.allocId();
67817179 try cg.body.emit(gpa, .OpSelectionMerge, .{
67827180 .merge_block = merge_label,
67837181 .selection_control = .{},
......@@ -6800,7 +7198,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
68007198 .loop => |*merge| {
68017199 // To jump out of a loop block, generate a conditional that exits the block
68027200 // to the loop merge if the target ID is not the one of this block.
6803 const continue_label = cg.module.allocId();
7201 const continue_label = cg.allocId();
68047202 try cg.body.emit(gpa, .OpBranchConditional, .{
68057203 .condition = jump_to_this_block_id,
68067204 .true_label = continue_label,
......@@ -6823,7 +7221,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
68237221}
68247222
68257223fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6826 const zcu = cg.module.zcu;
7224 const zcu = cg.zcu;
68277225 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
68287226 const operand_ty = cg.typeOf(br.operand);
68297227
......@@ -6838,16 +7236,16 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
68387236}
68397237
68407238fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6841 const gpa = cg.module.gpa;
7239 const gpa = cg.gpa;
68427240 const cond_br = cg.air.unwrapCondBr(inst);
68437241 const then_body = cond_br.then_body;
68447242 const else_body = cond_br.else_body;
68457243 const condition_id = try cg.resolve(cond_br.condition);
68467244
6847 const then_label = cg.module.allocId();
6848 const else_label = cg.module.allocId();
7245 const then_label = cg.allocId();
7246 const else_label = cg.allocId();
68497247
6850 const merge_label = cg.module.allocId();
7248 const merge_label = cg.allocId();
68517249
68527250 try cg.body.emit(gpa, .OpSelectionMerge, .{
68537251 .merge_block = merge_label,
......@@ -6888,14 +7286,14 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
68887286}
68897287
68907288fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
6891 const gpa = cg.module.gpa;
7289 const gpa = cg.gpa;
68927290 const block = cg.air.unwrapBlock(inst);
68937291
6894 const body_label = cg.module.allocId();
7292 const body_label = cg.allocId();
68957293
6896 const header_label = cg.module.allocId();
6897 const merge_label = cg.module.allocId();
6898 const continue_label = cg.module.allocId();
7294 const header_label = cg.allocId();
7295 const merge_label = cg.allocId();
7296 const continue_label = cg.allocId();
68997297
69007298 // The back-edge must point to the loop header, so generate a separate block for the
69017299 // loop header so that we don't accidentally include some instructions from there
......@@ -6927,18 +7325,19 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
69277325}
69287326
69297327fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6930 const zcu = cg.module.zcu;
7328 const zcu = cg.zcu;
69317329 const pt = cg.pt;
69327330 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6933
6934 const ptr_info = cg.typeOf(ty_op.operand).ptrInfo(zcu);
6935
7331 const ptr_ty = cg.typeOf(ty_op.operand);
7332 const ptr_info = ptr_ty.ptrInfo(zcu);
69367333 const elem_ty = cg.typeOfIndex(inst);
6937 const operand_ptr_id = try cg.resolve(ty_op.operand);
6938
7334 const ptr = try cg.resolvePtr(ty_op.operand);
69397335 assert(ptr_info.child == elem_ty.toIntern());
69407336
6941 if (cg.virtual_allocas.get(operand_ptr_id)) |stored| return stored.?;
7337 const operand_ptr_id = switch (ptr) {
7338 .tracked => |t| return t.slot.*.?,
7339 .id => |id| id,
7340 };
69427341
69437342 if (ptr_info.packed_offset.host_size != 0 and
69447343 ptr_info.flags.vector_index == .none)
......@@ -6955,7 +7354,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
69557354 break :blk try shifted.materialize(cg);
69567355 } else host_val;
69577356 const result_id = blk: {
6958 if (cg.module.backingIntBits(elem_bit_size).@"0" == cg.module.backingIntBits(host_bits).@"0")
7357 if (cg.backingIntBits(elem_bit_size).@"0" == cg.backingIntBits(host_bits).@"0")
69597358 break :blk try cg.bitCast(field_int_ty, host_int_ty, narrowed);
69607359 const trunc = try cg.buildConvert(field_int_ty, .{ .ty = host_int_ty, .value = .{ .singleton = narrowed } });
69617360 break :blk try trunc.materialize(cg);
......@@ -6968,9 +7367,9 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
69687367 const ptr_id = switch (ptr_info.flags.vector_index) {
69697368 .none => operand_ptr_id,
69707369 else => |index| ptr_id: {
6971 const elem_ptr_ty_id = try cg.module.ptrType(
7370 const elem_ptr_ty_id = try cg.ptrType(
69727371 try cg.resolveType(elem_ty, .indirect),
6973 cg.module.storageClass(ptr_info.flags.address_space),
7372 cg.storageClass(ptr_info.flags.address_space),
69747373 );
69757374 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
69767375 },
......@@ -6979,18 +7378,20 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
69797378}
69807379
69817380fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
6982 const zcu = cg.module.zcu;
7381 const zcu = cg.zcu;
69837382 const pt = cg.pt;
69847383 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6985 const ptr_info = cg.typeOf(bin_op.lhs).ptrInfo(zcu);
7384 const ptr_ty = cg.typeOf(bin_op.lhs);
7385 const ptr_info = ptr_ty.ptrInfo(zcu);
69867386 const elem_ty: Type = .fromInterned(ptr_info.child);
6987 const operand_ptr_id = try cg.resolve(bin_op.lhs);
69887387 const value_id = try cg.resolve(bin_op.rhs);
6989
6990 if (cg.virtual_allocas.getPtr(operand_ptr_id)) |slot| {
6991 slot.* = value_id;
6992 return;
6993 }
7388 const operand_ptr_id = switch (try cg.resolvePtr(bin_op.lhs)) {
7389 .tracked => |t| {
7390 t.slot.* = value_id;
7391 return;
7392 },
7393 .id => |id| id,
7394 };
69947395
69957396 if (ptr_info.packed_offset.host_size != 0 and
69967397 ptr_info.flags.vector_index == .none)
......@@ -7013,7 +7414,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
70137414 }
70147415
70157416 const extended = blk: {
7016 if (cg.module.backingIntBits(elem_bit_size).@"0" == cg.module.backingIntBits(host_bits).@"0")
7417 if (cg.backingIntBits(elem_bit_size).@"0" == cg.backingIntBits(host_bits).@"0")
70177418 break :blk try cg.bitCast(host_int_ty, field_int_ty, value_as_int);
70187419 const conv = try cg.buildConvert(host_int_ty, .{ .ty = field_int_ty, .value = .{ .singleton = value_as_int } });
70197420 break :blk try conv.materialize(cg);
......@@ -7037,9 +7438,9 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
70377438 const ptr_id = switch (ptr_info.flags.vector_index) {
70387439 .none => operand_ptr_id,
70397440 else => |index| ptr_id: {
7040 const elem_ptr_ty_id = try cg.module.ptrType(
7441 const elem_ptr_ty_id = try cg.ptrType(
70417442 try cg.resolveType(elem_ty, .indirect),
7042 cg.module.storageClass(ptr_info.flags.address_space),
7443 cg.storageClass(ptr_info.flags.address_space),
70437444 );
70447445 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
70457446 },
......@@ -7049,8 +7450,8 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
70497450}
70507451
70517452fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
7052 const gpa = cg.module.gpa;
7053 const zcu = cg.module.zcu;
7453 const gpa = cg.gpa;
7454 const zcu = cg.zcu;
70547455 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
70557456 const ret_ty = cg.typeOf(operand);
70567457 if (!ret_ty.hasRuntimeBits(zcu)) {
......@@ -7071,8 +7472,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
70717472}
70727473
70737474fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
7074 const gpa = cg.module.gpa;
7075 const zcu = cg.module.zcu;
7475 const gpa = cg.gpa;
7476 const zcu = cg.zcu;
70767477 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
70777478 const ptr_ty = cg.typeOf(un_op);
70787479 const ret_ty = ptr_ty.childType(zcu);
......@@ -7090,16 +7491,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
70907491 }
70917492 }
70927493
7093 const ptr = try cg.resolve(un_op);
7094 const value = try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
7494 const value = switch (try cg.resolvePtr(un_op)) {
7495 .tracked => |t| t.slot.*.?,
7496 .id => |ptr| try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }),
7497 };
70957498 try cg.body.emit(gpa, .OpReturnValue, .{
70967499 .value = value,
70977500 });
70987501}
70997502
71007503fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7101 const gpa = cg.module.gpa;
7102 const zcu = cg.module.zcu;
7504 const gpa = cg.gpa;
7505 const zcu = cg.zcu;
71037506 const unwrapped_try = cg.air.unwrapTry(inst);
71047507 const body = unwrapped_try.else_body;
71057508
......@@ -7118,7 +7521,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71187521 err_union_id;
71197522
71207523 const zero_id = try cg.constInt(.anyerror, 0);
7121 const is_err_id = cg.module.allocId();
7524 const is_err_id = cg.allocId();
71227525 try cg.body.emit(gpa, .OpINotEqual, .{
71237526 .id_result_type = bool_ty_id,
71247527 .id_result = is_err_id,
......@@ -7130,8 +7533,8 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71307533 // with the current body.
71317534 // Just generate a new block here, then generate a new block inline for the remainder of the body.
71327535
7133 const err_block = cg.module.allocId();
7134 const ok_block = cg.module.allocId();
7536 const err_block = cg.allocId();
7537 const ok_block = cg.allocId();
71357538
71367539 // According to AIR documentation, this block is guaranteed
71377540 // to not break and end in a return instruction. Thus,
......@@ -7162,7 +7565,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71627565}
71637566
71647567fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7165 const zcu = cg.module.zcu;
7568 const zcu = cg.zcu;
71667569 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
71677570 const operand_id = try cg.resolve(ty_op.operand);
71687571 const err_union_ty = cg.typeOf(ty_op.operand);
......@@ -7170,7 +7573,7 @@ fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71707573
71717574 if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
71727575 // No error possible, so just return undefined.
7173 return try cg.module.constUndef(err_ty_id);
7576 return try cg.constUndef(err_ty_id);
71747577 }
71757578
71767579 const payload_ty = err_union_ty.errorUnionPayload(zcu);
......@@ -7198,7 +7601,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71987601}
71997602
72007603fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7201 const zcu = cg.module.zcu;
7604 const zcu = cg.zcu;
72027605 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
72037606 const err_union_ty = cg.typeOfIndex(inst);
72047607 const payload_ty = err_union_ty.errorUnionPayload(zcu);
......@@ -7213,7 +7616,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
72137616
72147617 var members: [2]Id = undefined;
72157618 members[eu_layout.errorFieldIndex()] = operand_id;
7216 members[eu_layout.payloadFieldIndex()] = try cg.module.constUndef(payload_ty_id);
7619 members[eu_layout.payloadFieldIndex()] = try cg.constUndef(payload_ty_id);
72177620
72187621 var types: [2]Type = undefined;
72197622 types[eu_layout.errorFieldIndex()] = .anyerror;
......@@ -7247,7 +7650,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
72477650}
72487651
72497652fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?Id {
7250 const zcu = cg.module.zcu;
7653 const zcu = cg.zcu;
72517654 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
72527655 const operand_id = try cg.resolve(un_op);
72537656 const operand_ty = cg.typeOf(un_op);
......@@ -7274,7 +7677,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
72747677 loaded_id;
72757678
72767679 const ptr_ty_id = try cg.resolveType(ptr_ty, .direct);
7277 const null_id = try cg.module.constNull(ptr_ty_id);
7680 const null_id = try cg.constNull(ptr_ty_id);
72787681 const null_tmp: Temporary = .init(ptr_ty, null_id);
72797682 const ptr: Temporary = .init(ptr_ty, ptr_id);
72807683
......@@ -7289,9 +7692,9 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
72897692 const is_non_null_id = blk: {
72907693 if (is_pointer) {
72917694 if (payload_ty.hasRuntimeBits(zcu)) {
7292 const storage_class = cg.module.storageClass(operand_ty.ptrAddressSpace(zcu));
7695 const storage_class = cg.storageClass(operand_ty.ptrAddressSpace(zcu));
72937696 const bool_indirect_ty_id = try cg.resolveType(.bool, .indirect);
7294 const bool_ptr_ty_id = try cg.module.ptrType(bool_indirect_ty_id, storage_class);
7697 const bool_ptr_ty_id = try cg.ptrType(bool_indirect_ty_id, storage_class);
72957698 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});
72967699 break :blk try cg.load(.bool, tag_ptr_id, .{});
72977700 }
......@@ -7311,8 +7714,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
73117714 return switch (pred) {
73127715 .is_null => blk: {
73137716 // Invert condition
7314 const result_id = cg.module.allocId();
7315 try cg.body.emit(cg.module.gpa, .OpLogicalNot, .{
7717 const result_id = cg.allocId();
7718 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
73167719 .id_result_type = bool_ty_id,
73177720 .id_result = result_id,
73187721 .operand = is_non_null_id,
......@@ -7324,7 +7727,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
73247727}
73257728
73267729fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?Id {
7327 const zcu = cg.module.zcu;
7730 const zcu = cg.zcu;
73287731 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
73297732 const operand_id = try cg.resolve(un_op);
73307733 const err_union_ty = cg.typeOf(un_op);
......@@ -7342,10 +7745,10 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
73427745 else
73437746 try cg.extractField(.anyerror, operand_id, eu_layout.errorFieldIndex());
73447747
7345 const result_id = cg.module.allocId();
7748 const result_id = cg.allocId();
73467749 switch (pred) {
73477750 inline else => |pred_ct| try cg.body.emit(
7348 cg.module.gpa,
7751 cg.gpa,
73497752 switch (pred_ct) {
73507753 .is_err => .OpINotEqual,
73517754 .is_non_err => .OpIEqual,
......@@ -7362,7 +7765,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
73627765}
73637766
73647767fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7365 const zcu = cg.module.zcu;
7768 const zcu = cg.zcu;
73667769 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
73677770 const operand_id = try cg.resolve(ty_op.operand);
73687771 const optional_ty = cg.typeOf(ty_op.operand);
......@@ -7378,7 +7781,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
73787781}
73797782
73807783fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7381 const zcu = cg.module.zcu;
7784 const zcu = cg.zcu;
73827785 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
73837786 const operand_id = try cg.resolve(ty_op.operand);
73847787 const operand_ty = cg.typeOf(ty_op.operand);
......@@ -7402,7 +7805,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
74027805}
74037806
74047807fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7405 const zcu = cg.module.zcu;
7808 const zcu = cg.zcu;
74067809 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
74077810 const payload_ty = cg.typeOf(ty_op.operand);
74087811
......@@ -7422,9 +7825,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
74227825}
74237826
74247827fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7425 const gpa = cg.module.gpa;
7426 const zcu = cg.module.zcu;
7427 const target = cg.module.zcu.getTarget();
7828 const gpa = cg.gpa;
7829 const zcu = cg.zcu;
7830 const target = cg.zcu.getTarget();
74287831 const switch_br = cg.air.unwrapSwitch(inst);
74297832 const cond_ty = cg.typeOf(switch_br.operand);
74307833 const cond = try cg.resolve(switch_br.operand);
......@@ -7434,14 +7837,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
74347837 .bool, .error_set => 1,
74357838 .int => blk: {
74367839 const bits = cond_ty.intInfo(zcu).bits;
7437 const backing_bits, const big_int = cg.module.backingIntBits(bits);
7840 const backing_bits, const big_int = cg.backingIntBits(bits);
74387841 if (big_int) return cg.todo("implement composite int switch", .{});
74397842 break :blk if (backing_bits <= 32) 1 else 2;
74407843 },
74417844 .@"enum" => blk: {
74427845 const int_ty = cond_ty.intTagType(zcu);
74437846 const int_info = int_ty.intInfo(zcu);
7444 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
7847 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
74457848 if (big_int) return cg.todo("implement composite int switch", .{});
74467849 break :blk if (backing_bits <= 32) 1 else 2;
74477850 },
......@@ -7470,12 +7873,12 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
74707873 }
74717874
74727875 // First, pre-allocate the labels for the cases.
7473 const case_labels = cg.module.allocIds(num_cases);
7876 const case_labels = cg.allocIds(num_cases);
74747877 // We always need the default case - if zig has none, we will generate unreachable there.
7475 const default_label = cg.module.allocId();
7476 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;
7878 const default_label = cg.allocId();
7879 const switch_default = if (last_range_case != null) cg.allocId() else default_label;
74777880
7478 const merge_label = cg.module.allocId();
7881 const merge_label = cg.allocId();
74797882
74807883 try cg.body.emit(gpa, .OpSelectionMerge, .{
74817884 .merge_block = merge_label,
......@@ -7540,12 +7943,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
75407943 const item_tmp: Temporary = try cg.temporary(item);
75417944 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
75427945 case_cond = if (case_cond) |prev| blk: {
7543 const combined = cg.module.allocId();
7544 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7545 cg.body.writeOperand(Id, bool_ty_id);
7546 cg.body.writeOperand(Id, combined);
7547 cg.body.writeOperand(Id, prev);
7548 cg.body.writeOperand(Id, eq);
7946 const combined = cg.allocId();
7947 try cg.body.emit(gpa, .OpLogicalOr, .{
7948 .id_result_type = bool_ty_id,
7949 .id_result = combined,
7950 .operand_1 = prev,
7951 .operand_2 = eq,
7952 });
75497953 break :blk combined;
75507954 } else eq;
75517955 }
......@@ -7555,26 +7959,28 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
75557959 const hi_tmp: Temporary = try cg.temporary(range[1]);
75567960 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
75577961 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7558 const in_range = cg.module.allocId();
7559 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
7560 cg.body.writeOperand(Id, bool_ty_id);
7561 cg.body.writeOperand(Id, in_range);
7562 cg.body.writeOperand(Id, ge);
7563 cg.body.writeOperand(Id, le);
7962 const in_range = cg.allocId();
7963 try cg.body.emit(gpa, .OpLogicalAnd, .{
7964 .id_result_type = bool_ty_id,
7965 .id_result = in_range,
7966 .operand_1 = ge,
7967 .operand_2 = le,
7968 });
75647969 case_cond = if (case_cond) |prev| blk: {
7565 const combined = cg.module.allocId();
7566 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7567 cg.body.writeOperand(Id, bool_ty_id);
7568 cg.body.writeOperand(Id, combined);
7569 cg.body.writeOperand(Id, prev);
7570 cg.body.writeOperand(Id, in_range);
7970 const combined = cg.allocId();
7971 try cg.body.emit(gpa, .OpLogicalOr, .{
7972 .id_result_type = bool_ty_id,
7973 .id_result = combined,
7974 .operand_1 = prev,
7975 .operand_2 = in_range,
7976 });
75717977 break :blk combined;
75727978 } else in_range;
75737979 }
75747980
75757981 const case_label = case_labels.at(case.idx);
75767982 const is_last = case.idx == last_range_case.?;
7577 const next_check = if (is_last) default_label else cg.module.allocId();
7983 const next_check = if (is_last) default_label else cg.allocId();
75787984
75797985 try cg.body.emit(gpa, .OpSelectionMerge, .{
75807986 .merge_block = next_check,
......@@ -7633,9 +8039,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
76338039}
76348040
76358041fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7636 const gpa = cg.module.gpa;
7637 const zcu = cg.module.zcu;
7638 const target = cg.module.zcu.getTarget();
8042 const gpa = cg.gpa;
8043 const zcu = cg.zcu;
8044 const target = cg.zcu.getTarget();
76398045 const switch_br = cg.air.unwrapSwitch(inst);
76408046 const cond_ty = cg.typeOf(switch_br.operand);
76418047 const initial_cond = try cg.resolve(switch_br.operand);
......@@ -7645,14 +8051,14 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
76458051 .bool, .error_set => 1,
76468052 .int => blk: {
76478053 const bits = cond_ty.intInfo(zcu).bits;
7648 const backing_bits, const big_int = cg.module.backingIntBits(bits);
8054 const backing_bits, const big_int = cg.backingIntBits(bits);
76498055 if (big_int) return cg.todo("implement composite int loop switch", .{});
76508056 break :blk if (backing_bits <= 32) 1 else 2;
76518057 },
76528058 .@"enum" => blk: {
76538059 const int_ty = cond_ty.intTagType(zcu);
76548060 const int_info = int_ty.intInfo(zcu);
7655 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
8061 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
76568062 if (big_int) return cg.todo("implement composite int loop switch", .{});
76578063 break :blk if (backing_bits <= 32) 1 else 2;
76588064 },
......@@ -7682,15 +8088,15 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
76828088 }
76838089 }
76848090
7685 const case_labels = cg.module.allocIds(num_cases);
7686 const default_label = cg.module.allocId();
7687 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;
8091 const case_labels = cg.allocIds(num_cases);
8092 const default_label = cg.allocId();
8093 const switch_default = if (last_range_case != null) cg.allocId() else default_label;
76888094
7689 const header_label = cg.module.allocId();
7690 const loop_merge = cg.module.allocId();
7691 const continue_label = cg.module.allocId();
7692 const switch_merge = cg.module.allocId();
7693 const body_label = cg.module.allocId();
8095 const header_label = cg.allocId();
8096 const loop_merge = cg.allocId();
8097 const continue_label = cg.allocId();
8098 const switch_merge = cg.allocId();
8099 const body_label = cg.allocId();
76948100
76958101 // switch_dispatch signals "continue the loop" by using this sentinel as the
76968102 // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes
......@@ -7772,12 +8178,13 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
77728178 const item_tmp: Temporary = try cg.temporary(item);
77738179 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
77748180 case_cond = if (case_cond) |prev| blk: {
7775 const combined = cg.module.allocId();
7776 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7777 cg.body.writeOperand(Id, bool_ty_id);
7778 cg.body.writeOperand(Id, combined);
7779 cg.body.writeOperand(Id, prev);
7780 cg.body.writeOperand(Id, eq);
8181 const combined = cg.allocId();
8182 try cg.body.emit(gpa, .OpLogicalOr, .{
8183 .id_result_type = bool_ty_id,
8184 .id_result = combined,
8185 .operand_1 = prev,
8186 .operand_2 = eq,
8187 });
77818188 break :blk combined;
77828189 } else eq;
77838190 }
......@@ -7787,26 +8194,28 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
77878194 const hi_tmp: Temporary = try cg.temporary(range[1]);
77888195 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
77898196 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7790 const in_range = cg.module.allocId();
7791 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
7792 cg.body.writeOperand(Id, bool_ty_id);
7793 cg.body.writeOperand(Id, in_range);
7794 cg.body.writeOperand(Id, ge);
7795 cg.body.writeOperand(Id, le);
8197 const in_range = cg.allocId();
8198 try cg.body.emit(gpa, .OpLogicalAnd, .{
8199 .id_result_type = bool_ty_id,
8200 .id_result = in_range,
8201 .operand_1 = ge,
8202 .operand_2 = le,
8203 });
77968204 case_cond = if (case_cond) |prev| blk: {
7797 const combined = cg.module.allocId();
7798 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7799 cg.body.writeOperand(Id, bool_ty_id);
7800 cg.body.writeOperand(Id, combined);
7801 cg.body.writeOperand(Id, prev);
7802 cg.body.writeOperand(Id, in_range);
8205 const combined = cg.allocId();
8206 try cg.body.emit(gpa, .OpLogicalOr, .{
8207 .id_result_type = bool_ty_id,
8208 .id_result = combined,
8209 .operand_1 = prev,
8210 .operand_2 = in_range,
8211 });
78038212 break :blk combined;
78048213 } else in_range;
78058214 }
78068215
78078216 const case_label = case_labels.at(case.idx);
78088217 const is_last = case.idx == last_range_case.?;
7809 const next_check = if (is_last) default_label else cg.module.allocId();
8218 const next_check = if (is_last) default_label else cg.allocId();
78108219
78118220 try cg.body.emit(gpa, .OpSelectionMerge, .{
78128221 .merge_block = next_check,
......@@ -7860,7 +8269,7 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
78608269 try cg.beginSpvBlock(switch_merge);
78618270 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);
78628271
7863 const is_dispatch = cg.module.allocId();
8272 const is_dispatch = cg.allocId();
78648273 const bool_ty_id = try cg.resolveType(.bool, .direct);
78658274 try cg.body.emit(gpa, .OpIEqual, .{
78668275 .id_result_type = bool_ty_id,
......@@ -7869,12 +8278,12 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
78698278 .operand_2 = dispatch_sentinel,
78708279 });
78718280
7872 const dispatch_check_merge = cg.module.allocId();
8281 const dispatch_check_merge = cg.allocId();
78738282 try cg.body.emit(gpa, .OpSelectionMerge, .{
78748283 .merge_block = dispatch_check_merge,
78758284 .selection_control = .{},
78768285 });
7877 const exit_block = cg.module.allocId();
8286 const exit_block = cg.allocId();
78788287 try cg.body.emit(gpa, .OpBranchConditional, .{
78798288 .condition = is_dispatch,
78808289 .true_label = dispatch_check_merge,
......@@ -7906,25 +8315,30 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void {
79068315}
79078316
79088317fn airUnreach(cg: *CodeGen) !void {
7909 try cg.body.emit(cg.module.gpa, .OpUnreachable, {});
8318 try cg.body.emit(cg.gpa, .OpUnreachable, {});
79108319}
79118320
79128321fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {
7913 const zcu = cg.module.zcu;
8322 const zcu = cg.zcu;
79148323 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
79158324 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;
79168325
79178326 if (zcu.comp.config.root_strip) return;
79188327
7919 try cg.body.emit(cg.module.gpa, .OpLine, .{
7920 .file = try cg.module.debugString(path),
8328 const path_id = cg.allocId();
8329 try cg.sections.debug_strings.emit(cg.gpa, .OpString, .{
8330 .id_result = path_id,
8331 .string = path,
8332 });
8333 try cg.body.emit(cg.gpa, .OpLine, .{
8334 .file = path_id,
79218335 .line = cg.base_line + dbg_stmt.line + 1,
79228336 .column = dbg_stmt.column + 1,
79238337 });
79248338}
79258339
79268340fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7927 const zcu = cg.module.zcu;
8341 const zcu = cg.zcu;
79288342 const block = cg.air.unwrapDbgBlock(inst);
79298343 const old_base_line = cg.base_line;
79308344 defer cg.base_line = old_base_line;
......@@ -7934,15 +8348,17 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
79348348
79358349fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
79368350 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
7937 const target_id = try cg.resolve(pl_op.operand);
7938 if (cg.virtual_allocas.contains(target_id)) return;
8351 const target_id = switch (try cg.resolvePtr(pl_op.operand)) {
8352 .tracked => return,
8353 .id => |id| id,
8354 };
79398355 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
7940 try cg.module.debugName(target_id, name.toSlice(cg.air));
8356 try cg.debugName(target_id, name.toSlice(cg.air));
79418357}
79428358
79438359fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7944 const gpa = cg.module.gpa;
7945 const zcu = cg.module.zcu;
8360 const gpa = cg.gpa;
8361 const zcu = cg.zcu;
79468362 const unwrapped_asm = cg.air.unwrapAsm(inst);
79478363
79488364 const is_volatile = unwrapped_asm.is_volatile;
......@@ -7974,7 +8390,6 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
79748390 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});
79758391 });
79768392
7977 // TODO: This entire function should be handled a bit better...
79788393 const ip = &zcu.intern_pool;
79798394 switch (ip.indexToKey(val.toIntern())) {
79808395 .int_type,
......@@ -8080,8 +8495,8 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
80808495fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) !?Id {
80818496 _ = modifier;
80828497
8083 const gpa = cg.module.gpa;
8084 const zcu = cg.module.zcu;
8498 const gpa = cg.gpa;
8499 const zcu = cg.zcu;
80858500 const air_call = cg.air.unwrapCall(inst);
80868501 const args = air_call.args;
80878502 const callee_ty = cg.typeOf(air_call.callee);
......@@ -8094,11 +8509,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
80948509 const return_type = fn_info.return_type;
80958510
80968511 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));
8097 const result_id = cg.module.allocId();
8512 const result_id = cg.allocId();
80988513 const callee_id = try cg.resolve(air_call.callee);
80998514
8100 comptime assert(zig_call_abi_ver == 3);
8101
81028515 const scratch_top = cg.id_scratch.items.len;
81038516 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
81048517 const params = try cg.id_scratch.addManyAsSlice(gpa, args.len);
......@@ -8113,7 +8526,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
81138526
81148527 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and
81158528 !arg_ty.childType(zcu).hasRuntimeBits(zcu) and
8116 cg.module.storageClass(arg_ty.ptrAddressSpace(zcu)) == .function)
8529 cg.storageClass(arg_ty.ptrAddressSpace(zcu)) == .function)
81178530 {
81188531 // in logical addressing, pointer arguments to function calls
81198532 // must be memory object declarations (OpVariable). for pointers to
......@@ -8148,15 +8561,26 @@ fn builtin3D(
81488561 dimension: u32,
81498562 out_of_range_value: anytype,
81508563) !Id {
8151 const gpa = cg.module.gpa;
8564 const gpa = cg.gpa;
81528565 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);
8153 const u32_ty_id = try cg.module.intType(.unsigned, 32);
8154 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);
8155 const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input);
8156 const spv_decl_index = try cg.module.builtin(ptr_ty_id, built_in, .input);
8157 try cg.module.decl_deps.append(gpa, spv_decl_index);
8158 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;
8159 const vec_id = cg.module.allocId();
8566 const u32_ty_id = try cg.intType(.unsigned, 32);
8567 const vec_ty_id = try cg.vectorType(3, u32_ty_id);
8568 const ptr_ty_id = try cg.ptrType(vec_ty_id, .input);
8569 const builtins_gop = try cg.builtins.getOrPut(gpa, .{ built_in, .input });
8570 if (!builtins_gop.found_existing) {
8571 builtins_gop.value_ptr.* = try cg.allocDecl(.global);
8572 const decl = cg.declPtr(builtins_gop.value_ptr.*);
8573 try cg.sections.globals.emit(gpa, .OpVariable, .{
8574 .id_result_type = ptr_ty_id,
8575 .id_result = decl.result_id,
8576 .storage_class = .input,
8577 });
8578 try cg.decorate(decl.result_id, .{ .built_in = .{ .built_in = built_in } });
8579 }
8580 const spv_decl_index = builtins_gop.value_ptr.*;
8581 try cg.decl_deps.append(gpa, spv_decl_index);
8582 const ptr_id = cg.declPtr(spv_decl_index).result_id;
8583 const vec_id = cg.allocId();
81608584 try cg.body.emit(gpa, .OpLoad, .{
81618585 .id_result_type = vec_ty_id,
81628586 .id_result = vec_id,
......@@ -8187,12 +8611,30 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
81878611 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
81888612}
81898613
8190fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
8191 const zcu = cg.module.zcu;
8192 return cg.air.typeOf(inst, &zcu.intern_pool);
8193}
8614const std = @import("std");
8615const Allocator = std.mem.Allocator;
8616const Target = std.Target;
8617const Signedness = std.lang.Signedness;
8618const assert = std.debug.assert;
8619const log = std.log.scoped(.codegen);
81948620
8195fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
8196 const zcu = cg.module.zcu;
8197 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
8198}
8621const builtin = @import("builtin");
8622const link = @import("../../link.zig");
8623const codegen = @import("../../codegen.zig");
8624const Zcu = @import("../../Zcu.zig");
8625const Type = @import("../../Type.zig");
8626const Value = @import("../../Value.zig");
8627const Air = @import("../../Air.zig");
8628const InternPool = @import("../../InternPool.zig");
8629const Section = @import("Section.zig");
8630const Assembler = @import("Assembler.zig");
8631const Mir = @import("Mir.zig");
8632
8633const spec = @import("spec.zig");
8634const Opcode = spec.Opcode;
8635const Word = spec.Word;
8636const Id = spec.Id;
8637const IdRange = spec.IdRange;
8638const StorageClass = spec.StorageClass;
8639
8640const CodeGen = @This();
src/codegen/spirv/Mir.zig+5-5
......@@ -6,13 +6,13 @@ const Word = spec.Word;
66const Id = spec.Id;
77
88const InternPool = @import("../../InternPool.zig");
9const Module = @import("Module.zig");
9const CodeGen = @import("CodeGen.zig");
1010
1111const Mir = @This();
1212
1313id_bound: Word,
1414owner_nav: InternPool.Nav.Index,
15kind: Module.Decl.Kind,
15kind: CodeGen.Decl.Kind,
1616decl_result_id: Id,
1717extended_instruction_set: []const Word,
1818globals: []const Word,
......@@ -30,18 +30,18 @@ entry_points: []const EntryPoint,
3030pub const NavRef = struct {
3131 local_id: Id,
3232 nav: InternPool.Nav.Index,
33 kind: Module.Decl.Kind,
33 kind: CodeGen.Decl.Kind,
3434};
3535
3636pub const UavRef = struct {
3737 local_id: Id,
3838 val: InternPool.Index,
3939 storage_class: spec.StorageClass,
40 kind: Module.Decl.Kind,
40 kind: CodeGen.Decl.Kind,
4141};
4242
4343pub const DeclDep = struct {
44 kind: Module.Decl.Kind,
44 kind: CodeGen.Decl.Kind,
4545 nav: InternPool.Nav.Index,
4646};
4747
src/codegen/spirv/Module.zig deleted-791
......@@ -1,791 +0,0 @@
1//! This structure represents a SPIR-V (sections) module being compiled, and keeps
2//! track of all relevant information. That includes the actual instructions, the
3//! current result-id bound, and data structures for querying result-id's of data
4//! which needs to be persistent over different calls to Decl code generation.
5//!
6//! A SPIR-V binary module supports both little- and big endian layout. The layout
7//! is detected by the magic word in the header. Therefore, we can ignore any byte
8//! order throughout the implementation, and just use the host byte order, and make
9//! this a problem for the consumer.
10const std = @import("std");
11const Allocator = std.mem.Allocator;
12const assert = std.debug.assert;
13
14const Zcu = @import("../../Zcu.zig");
15const InternPool = @import("../../InternPool.zig");
16const Section = @import("Section.zig");
17const spec = @import("spec.zig");
18const Word = spec.Word;
19const Id = spec.Id;
20
21const Module = @This();
22
23gpa: Allocator,
24arena: Allocator,
25zcu: *Zcu,
26nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty,
27uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty,
28intern_map: std.AutoHashMapUnmanaged(struct { InternPool.Index, Repr }, Id) = .empty,
29decls: std.ArrayList(Decl) = .empty,
30decl_deps: std.ArrayList(Decl.Index) = .empty,
31entry_points: std.array_hash_map.Auto(Id, EntryPoint) = .empty,
32/// This map serves a dual purpose:
33/// - It keeps track of pointers that are currently being emitted, so that we can tell
34/// if they are recursive and need an OpTypeForwardPointer.
35/// - It caches pointers by child-type. This is required because sometimes we rely on
36/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned
37/// via the usual `intern_map` mechanism.
38ptr_types: std.AutoHashMapUnmanaged(struct { Id, spec.StorageClass }, Id) = .{},
39/// For test declarations compiled for Vulkan target, we have to add a buffer.
40/// We only need to generate this once, this holds the link information related to that.
41error_buffer: ?Decl.Index = null,
42/// SPIR-V instructions return result-ids.
43/// This variable holds the module-wide counter for these.
44next_result_id: Word = 1,
45/// Some types shouldn't be emitted more than one time, but cannot be caught by
46/// the `intern_map` during codegen. Sometimes, IDs are compared to check if
47/// types are the same, so we can't delay until the dedup pass. Therefore,
48/// this is an ad-hoc structure to cache types where required.
49/// According to the SPIR-V specification, section 2.8, this includes all non-aggregate
50/// non-pointer types.
51/// Additionally, this is used for other values which can be cached, for example,
52/// built-in variables.
53cache: struct {
54 bool_type: ?Id = null,
55 void_type: ?Id = null,
56 opaque_types: std.StringHashMapUnmanaged(Id) = .empty,
57 int_types: std.AutoHashMapUnmanaged(std.lang.Type.Int, Id) = .empty,
58 float_types: std.AutoHashMapUnmanaged(std.lang.Type.Float, Id) = .empty,
59 vector_types: std.AutoHashMapUnmanaged(struct { Id, u32 }, Id) = .empty,
60 array_types: std.AutoHashMapUnmanaged(struct { Id, Id }, Id) = .empty,
61 struct_types: std.array_hash_map.Custom(StructType, Id, StructType.HashContext, true) = .empty,
62 fn_types: std.array_hash_map.Custom(FnType, Id, FnType.HashContext, true) = .empty,
63
64 extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,
65 decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,
66 builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty,
67 strings: std.array_hash_map.String(Id) = .empty,
68
69 bool_const: [2]?Id = .{ null, null },
70 constants: std.array_hash_map.Custom(Constant, Id, Constant.HashContext, true) = .empty,
71
72 spirv_types: std.AutoHashMapUnmanaged(InternPool.Index, Id) = .empty,
73} = .{},
74/// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".
75sections: struct {
76 extended_instruction_set: Section = .{},
77 memory_model: Section = .{},
78 execution_modes: Section = .{},
79 debug_strings: Section = .{},
80 debug_names: Section = .{},
81 annotations: Section = .{},
82 globals: Section = .{},
83 functions: Section = .{},
84} = .{},
85
86pub const big_int_bits = 32;
87
88/// Data can be lowered into in two basic representations: indirect, which is when
89/// a type is stored in memory, and direct, which is how a type is stored when its
90/// a direct SPIR-V value.
91pub const Repr = enum {
92 /// A SPIR-V value as it would be used in operations.
93 direct,
94 /// A SPIR-V value as it is stored in memory.
95 indirect,
96};
97
98/// Declarations, both functions and globals, can have dependencies. These are used for 2 things:
99/// - Globals must be declared before they are used, also between globals. The compiler processes
100/// globals unordered, so we must use the dependencies here to figure out how to order the globals
101/// in the final module. The Globals structure is also used for that.
102/// - Entry points must declare the complete list of OpVariable instructions that they access.
103/// For these we use the same dependency structure.
104/// In this mechanism, globals will only depend on other globals, while functions may depend on
105/// globals or other functions.
106pub const Decl = struct {
107 /// Index to refer to a Decl by.
108 pub const Index = enum(u32) { _ };
109
110 /// Useful to tell what kind of decl this is, and hold the result-id or field index
111 /// to be used for this decl.
112 pub const Kind = enum {
113 func,
114 global,
115 invocation_global,
116 };
117
118 /// See comment on Kind
119 kind: Kind,
120 /// The result-id associated to this decl. The specific meaning of this depends on `kind`:
121 /// - For `func`, this is the result-id of the associated OpFunction instruction.
122 /// - For `global`, this is the result-id of the associated OpVariable instruction.
123 /// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
124 result_id: Id,
125 /// The offset of the first dependency of this decl in the `decl_deps` array.
126 begin_dep: usize = 0,
127 /// The past-end offset of the dependencies of this decl in the `decl_deps` array.
128 end_dep: usize = 0,
129 /// Whether a stub OpFunction/OpFunctionEnd + Import linkage decoration has
130 /// already been emitted for this extern function decl.
131 has_extern_stub: bool = false,
132};
133
134pub const EntryPoint = struct {
135 decl_index: Decl.Index,
136 name: []const u8,
137 cc: std.builtin.CallingConvention,
138};
139
140const StructType = struct {
141 fields: []const Id,
142 ip_index: InternPool.Index,
143
144 const HashContext = struct {
145 pub fn hash(_: @This(), ty: StructType) u32 {
146 var hasher = std.hash.Wyhash.init(0);
147 hasher.update(std.mem.sliceAsBytes(ty.fields));
148 hasher.update(std.mem.asBytes(&ty.ip_index));
149 return @truncate(hasher.final());
150 }
151
152 pub fn eql(_: @This(), a: StructType, b: StructType, _: usize) bool {
153 return a.ip_index == b.ip_index and std.mem.eql(Id, a.fields, b.fields);
154 }
155 };
156};
157
158const FnType = struct {
159 return_ty: Id,
160 params: []const Id,
161
162 const HashContext = struct {
163 pub fn hash(_: @This(), ty: FnType) u32 {
164 var hasher = std.hash.Wyhash.init(0);
165 hasher.update(std.mem.asBytes(&ty.return_ty));
166 hasher.update(std.mem.sliceAsBytes(ty.params));
167 return @truncate(hasher.final());
168 }
169
170 pub fn eql(_: @This(), a: FnType, b: FnType, _: usize) bool {
171 return a.return_ty == b.return_ty and
172 std.mem.eql(Id, a.params, b.params);
173 }
174 };
175};
176
177const Constant = struct {
178 ty: Id,
179 value: spec.LiteralContextDependentNumber,
180
181 const HashContext = struct {
182 pub fn hash(_: @This(), value: Constant) u32 {
183 const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?;
184 var hasher = std.hash.Wyhash.init(0);
185 hasher.update(std.mem.asBytes(&value.ty));
186 hasher.update(std.mem.asBytes(&@as(Tag, value.value)));
187 switch (value.value) {
188 inline else => |v| hasher.update(std.mem.asBytes(&v)),
189 }
190 return @truncate(hasher.final());
191 }
192
193 pub fn eql(_: @This(), a: Constant, b: Constant, _: usize) bool {
194 if (a.ty != b.ty) return false;
195 const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?;
196 if (@as(Tag, a.value) != @as(Tag, b.value)) return false;
197 return switch (a.value) {
198 inline else => |v, tag| v == @field(b.value, @tagName(tag)),
199 };
200 }
201 };
202};
203
204pub fn deinit(module: *Module) void {
205 module.nav_link.deinit(module.gpa);
206 module.uav_link.deinit(module.gpa);
207 module.intern_map.deinit(module.gpa);
208 module.ptr_types.deinit(module.gpa);
209
210 module.sections.extended_instruction_set.deinit(module.gpa);
211 module.sections.memory_model.deinit(module.gpa);
212 module.sections.execution_modes.deinit(module.gpa);
213 module.sections.debug_strings.deinit(module.gpa);
214 module.sections.debug_names.deinit(module.gpa);
215 module.sections.annotations.deinit(module.gpa);
216 module.sections.globals.deinit(module.gpa);
217 module.sections.functions.deinit(module.gpa);
218
219 module.cache.opaque_types.deinit(module.gpa);
220 module.cache.int_types.deinit(module.gpa);
221 module.cache.float_types.deinit(module.gpa);
222 module.cache.vector_types.deinit(module.gpa);
223 module.cache.array_types.deinit(module.gpa);
224 module.cache.struct_types.deinit(module.gpa);
225 module.cache.fn_types.deinit(module.gpa);
226 module.cache.spirv_types.deinit(module.gpa);
227 module.cache.extended_instruction_set.deinit(module.gpa);
228 module.cache.decorations.deinit(module.gpa);
229 module.cache.builtins.deinit(module.gpa);
230 module.cache.strings.deinit(module.gpa);
231
232 module.cache.constants.deinit(module.gpa);
233
234 module.decls.deinit(module.gpa);
235 module.decl_deps.deinit(module.gpa);
236 module.entry_points.deinit(module.gpa);
237
238 module.* = undefined;
239}
240
241/// Fetch or allocate a result id for nav index. This function also marks the nav as alive.
242/// Note: Function does not actually generate the nav, it just allocates an index.
243pub fn resolveNav(module: *Module, ip: *InternPool, nav_index: InternPool.Nav.Index) !Decl.Index {
244 const entry = try module.nav_link.getOrPut(module.gpa, nav_index);
245 if (!entry.found_existing) {
246 const nav = ip.getNav(nav_index);
247 // TODO: Extern fn?
248 const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type))
249 .func
250 else switch (nav.resolved.?.@"addrspace") {
251 .generic => .invocation_global,
252 else => .global,
253 };
254 entry.value_ptr.* = try module.allocDecl(kind);
255 }
256
257 return entry.value_ptr.*;
258}
259
260pub fn allocIds(module: *Module, n: u32) spec.IdRange {
261 defer module.next_result_id += n;
262 return .{ .base = module.next_result_id, .len = n };
263}
264
265pub fn allocId(module: *Module) Id {
266 return module.allocIds(1).at(0);
267}
268
269pub fn idBound(module: Module) Word {
270 return module.next_result_id;
271}
272
273pub fn addEntryPointDeps(
274 module: *Module,
275 decl_index: Decl.Index,
276 seen: *std.bit_set.Dynamic,
277 interface: *std.array_list.Managed(Id),
278) !void {
279 const decl = module.declPtr(decl_index);
280 const deps = module.decl_deps.items[decl.begin_dep..decl.end_dep];
281
282 if (seen.isSet(@intFromEnum(decl_index))) {
283 return;
284 }
285
286 seen.set(@intFromEnum(decl_index));
287
288 if (decl.kind == .global) {
289 try interface.append(decl.result_id);
290 }
291
292 for (deps) |dep| {
293 try module.addEntryPointDeps(dep, seen, interface);
294 }
295}
296
297/// Imports or returns the existing id of an extended instruction set
298pub fn importInstructionSet(module: *Module, set: spec.InstructionSet) !Id {
299 assert(set != .core);
300
301 const gop = try module.cache.extended_instruction_set.getOrPut(module.gpa, set);
302 if (gop.found_existing) return gop.value_ptr.*;
303
304 const result_id = module.allocId();
305 try module.sections.extended_instruction_set.emit(module.gpa, .OpExtInstImport, .{
306 .id_result = result_id,
307 .name = @tagName(set),
308 });
309 gop.value_ptr.* = result_id;
310
311 return result_id;
312}
313
314pub fn boolType(module: *Module) !Id {
315 if (module.cache.bool_type) |id| return id;
316
317 const result_id = module.allocId();
318 try module.sections.globals.emit(module.gpa, .OpTypeBool, .{
319 .id_result = result_id,
320 });
321 module.cache.bool_type = result_id;
322 return result_id;
323}
324
325pub fn voidType(module: *Module) !Id {
326 if (module.cache.void_type) |id| return id;
327
328 const result_id = module.allocId();
329 try module.sections.globals.emit(module.gpa, .OpTypeVoid, .{
330 .id_result = result_id,
331 });
332 module.cache.void_type = result_id;
333 try module.debugName(result_id, "void");
334 return result_id;
335}
336
337pub fn opaqueType(module: *Module, name: []const u8) !Id {
338 if (module.cache.opaque_types.get(name)) |id| return id;
339 const result_id = module.allocId();
340 const name_dup = try module.arena.dupe(u8, name);
341 try module.sections.globals.emit(module.gpa, .OpTypeOpaque, .{
342 .id_result = result_id,
343 .literal_string = name_dup,
344 });
345 try module.debugName(result_id, name_dup);
346 try module.cache.opaque_types.put(module.gpa, name_dup, result_id);
347 return result_id;
348}
349
350pub fn backingIntBits(module: *Module, bits: u16) struct { u16, bool } {
351 assert(bits != 0);
352 const target = module.zcu.getTarget();
353 const ints = [_]struct { bits: u16, enabled: bool }{
354 .{ .bits = 8, .enabled = target.cpu.has(.spirv, .int8) },
355 .{ .bits = 16, .enabled = target.cpu.has(.spirv, .int16) },
356 .{ .bits = 32, .enabled = true },
357 .{ .bits = 64, .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64 },
358 };
359
360 for (ints) |int| {
361 if (bits <= int.bits and int.enabled) return .{ int.bits, false };
362 }
363
364 return .{ std.mem.alignForward(u16, bits, big_int_bits), true };
365}
366
367pub fn intType(module: *Module, signedness: std.lang.Signedness, bits: u16) !Id {
368 assert(bits > 0);
369
370 const target = module.zcu.getTarget();
371 const actual_signedness = switch (target.os.tag) {
372 // Kernel only supports unsigned ints.
373 .opencl, .amdhsa => .unsigned,
374 else => signedness,
375 };
376 const backing_bits, const big_int = module.backingIntBits(bits);
377 if (big_int) {
378 const u32_ty = try module.intType(.unsigned, 32);
379 const len_id = try module.constant(u32_ty, .{ .uint32 = backing_bits / big_int_bits });
380 return module.arrayType(len_id, u32_ty);
381 }
382
383 const entry = try module.cache.int_types.getOrPut(module.gpa, .{ .signedness = actual_signedness, .bits = backing_bits });
384 if (!entry.found_existing) {
385 const result_id = module.allocId();
386 entry.value_ptr.* = result_id;
387 try module.sections.globals.emit(module.gpa, .OpTypeInt, .{
388 .id_result = result_id,
389 .width = backing_bits,
390 .signedness = switch (actual_signedness) {
391 .signed => 1,
392 .unsigned => 0,
393 },
394 });
395
396 switch (actual_signedness) {
397 .signed => try module.debugNameFmt(result_id, "i{}", .{backing_bits}),
398 .unsigned => try module.debugNameFmt(result_id, "u{}", .{backing_bits}),
399 }
400 }
401 return entry.value_ptr.*;
402}
403
404pub fn floatType(module: *Module, bits: u16) !Id {
405 assert(bits > 0);
406 const entry = try module.cache.float_types.getOrPut(module.gpa, .{ .bits = bits });
407 if (!entry.found_existing) {
408 const result_id = module.allocId();
409 entry.value_ptr.* = result_id;
410 try module.sections.globals.emit(module.gpa, .OpTypeFloat, .{
411 .id_result = result_id,
412 .width = bits,
413 });
414 try module.debugNameFmt(result_id, "f{}", .{bits});
415 }
416 return entry.value_ptr.*;
417}
418
419pub fn vectorType(module: *Module, len: u32, child_ty_id: Id) !Id {
420 const entry = try module.cache.vector_types.getOrPut(module.gpa, .{ child_ty_id, len });
421 if (!entry.found_existing) {
422 const result_id = module.allocId();
423 entry.value_ptr.* = result_id;
424 try module.sections.globals.emit(module.gpa, .OpTypeVector, .{
425 .id_result = result_id,
426 .component_type = child_ty_id,
427 .component_count = len,
428 });
429 }
430 return entry.value_ptr.*;
431}
432
433pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id {
434 const entry = try module.cache.array_types.getOrPut(module.gpa, .{ child_ty_id, len_id });
435 if (!entry.found_existing) {
436 const result_id = module.allocId();
437 entry.value_ptr.* = result_id;
438 try module.sections.globals.emit(module.gpa, .OpTypeArray, .{
439 .id_result = result_id,
440 .element_type = child_ty_id,
441 .length = len_id,
442 });
443 }
444 return entry.value_ptr.*;
445}
446
447pub fn ptrType(module: *Module, child_ty_id: Id, storage_class: spec.StorageClass) !Id {
448 const key = .{ child_ty_id, storage_class };
449 const gop = try module.ptr_types.getOrPut(module.gpa, key);
450 if (!gop.found_existing) {
451 gop.value_ptr.* = module.allocId();
452 try module.sections.globals.emit(module.gpa, .OpTypePointer, .{
453 .id_result = gop.value_ptr.*,
454 .storage_class = storage_class,
455 .type = child_ty_id,
456 });
457 return gop.value_ptr.*;
458 }
459 return gop.value_ptr.*;
460}
461
462pub fn structType(
463 module: *Module,
464 types: []const Id,
465 maybe_names: ?[]const []const u8,
466 ip_index: InternPool.Index,
467) !Id {
468 const actual_ip_index = if (module.zcu.comp.config.root_strip) .none else ip_index;
469
470 if (module.cache.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id;
471 const result_id = module.allocId();
472 const types_dup = try module.arena.dupe(Id, types);
473 try module.sections.globals.emit(module.gpa, .OpTypeStruct, .{
474 .id_result = result_id,
475 .id_ref = types_dup,
476 });
477
478 if (maybe_names) |names| {
479 assert(names.len == types.len);
480 for (names, 0..) |name, i| {
481 try module.memberDebugName(result_id, @intCast(i), name);
482 }
483 }
484
485 try module.cache.struct_types.put(
486 module.gpa,
487 .{ .fields = types_dup, .ip_index = actual_ip_index },
488 result_id,
489 );
490 return result_id;
491}
492
493pub fn structFields(module: *const Module, struct_ty_id: Id) ?[]const Id {
494 for (module.cache.struct_types.keys(), module.cache.struct_types.values()) |key, val| {
495 if (val == struct_ty_id) return key.fields;
496 }
497 return null;
498}
499
500pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const Id) !Id {
501 if (module.cache.fn_types.get(.{
502 .return_ty = return_ty_id,
503 .params = param_type_ids,
504 })) |id| return id;
505 const result_id = module.allocId();
506 const params_dup = try module.arena.dupe(Id, param_type_ids);
507 try module.sections.globals.emit(module.gpa, .OpTypeFunction, .{
508 .id_result = result_id,
509 .return_type = return_ty_id,
510 .id_ref_2 = params_dup,
511 });
512 try module.cache.fn_types.put(module.gpa, .{
513 .return_ty = return_ty_id,
514 .params = params_dup,
515 }, result_id);
516 return result_id;
517}
518
519pub fn samplerType(module: *Module, ip_index: InternPool.Index) !Id {
520 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
521 if (!entry.found_existing) {
522 const result_id = module.allocId();
523 entry.value_ptr.* = result_id;
524 try module.sections.globals.emit(module.gpa, .OpTypeSampler, .{
525 .id_result = result_id,
526 });
527 }
528 return entry.value_ptr.*;
529}
530
531pub fn imageType(
532 module: *Module,
533 ip_index: InternPool.Index,
534 sampled_ty_id: Id,
535 dim: spec.Dim,
536 depth: spec.LiteralInteger,
537 arrayed: spec.LiteralInteger,
538 ms: spec.LiteralInteger,
539 sampled: spec.LiteralInteger,
540 image_format: spec.ImageFormat,
541 access_qualifier: ?spec.AccessQualifier,
542) !Id {
543 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
544 if (!entry.found_existing) {
545 const result_id = module.allocId();
546 entry.value_ptr.* = result_id;
547 try module.sections.globals.emit(module.gpa, .OpTypeImage, .{
548 .id_result = result_id,
549 .sampled_type = sampled_ty_id,
550 .dim = dim,
551 .depth = depth,
552 .arrayed = arrayed,
553 .ms = ms,
554 .sampled = sampled,
555 .image_format = image_format,
556 .access_qualifier = access_qualifier,
557 });
558 }
559 return entry.value_ptr.*;
560}
561
562pub fn sampledImageType(module: *Module, ip_index: InternPool.Index, image_ty_id: Id) !Id {
563 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
564 if (!entry.found_existing) {
565 const result_id = module.allocId();
566 entry.value_ptr.* = result_id;
567 try module.sections.globals.emit(module.gpa, .OpTypeSampledImage, .{
568 .id_result = result_id,
569 .image_type = image_ty_id,
570 });
571 }
572 return entry.value_ptr.*;
573}
574
575pub fn runtimeArrayType(module: *Module, ip_index: InternPool.Index, elem_ty_id: Id) !Id {
576 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
577 if (!entry.found_existing) {
578 const result_id = module.allocId();
579 entry.value_ptr.* = result_id;
580 try module.sections.globals.emit(module.gpa, .OpTypeRuntimeArray, .{
581 .id_result = result_id,
582 .element_type = elem_ty_id,
583 });
584 }
585 return entry.value_ptr.*;
586}
587
588pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id {
589 const gop = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value });
590 if (!gop.found_existing) {
591 gop.value_ptr.* = module.allocId();
592 try module.sections.globals.emit(module.gpa, .OpConstant, .{
593 .id_result_type = ty_id,
594 .id_result = gop.value_ptr.*,
595 .value = value,
596 });
597 }
598 return gop.value_ptr.*;
599}
600
601pub fn constBool(module: *Module, value: bool) !Id {
602 if (module.cache.bool_const[@intFromBool(value)]) |b| return b;
603
604 const result_ty_id = try module.boolType();
605 const result_id = module.allocId();
606 module.cache.bool_const[@intFromBool(value)] = result_id;
607
608 switch (value) {
609 inline else => |value_ct| try module.sections.globals.emit(
610 module.gpa,
611 if (value_ct) .OpConstantTrue else .OpConstantFalse,
612 .{
613 .id_result_type = result_ty_id,
614 .id_result = result_id,
615 },
616 ),
617 }
618
619 return result_id;
620}
621
622pub fn builtin(
623 module: *Module,
624 result_ty_id: Id,
625 spirv_builtin: spec.BuiltIn,
626 storage_class: spec.StorageClass,
627) !Decl.Index {
628 const gop = try module.cache.builtins.getOrPut(module.gpa, .{ spirv_builtin, storage_class });
629 if (!gop.found_existing) {
630 const decl_index = try module.allocDecl(.global);
631 const decl = module.declPtr(decl_index);
632
633 gop.value_ptr.* = decl_index;
634 try module.sections.globals.emit(module.gpa, .OpVariable, .{
635 .id_result_type = result_ty_id,
636 .id_result = decl.result_id,
637 .storage_class = storage_class,
638 });
639 try module.decorate(decl.result_id, .{ .built_in = .{ .built_in = spirv_builtin } });
640 }
641 return gop.value_ptr.*;
642}
643
644pub fn constUndef(module: *Module, ty_id: Id) !Id {
645 const result_id = module.allocId();
646 try module.sections.globals.emit(module.gpa, .OpUndef, .{
647 .id_result_type = ty_id,
648 .id_result = result_id,
649 });
650 return result_id;
651}
652
653pub fn constNull(module: *Module, ty_id: Id) !Id {
654 const result_id = module.allocId();
655 try module.sections.globals.emit(module.gpa, .OpConstantNull, .{
656 .id_result_type = ty_id,
657 .id_result = result_id,
658 });
659 return result_id;
660}
661
662/// Decorate a result-id.
663pub fn decorate(
664 module: *Module,
665 target: Id,
666 decoration: spec.Decoration.Extended,
667) !void {
668 const gop = try module.cache.decorations.getOrPut(module.gpa, .{ target, decoration });
669 if (!gop.found_existing) {
670 try module.sections.annotations.emit(module.gpa, .OpDecorate, .{
671 .target = target,
672 .decoration = decoration,
673 });
674 }
675}
676
677/// Decorate a result-id which is a member of some struct.
678/// We really don't have to and shouldn't need to cache this.
679pub fn decorateMember(
680 module: *Module,
681 structure_type: Id,
682 member: u32,
683 decoration: spec.Decoration.Extended,
684) !void {
685 try module.sections.annotations.emit(module.gpa, .OpMemberDecorate, .{
686 .structure_type = structure_type,
687 .member = member,
688 .decoration = decoration,
689 });
690}
691
692pub fn allocDecl(module: *Module, kind: Decl.Kind) !Decl.Index {
693 try module.decls.append(module.gpa, .{
694 .kind = kind,
695 .result_id = module.allocId(),
696 });
697
698 return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(module.decls.items.len - 1))));
699}
700
701pub fn declPtr(module: *Module, index: Decl.Index) *Decl {
702 return &module.decls.items[@intFromEnum(index)];
703}
704
705/// Declare a SPIR-V function as an entry point. This causes an extra wrapper
706/// function to be generated, which is then exported as the real entry point. The purpose of this
707/// wrapper is to allocate and initialize the structure holding the instance globals.
708pub fn declareEntryPoint(
709 module: *Module,
710 decl_index: Decl.Index,
711 name: []const u8,
712 cc: std.builtin.CallingConvention,
713) !void {
714 const gop = try module.entry_points.getOrPut(module.gpa, module.declPtr(decl_index).result_id);
715 gop.value_ptr.decl_index = decl_index;
716 gop.value_ptr.name = name;
717 gop.value_ptr.cc = cc;
718}
719
720pub fn debugName(module: *Module, target: Id, name: []const u8) !void {
721 if (module.zcu.comp.config.root_strip) return;
722 try module.sections.debug_names.emit(module.gpa, .OpName, .{
723 .target = target,
724 .name = name,
725 });
726}
727
728pub fn debugNameFmt(module: *Module, target: Id, comptime fmt: []const u8, args: anytype) !void {
729 if (module.zcu.comp.config.root_strip) return;
730 const name = try std.fmt.allocPrint(module.gpa, fmt, args);
731 defer module.gpa.free(name);
732 try module.debugName(target, name);
733}
734
735pub fn memberDebugName(module: *Module, target: Id, member: u32, name: []const u8) !void {
736 if (module.zcu.comp.config.root_strip) return;
737 try module.sections.debug_names.emit(module.gpa, .OpMemberName, .{
738 .type = target,
739 .member = member,
740 .name = name,
741 });
742}
743
744pub fn debugString(module: *Module, string: []const u8) !Id {
745 const entry = try module.cache.strings.getOrPut(module.gpa, string);
746 if (!entry.found_existing) {
747 entry.value_ptr.* = module.allocId();
748 try module.sections.debug_strings.emit(module.gpa, .OpString, .{
749 .id_result = entry.value_ptr.*,
750 .string = string,
751 });
752 }
753 return entry.value_ptr.*;
754}
755
756pub fn storageClass(module: *Module, as: std.lang.AddressSpace) spec.StorageClass {
757 const target = module.zcu.getTarget();
758 return switch (as) {
759 .generic => .function,
760 .global => switch (target.os.tag) {
761 .opencl, .amdhsa => .cross_workgroup,
762 else => .storage_buffer,
763 },
764 .push_constant => .push_constant,
765 .output => .output,
766 .uniform => .uniform,
767 .storage_buffer => .storage_buffer,
768 .physical_storage_buffer => .physical_storage_buffer,
769 .constant => .uniform_constant,
770 .shared => .workgroup,
771 .local => .function,
772 .input => .input,
773 .gs,
774 .fs,
775 .ss,
776 .far,
777 .param,
778 .flash,
779 .flash1,
780 .flash2,
781 .flash3,
782 .flash4,
783 .flash5,
784 .cog,
785 .lut,
786 .hub,
787 .externref,
788 .funcref,
789 => unreachable,
790 };
791}