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;...@@ -3,7 +3,7 @@ const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;3const assert = std.debug.assert;
44
5const CodeGen = @import("CodeGen.zig");5const CodeGen = @import("CodeGen.zig");
6const Decl = @import("Module.zig").Decl;6const Decl = @import("CodeGen.zig").Decl;
77
8const spec = @import("spec.zig");8const spec = @import("spec.zig");
9const Opcode = spec.Opcode;9const Opcode = spec.Opcode;
...@@ -56,7 +56,7 @@ const Operand = union(enum) {...@@ -56,7 +56,7 @@ const Operand = union(enum) {
56};56};
5757
58pub fn deinit(ass: *Assembler) void {58pub fn deinit(ass: *Assembler) void {
59 const gpa = ass.cg.module.gpa;59 const gpa = ass.cg.gpa;
60 for (ass.errors.items) |err| gpa.free(err.msg);60 for (ass.errors.items) |err| gpa.free(err.msg);
61 ass.tokens.deinit(gpa);61 ass.tokens.deinit(gpa);
62 ass.errors.deinit(gpa);62 ass.errors.deinit(gpa);
...@@ -69,7 +69,7 @@ pub fn deinit(ass: *Assembler) void {...@@ -69,7 +69,7 @@ pub fn deinit(ass: *Assembler) void {
69const Error = error{ AssembleFail, OutOfMemory };69const Error = error{ AssembleFail, OutOfMemory };
7070
71pub fn assemble(ass: *Assembler, src: []const u8) Error!void {71pub fn assemble(ass: *Assembler, src: []const u8) Error!void {
72 const gpa = ass.cg.module.gpa;72 const gpa = ass.cg.gpa;
7373
74 ass.src = src;74 ass.src = src;
75 ass.errors.clearRetainingCapacity();75 ass.errors.clearRetainingCapacity();
...@@ -100,7 +100,7 @@ const ErrorMsg = struct {...@@ -100,7 +100,7 @@ const ErrorMsg = struct {
100};100};
101101
102fn addError(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytype) !void {102fn 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;
104 const msg = try std.fmt.allocPrint(gpa, fmt, args);104 const msg = try std.fmt.allocPrint(gpa, fmt, args);
105 errdefer gpa.free(msg);105 errdefer gpa.free(msg);
106 try ass.errors.append(gpa, .{106 try ass.errors.append(gpa, .{
...@@ -159,7 +159,7 @@ const AsmValue = union(enum) {...@@ -159,7 +159,7 @@ const AsmValue = union(enum) {
159/// If this function returns `error.AssembleFail`, an explanatory159/// If this function returns `error.AssembleFail`, an explanatory
160/// error message has already been emitted into `ass.errors`.160/// error message has already been emitted into `ass.errors`.
161fn processInstruction(ass: *Assembler) !void {161fn processInstruction(ass: *Assembler) !void {
162 const module = ass.cg.module;162 const cg = ass.cg;
163 const result: AsmValue = switch (ass.inst.opcode) {163 const result: AsmValue = switch (ass.inst.opcode) {
164 .OpEntryPoint => {164 .OpEntryPoint => {
165 return ass.fail(ass.currentToken().start, "cannot export entry points in assembly", .{});165 return ass.fail(ass.currentToken().start, "cannot export entry points in assembly", .{});
...@@ -176,7 +176,7 @@ fn processInstruction(ass: *Assembler) !void {...@@ -176,7 +176,7 @@ fn processInstruction(ass: *Assembler) !void {
176 const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse {176 const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse {
177 return ass.fail(set_name_offset, "unknown instruction set: {s}", .{set_name});177 return ass.fail(set_name_offset, "unknown instruction set: {s}", .{set_name});
178 };178 };
179 break :blk .{ .value = try module.importInstructionSet(set_tag) };179 break :blk .{ .value = try cg.importInstructionSet(set_tag) };
180 },180 },
181 else => switch (ass.inst.opcode.class()) {181 else => switch (ass.inst.opcode.class()) {
182 .type_declaration => try ass.processTypeInstruction(),182 .type_declaration => try ass.processTypeInstruction(),
...@@ -197,13 +197,12 @@ fn processInstruction(ass: *Assembler) !void {...@@ -197,13 +197,12 @@ fn processInstruction(ass: *Assembler) !void {
197197
198fn processTypeInstruction(ass: *Assembler) !AsmValue {198fn processTypeInstruction(ass: *Assembler) !AsmValue {
199 const cg = ass.cg;199 const cg = ass.cg;
200 const gpa = cg.module.gpa;200 const gpa = cg.gpa;
201 const module = cg.module;
202 const operands = ass.inst.operands.items;201 const operands = ass.inst.operands.items;
203 const section = &module.sections.globals;202 const section = &cg.sections.globals;
204 const id = switch (ass.inst.opcode) {203 const id = switch (ass.inst.opcode) {
205 .OpTypeVoid => try module.voidType(),204 .OpTypeVoid => try cg.voidType(),
206 .OpTypeBool => try module.boolType(),205 .OpTypeBool => try cg.boolType(),
207 .OpTypeInt => blk: {206 .OpTypeInt => blk: {
208 const signedness: std.lang.Signedness = switch (operands[2].literal32) {207 const signedness: std.lang.Signedness = switch (operands[2].literal32) {
209 0 => .unsigned,208 0 => .unsigned,
...@@ -216,7 +215,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {...@@ -216,7 +215,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
216 const width = std.math.cast(u16, operands[1].literal32) orelse {215 const width = std.math.cast(u16, operands[1].literal32) orelse {
217 return ass.fail(0, "int type of {} bits is too large", .{operands[1].literal32});216 return ass.fail(0, "int type of {} bits is too large", .{operands[1].literal32});
218 };217 };
219 break :blk try module.intType(signedness, width);218 break :blk try cg.intType(signedness, width);
220 },219 },
221 .OpTypeFloat => blk: {220 .OpTypeFloat => blk: {
222 const bits = operands[1].literal32;221 const bits = operands[1].literal32;
...@@ -226,11 +225,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {...@@ -226,11 +225,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
226 return ass.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});225 return ass.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});
227 },226 },
228 }227 }
229 break :blk try module.floatType(@intCast(bits));228 break :blk try cg.floatType(@intCast(bits));
230 },229 },
231 .OpTypeVector => blk: {230 .OpTypeVector => blk: {
232 const child_type = try ass.resolveRefId(operands[1].ref_id);231 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);
234 },233 },
235 .OpTypeArray => {234 .OpTypeArray => {
236 // TODO: The length of an OpTypeArray is determined by a constant (which may be a spec constant),235 // 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 {...@@ -239,8 +238,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
239 },238 },
240 .OpTypeRuntimeArray => blk: {239 .OpTypeRuntimeArray => blk: {
241 const element_type = try ass.resolveRefId(operands[1].ref_id);240 const element_type = try ass.resolveRefId(operands[1].ref_id);
242 const result_id = module.allocId();241 const result_id = cg.allocId();
243 try section.emit(module.gpa, .OpTypeRuntimeArray, .{242 try section.emit(cg.gpa, .OpTypeRuntimeArray, .{
244 .id_result = result_id,243 .id_result = result_id,
245 .element_type = element_type,244 .element_type = element_type,
246 });245 });
...@@ -249,8 +248,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {...@@ -249,8 +248,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
249 .OpTypePointer => blk: {248 .OpTypePointer => blk: {
250 const storage_class: StorageClass = @enumFromInt(operands[1].value);249 const storage_class: StorageClass = @enumFromInt(operands[1].value);
251 const child_type = try ass.resolveRefId(operands[2].ref_id);250 const child_type = try ass.resolveRefId(operands[2].ref_id);
252 const result_id = module.allocId();251 const result_id = cg.allocId();
253 try section.emit(module.gpa, .OpTypePointer, .{252 try section.emit(cg.gpa, .OpTypePointer, .{
254 .id_result = result_id,253 .id_result = result_id,
255 .storage_class = storage_class,254 .storage_class = storage_class,
256 .type = child_type,255 .type = child_type,
...@@ -262,11 +261,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {...@@ -262,11 +261,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
262 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);261 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
263 const ids = try cg.id_scratch.addManyAsSlice(gpa, operands[1..].len);262 const ids = try cg.id_scratch.addManyAsSlice(gpa, operands[1..].len);
264 for (operands[1..], ids) |op, *id| id.* = try ass.resolveRefId(op.ref_id);263 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);
266 },265 },
267 .OpTypeImage => blk: {266 .OpTypeImage => blk: {
268 const sampled_type = try ass.resolveRefId(operands[1].ref_id);267 const sampled_type = try ass.resolveRefId(operands[1].ref_id);
269 const result_id = module.allocId();268 const result_id = cg.allocId();
270 try section.emit(gpa, .OpTypeImage, .{269 try section.emit(gpa, .OpTypeImage, .{
271 .id_result = result_id,270 .id_result = result_id,
272 .sampled_type = sampled_type,271 .sampled_type = sampled_type,
...@@ -280,13 +279,13 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {...@@ -280,13 +279,13 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
280 break :blk result_id;279 break :blk result_id;
281 },280 },
282 .OpTypeSampler => blk: {281 .OpTypeSampler => blk: {
283 const result_id = module.allocId();282 const result_id = cg.allocId();
284 try section.emit(gpa, .OpTypeSampler, .{ .id_result = result_id });283 try section.emit(gpa, .OpTypeSampler, .{ .id_result = result_id });
285 break :blk result_id;284 break :blk result_id;
286 },285 },
287 .OpTypeSampledImage => blk: {286 .OpTypeSampledImage => blk: {
288 const image_type = try ass.resolveRefId(operands[1].ref_id);287 const image_type = try ass.resolveRefId(operands[1].ref_id);
289 const result_id = module.allocId();288 const result_id = cg.allocId();
290 try section.emit(gpa, .OpTypeSampledImage, .{ .id_result = result_id, .image_type = image_type });289 try section.emit(gpa, .OpTypeSampledImage, .{ .id_result = result_id, .image_type = image_type });
291 break :blk result_id;290 break :blk result_id;
292 },291 },
...@@ -301,8 +300,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {...@@ -301,8 +300,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
301 for (param_types, param_operands) |*param, operand| {300 for (param_types, param_operands) |*param, operand| {
302 param.* = try ass.resolveRefId(operand.ref_id);301 param.* = try ass.resolveRefId(operand.ref_id);
303 }302 }
304 const result_id = module.allocId();303 const result_id = cg.allocId();
305 try section.emit(module.gpa, .OpTypeFunction, .{304 try section.emit(cg.gpa, .OpTypeFunction, .{
306 .id_result = result_id,305 .id_result = result_id,
307 .return_type = return_type,306 .return_type = return_type,
308 .id_ref_2 = param_types,307 .id_ref_2 = param_types,
...@@ -318,27 +317,27 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {...@@ -318,27 +317,27 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
318/// - No forward references are allowed in operands.317/// - No forward references are allowed in operands.
319/// - Target section is determined from instruction type.318/// - Target section is determined from instruction type.
320fn processGenericInstruction(ass: *Assembler) !?AsmValue {319fn processGenericInstruction(ass: *Assembler) !?AsmValue {
321 const module = ass.cg.module;320 const cg = ass.cg;
322 const target = module.zcu.getTarget();321 const target = cg.zcu.getTarget();
323 const operands = ass.inst.operands.items;322 const operands = ass.inst.operands.items;
324 var maybe_spv_decl_index: ?Decl.Index = null;323 var maybe_spv_decl_index: ?Decl.Index = null;
325 const section = switch (ass.inst.opcode.class()) {324 const section = switch (ass.inst.opcode.class()) {
326 .constant_creation => &module.sections.globals,325 .constant_creation => &cg.sections.globals,
327 .annotation => &module.sections.annotations,326 .annotation => &cg.sections.annotations,
328 .type_declaration => unreachable, // Handled elsewhere.327 .type_declaration => unreachable, // Handled elsewhere.
329 else => switch (ass.inst.opcode) {328 else => switch (ass.inst.opcode) {
330 .OpEntryPoint => unreachable,329 .OpEntryPoint => unreachable,
331 .OpExecutionMode, .OpExecutionModeId => &module.sections.execution_modes,330 .OpExecutionMode, .OpExecutionModeId => &cg.sections.execution_modes,
332 .OpVariable => section: {331 .OpVariable => section: {
333 const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);332 const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);
334 if (storage_class == .function) break :section &ass.cg.prologue;333 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);
336 if (!target.cpu.has(.spirv, .v1_4) and storage_class != .input and storage_class != .output) {335 if (!target.cpu.has(.spirv, .v1_4) and storage_class != .input and storage_class != .output) {
337 // Before version 1.4, the interface’s storage classes are limited to the Input and Output336 // 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;
339 }338 }
340 try ass.cg.module.decl_deps.append(module.gpa, maybe_spv_decl_index.?);339 try ass.cg.decl_deps.append(cg.gpa, maybe_spv_decl_index.?);
341 break :section &module.sections.globals;340 break :section &cg.sections.globals;
342 },341 },
343 else => &ass.cg.body,342 else => &ass.cg.body,
344 },343 },
...@@ -348,36 +347,36 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue {...@@ -348,36 +347,36 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue {
348 const first_word = section.instructions.items.len;347 const first_word = section.instructions.items.len;
349 // At this point we're not quite sure how many operands this instruction is348 // At this point we're not quite sure how many operands this instruction is
350 // going to have, so insert 0 and patch up the actual opcode word later.349 // 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);
352 section.writeWord(0);351 section.writeWord(0);
353352
354 for (operands) |operand| {353 for (operands) |operand| {
355 switch (operand) {354 switch (operand) {
356 .value, .literal32 => |word| {355 .value, .literal32 => |word| {
357 try section.ensureUnusedCapacity(module.gpa, 1);356 try section.ensureUnusedCapacity(cg.gpa, 1);
358 section.writeWord(word);357 section.writeWord(word);
359 },358 },
360 .literal64 => |dword| {359 .literal64 => |dword| {
361 try section.ensureUnusedCapacity(module.gpa, 2);360 try section.ensureUnusedCapacity(cg.gpa, 2);
362 section.writeDoubleWord(dword);361 section.writeDoubleWord(dword);
363 },362 },
364 .result_id => {363 .result_id => {
365 maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index|364 maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index|
366 module.declPtr(spv_decl_index).result_id365 cg.declPtr(spv_decl_index).result_id
367 else366 else
368 module.allocId();367 cg.allocId();
369 try section.ensureUnusedCapacity(module.gpa, 1);368 try section.ensureUnusedCapacity(cg.gpa, 1);
370 section.writeOperand(Id, maybe_result_id.?);369 section.writeOperand(Id, maybe_result_id.?);
371 },370 },
372 .ref_id => |index| {371 .ref_id => |index| {
373 const result = try ass.resolveRef(index);372 const result = try ass.resolveRef(index);
374 try section.ensureUnusedCapacity(module.gpa, 1);373 try section.ensureUnusedCapacity(cg.gpa, 1);
375 section.writeOperand(spec.Id, result.resultId());374 section.writeOperand(spec.Id, result.resultId());
376 },375 },
377 .string => |offset| {376 .string => |offset| {
378 const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0);377 const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0);
379 const size = std.math.divCeil(usize, text.len + 1, @sizeOf(Word)) catch unreachable;378 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);
381 section.writeOperand(spec.LiteralString, text);380 section.writeOperand(spec.LiteralString, text);
382 },381 },
383 }382 }
...@@ -430,7 +429,7 @@ fn resolveRefId(ass: *Assembler, ref: AsmValue.Ref) !Id {...@@ -430,7 +429,7 @@ fn resolveRefId(ass: *Assembler, ref: AsmValue.Ref) !Id {
430}429}
431430
432fn parseInstruction(ass: *Assembler) !void {431fn parseInstruction(ass: *Assembler) !void {
433 const gpa = ass.cg.module.gpa;432 const gpa = ass.cg.gpa;
434433
435 ass.inst.opcode = undefined;434 ass.inst.opcode = undefined;
436 ass.inst.operands.clearRetainingCapacity();435 ass.inst.operands.clearRetainingCapacity();
...@@ -522,7 +521,7 @@ fn parseOperand(ass: *Assembler, kind: spec.OperandKind) Error!void {...@@ -522,7 +521,7 @@ fn parseOperand(ass: *Assembler, kind: spec.OperandKind) Error!void {
522521
523/// Also handles parsing any required extra operands.522/// Also handles parsing any required extra operands.
524fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {523fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {
525 const gpa = ass.cg.module.gpa;524 const gpa = ass.cg.gpa;
526525
527 var tok = ass.currentToken();526 var tok = ass.currentToken();
528 try ass.expectToken(.value);527 try ass.expectToken(.value);
...@@ -571,7 +570,7 @@ fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {...@@ -571,7 +570,7 @@ fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {
571570
572/// Also handles parsing any required extra operands.571/// Also handles parsing any required extra operands.
573fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {572fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {
574 const gpa = ass.cg.module.gpa;573 const gpa = ass.cg.gpa;
575574
576 const tok = ass.currentToken();575 const tok = ass.currentToken();
577 if (ass.eatToken(.placeholder)) {576 if (ass.eatToken(.placeholder)) {
...@@ -622,7 +621,7 @@ fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {...@@ -622,7 +621,7 @@ fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {
622}621}
623622
624fn parseRefId(ass: *Assembler) !void {623fn parseRefId(ass: *Assembler) !void {
625 const gpa = ass.cg.module.gpa;624 const gpa = ass.cg.gpa;
626625
627 const tok = ass.currentToken();626 const tok = ass.currentToken();
628 try ass.expectToken(.result_id);627 try ass.expectToken(.result_id);
...@@ -638,7 +637,7 @@ fn parseRefId(ass: *Assembler) !void {...@@ -638,7 +637,7 @@ fn parseRefId(ass: *Assembler) !void {
638}637}
639638
640fn parseLiteralInteger(ass: *Assembler) !void {639fn parseLiteralInteger(ass: *Assembler) !void {
641 const gpa = ass.cg.module.gpa;640 const gpa = ass.cg.gpa;
642641
643 const tok = ass.currentToken();642 const tok = ass.currentToken();
644 if (ass.eatToken(.placeholder)) {643 if (ass.eatToken(.placeholder)) {
...@@ -671,7 +670,7 @@ fn parseLiteralInteger(ass: *Assembler) !void {...@@ -671,7 +670,7 @@ fn parseLiteralInteger(ass: *Assembler) !void {
671}670}
672671
673fn parseLiteralExtInstInteger(ass: *Assembler) !void {672fn parseLiteralExtInstInteger(ass: *Assembler) !void {
674 const gpa = ass.cg.module.gpa;673 const gpa = ass.cg.gpa;
675674
676 const tok = ass.currentToken();675 const tok = ass.currentToken();
677 if (ass.eatToken(.placeholder)) {676 if (ass.eatToken(.placeholder)) {
...@@ -699,7 +698,7 @@ fn parseLiteralExtInstInteger(ass: *Assembler) !void {...@@ -699,7 +698,7 @@ fn parseLiteralExtInstInteger(ass: *Assembler) !void {
699}698}
700699
701fn parseString(ass: *Assembler) !void {700fn parseString(ass: *Assembler) !void {
702 const gpa = ass.cg.module.gpa;701 const gpa = ass.cg.gpa;
703702
704 const tok = ass.currentToken();703 const tok = ass.currentToken();
705 try ass.expectToken(.string);704 try ass.expectToken(.string);
...@@ -722,46 +721,36 @@ fn parseString(ass: *Assembler) !void {...@@ -722,46 +721,36 @@ fn parseString(ass: *Assembler) !void {
722}721}
723722
724fn parseContextDependentNumber(ass: *Assembler) !void {723fn parseContextDependentNumber(ass: *Assembler) !void {
725 const module = ass.cg.module;724 const cg = ass.cg;
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.
731 assert(ass.inst.opcode == .OpConstant or ass.inst.opcode == .OpSpecConstant);725 assert(ass.inst.opcode == .OpConstant or ass.inst.opcode == .OpSpecConstant);
732726
733 const tok = ass.currentToken();727 const tok = ass.currentToken();
734 const result = try ass.resolveRef(ass.inst.operands.items[0].ref_id);728 const result = try ass.resolveRef(ass.inst.operands.items[0].ref_id);
735 const result_id = result.resultId();729 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 {731 const words = cg.sections.globals.instructions.items;
754 var it = module.cache.float_types.iterator();732 var offset: usize = 0;
755 while (it.next()) |entry| {733 while (offset < words.len) {
756 const id = entry.value_ptr.*;734 const word_count = words[offset] >> 16;
757 if (id != result_id) continue;735 const opcode: Opcode = @enumFromInt(words[offset] & 0xFFFF);
758 const info = entry.key_ptr.*;736 defer offset += word_count;
759 switch (info.bits) {737 if (word_count == 0) break;
760 16 => try ass.parseContextDependentFloat(16),738 switch (opcode) {
761 32 => try ass.parseContextDependentFloat(32),739 .OpTypeInt => if (word_count >= 4 and @as(Id, @enumFromInt(words[offset + 1])) == result_id) {
762 64 => try ass.parseContextDependentFloat(64),740 const width: u16 = @intCast(words[offset + 2]);
763 else => return ass.fail(tok.start, "cannot parse {}-bit info literal", .{info.bits}),741 const signedness: std.lang.Signedness = if (words[offset + 3] == 0) .unsigned else .signed;
764 }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 => {},
765 }754 }
766 }755 }
767756
...@@ -769,7 +758,7 @@ fn parseContextDependentNumber(ass: *Assembler) !void {...@@ -769,7 +758,7 @@ fn parseContextDependentNumber(ass: *Assembler) !void {
769}758}
770759
771fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, width: u32) !void {760fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, width: u32) !void {
772 const gpa = ass.cg.module.gpa;761 const gpa = ass.cg.gpa;
773762
774 const tok = ass.currentToken();763 const tok = ass.currentToken();
775 if (ass.eatToken(.placeholder)) {764 if (ass.eatToken(.placeholder)) {
...@@ -820,7 +809,7 @@ fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, wi...@@ -820,7 +809,7 @@ fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, wi
820}809}
821810
822fn parseContextDependentFloat(ass: *Assembler, comptime width: u16) !void {811fn parseContextDependentFloat(ass: *Assembler, comptime width: u16) !void {
823 const gpa = ass.cg.module.gpa;812 const gpa = ass.cg.gpa;
824813
825 const Float = std.meta.Float(width);814 const Float = std.meta.Float(width);
826 const Int = @Int(.unsigned, width);815 const Int = @Int(.unsigned, width);
...@@ -893,7 +882,7 @@ fn tokenText(ass: Assembler, tok: Token) []const u8 {...@@ -893,7 +882,7 @@ fn tokenText(ass: Assembler, tok: Token) []const u8 {
893/// Tokenize `ass.src` and put the tokens in `ass.tokens`.882/// Tokenize `ass.src` and put the tokens in `ass.tokens`.
894/// Any errors encountered are appended to `ass.errors`.883/// Any errors encountered are appended to `ass.errors`.
895fn tokenize(ass: *Assembler) !void {884fn tokenize(ass: *Assembler) !void {
896 const gpa = ass.cg.module.gpa;885 const gpa = ass.cg.gpa;
897886
898 ass.tokens.clearRetainingCapacity();887 ass.tokens.clearRetainingCapacity();
899888
src/codegen/spirv/CodeGen.zig+1713-1271
...@@ -1,36 +1,103 @@...@@ -1,36 +1,103 @@
1const std = @import("std");1// Compilation
2const Allocator = std.mem.Allocator;2pt: Zcu.PerThread,
3const Target = std.Target;3zcu: *Zcu,
4const Signedness = std.lang.Signedness;4gpa: Allocator,
5const assert = std.debug.assert;5arena: Allocator,
6const log = std.log.scoped(.codegen);6air: Air,
7liveness: Air.Liveness,
8owner_nav: InternPool.Nav.Index,
9base_line: u32,
710
8const builtin = @import("builtin");11// Module-level output (accumulated across the nav's codegen)
9const link = @import("../../link.zig");12next_result_id: Word = 1,
10const codegen = @import("../../codegen.zig");13decls: std.ArrayList(Decl) = .empty,
11const Zcu = @import("../../Zcu.zig");14decl_deps: std.ArrayList(Decl.Index) = .empty,
12const Type = @import("../../Type.zig");15nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty,
13const Value = @import("../../Value.zig");16uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty,
14const Air = @import("../../Air.zig");17entry_points: std.array_hash_map.Auto(Id, EntryPoint) = .empty,
15const InternPool = @import("../../InternPool.zig");18error_buffer: ?Decl.Index = null,
16const Section = @import("Section.zig");19struct_types: std.array_hash_map.Custom(StructType, Id, StructType.HashContext, true) = .empty,
17const Assembler = @import("Assembler.zig");20builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty,
18const Mir = @import("Mir.zig");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");50const big_int_bits = @bitSizeOf(u32);
21const Opcode = spec.Opcode;
22const Word = spec.Word;
23const Id = spec.Id;
24const IdRange = spec.IdRange;
25const StorageClass = spec.StorageClass;
2651
27const Module = @import("Module.zig");52/// Data can be lowered into in two basic representations: indirect, which is when
28const Decl = Module.Decl;53/// a type is stored in memory, and direct, which is how a type is stored when its
29const Repr = Module.Repr;54/// a direct SPIR-V value.
30const InternMap = Module.InternMap;55pub const Repr = enum {
31const PtrTypeMap = Module.PtrTypeMap;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
35pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {102pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
36 return comptime &.initMany(&.{103 return comptime &.initMany(&.{
...@@ -43,60 +110,40 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {...@@ -43,60 +110,40 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
43 });110 });
44}111}
45112
46pub const zig_call_abi_ver = 3;
47
48const LoopSwitch = struct { cond_var: Id, continue_label: Id };113const LoopSwitch = struct { cond_var: Id, continue_label: Id };
49114
50/// This type indicates the way that a block is terminated. The115/// Pointer-typed AIR refs should resolve through `resolvePtr` to handle the
51/// state of a particular block is used to track how a jump from116/// `tracked_allocas` case explicitly at every use site.
52/// inside the block must reach the outside.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.
53const Block = union(enum) {126const Block = union(enum) {
54 const Incoming = struct {127 const Incoming = struct {
55 src_label: Id,128 src_label: Id,
56 /// Instruction that returns an u32 value of the129 /// Block index (u32) that control flow should jump to next.
57 /// `Air.Inst.Index` that control flow should jump to.
58 next_block: Id,130 next_block: Id,
59 };131 };
60132
61 const SelectionMerge = struct {133 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.
65 incoming: Incoming,134 incoming: Incoming,
66 /// The label id of the cond_br's merge block.135 /// Label of the cond_br's merge block (undefined for top-of-stack).
67 /// For the top-most element in the stack, this
68 /// value is undefined.
69 merge_block: Id,136 merge_block: Id,
70 };137 };
71138
72 /// For a `selection` type block, we cannot use early exits, and we139 /// Selection blocks can't use early exits. Closing requires a "merge ladder"
73 /// must generate a 'merge ladder' of OpSelection instructions. To that end,140 /// of nested OpSelectionMerge instructions, one per pending merge.
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
87 selection: struct {141 selection: struct {
88 /// In order to know which merges we still need to do, we need to keep
89 /// a stack of those.
90 merge_stack: std.ArrayList(SelectionMerge) = .empty,142 merge_stack: std.ArrayList(SelectionMerge) = .empty,
91 },143 },
92 /// For a `loop` type block, we can early-exit the block by144 /// Loop blocks early-exit by jumping to the loop merge label.
93 /// jumping to the loop exit node, and we don't need to generate
94 /// an entire stack of merges.
95 loop: struct {145 loop: struct {
96 /// The next block to jump to can be determined from any number
97 /// of conditions that jump to the loop exit.
98 merges: std.ArrayList(Incoming) = .empty,146 merges: std.ArrayList(Incoming) = .empty,
99 /// The label id of the loop's merge block.
100 merge_block: Id,147 merge_block: Id,
101 },148 },
102149
...@@ -109,39 +156,36 @@ const Block = union(enum) {...@@ -109,39 +156,36 @@ const Block = union(enum) {
109 }156 }
110};157};
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
134pub fn deinit(cg: *CodeGen) void {159pub fn deinit(cg: *CodeGen) void {
135 const gpa = cg.module.gpa;160 const gpa = cg.gpa;
136 cg.block_stack.deinit(gpa);161 cg.block_stack.deinit(gpa);
137 cg.block_results.deinit(gpa);162 cg.block_results.deinit(gpa);
138 cg.args.deinit(gpa);163 cg.args.deinit(gpa);
139 cg.virtual_allocas.deinit(gpa);164 cg.tracked_allocas.deinit(gpa);
140 cg.inst_results.deinit(gpa);165 cg.inst_results.deinit(gpa);
141 cg.loop_switches.deinit(gpa);166 cg.loop_switches.deinit(gpa);
142 cg.id_scratch.deinit(gpa);167 cg.id_scratch.deinit(gpa);
143 cg.prologue.deinit(gpa);168 cg.prologue.deinit(gpa);
144 cg.body.deinit(gpa);169 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);
145}189}
146190
147pub fn generate(191pub fn generate(
...@@ -157,19 +201,15 @@ pub fn generate(...@@ -157,19 +201,15 @@ pub fn generate(
157201
158 var arena = std.heap.ArenaAllocator.init(gpa);202 var arena = std.heap.ArenaAllocator.init(gpa);
159 defer arena.deinit();203 defer arena.deinit();
160 var module: Module = .{
161 .gpa = gpa,
162 .arena = arena.allocator(),
163 .zcu = zcu,
164 };
165 defer module.deinit();
166204
167 var cg: CodeGen = .{205 var cg: CodeGen = .{
168 .pt = pt,206 .pt = pt,
207 .gpa = gpa,
208 .arena = arena.allocator(),
209 .zcu = zcu,
169 .air = air.*,210 .air = air.*,
170 .liveness = liveness.*.?,211 .liveness = liveness.*.?,
171 .owner_nav = nav,212 .owner_nav = nav,
172 .module = &module,
173 .base_line = zcu.navSrcLine(nav),213 .base_line = zcu.navSrcLine(nav),
174 };214 };
175 defer cg.deinit();215 defer cg.deinit();
...@@ -191,19 +231,15 @@ pub fn generateNav(...@@ -191,19 +231,15 @@ pub fn generateNav(
191231
192 var arena = std.heap.ArenaAllocator.init(gpa);232 var arena = std.heap.ArenaAllocator.init(gpa);
193 defer arena.deinit();233 defer arena.deinit();
194 var module: Module = .{
195 .gpa = gpa,
196 .arena = arena.allocator(),
197 .zcu = zcu,
198 };
199 defer module.deinit();
200234
201 var cg: CodeGen = .{235 var cg: CodeGen = .{
202 .pt = pt,236 .pt = pt,
237 .gpa = gpa,
238 .arena = arena.allocator(),
239 .zcu = zcu,
203 .air = undefined,240 .air = undefined,
204 .liveness = undefined,241 .liveness = undefined,
205 .owner_nav = nav_index,242 .owner_nav = nav_index,
206 .module = &module,
207 .base_line = zcu.navSrcLine(nav_index),243 .base_line = zcu.navSrcLine(nav_index),
208 };244 };
209 defer cg.deinit();245 defer cg.deinit();
...@@ -217,11 +253,9 @@ pub fn generateNav(...@@ -217,11 +253,9 @@ pub fn generateNav(
217}253}
218254
219fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {255fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
220 const module = cg.module;256 const owner_entry = cg.nav_link.get(cg.owner_nav);
221
222 const owner_entry = module.nav_link.get(cg.owner_nav);
223 const owner_decl_index = owner_entry orelse return .{257 const owner_decl_index = owner_entry orelse return .{
224 .id_bound = module.next_result_id,258 .id_bound = cg.next_result_id,
225 .owner_nav = cg.owner_nav,259 .owner_nav = cg.owner_nav,
226 .kind = .func,260 .kind = .func,
227 .decl_result_id = .none,261 .decl_result_id = .none,
...@@ -239,14 +273,14 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {...@@ -239,14 +273,14 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
239 .entry_points = &.{},273 .entry_points = &.{},
240 };274 };
241275
242 const owner_decl = module.declPtr(owner_decl_index);276 const owner_decl = cg.declPtr(owner_decl_index);
243277
244 var nav_refs: std.ArrayList(Mir.NavRef) = .empty;278 var nav_refs: std.ArrayList(Mir.NavRef) = .empty;
245 defer nav_refs.deinit(gpa);279 defer nav_refs.deinit(gpa);
246 var nav_it = module.nav_link.iterator();280 var nav_it = cg.nav_link.iterator();
247 while (nav_it.next()) |entry| {281 while (nav_it.next()) |entry| {
248 if (entry.key_ptr.* == cg.owner_nav) continue;282 if (entry.key_ptr.* == cg.owner_nav) continue;
249 const decl = module.declPtr(entry.value_ptr.*);283 const decl = cg.declPtr(entry.value_ptr.*);
250 try nav_refs.append(gpa, .{284 try nav_refs.append(gpa, .{
251 .local_id = decl.result_id,285 .local_id = decl.result_id,
252 .nav = entry.key_ptr.*,286 .nav = entry.key_ptr.*,
...@@ -256,9 +290,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {...@@ -256,9 +290,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
256290
257 var uav_refs: std.ArrayList(Mir.UavRef) = .empty;291 var uav_refs: std.ArrayList(Mir.UavRef) = .empty;
258 defer uav_refs.deinit(gpa);292 defer uav_refs.deinit(gpa);
259 var uav_it = module.uav_link.iterator();293 var uav_it = cg.uav_link.iterator();
260 while (uav_it.next()) |entry| {294 while (uav_it.next()) |entry| {
261 const decl = module.declPtr(entry.value_ptr.*);295 const decl = cg.declPtr(entry.value_ptr.*);
262 try uav_refs.append(gpa, .{296 try uav_refs.append(gpa, .{
263 .local_id = decl.result_id,297 .local_id = decl.result_id,
264 .val = entry.key_ptr.*[0],298 .val = entry.key_ptr.*[0],
...@@ -272,9 +306,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {...@@ -272,9 +306,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
272 var internal_globals: std.ArrayList(Id) = .empty;306 var internal_globals: std.ArrayList(Id) = .empty;
273 defer internal_globals.deinit(gpa);307 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];
276 for (deps) |dep_index| {310 for (deps) |dep_index| {
277 const dep_decl = module.declPtr(dep_index);311 const dep_decl = cg.declPtr(dep_index);
278 var found = false;312 var found = false;
279 nav_it.index = 0;313 nav_it.index = 0;
280 while (nav_it.next()) |entry| {314 while (nav_it.next()) |entry| {
...@@ -294,10 +328,10 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {...@@ -294,10 +328,10 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
294328
295 var ep_list: std.ArrayList(Mir.EntryPoint) = .empty;329 var ep_list: std.ArrayList(Mir.EntryPoint) = .empty;
296 defer ep_list.deinit(gpa);330 defer ep_list.deinit(gpa);
297 var ep_it = module.entry_points.iterator();331 var ep_it = cg.entry_points.iterator();
298 while (ep_it.next()) |entry| {332 while (ep_it.next()) |entry| {
299 const ep = entry.value_ptr;333 const ep = entry.value_ptr;
300 const ep_decl = module.declPtr(ep.decl_index);334 const ep_decl = cg.declPtr(ep.decl_index);
301 try ep_list.append(gpa, .{335 try ep_list.append(gpa, .{
302 .local_id = ep_decl.result_id,336 .local_id = ep_decl.result_id,
303 .name = try gpa.dupe(u8, ep.name),337 .name = try gpa.dupe(u8, ep.name),
...@@ -306,17 +340,17 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {...@@ -306,17 +340,17 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
306 }340 }
307341
308 return .{342 return .{
309 .id_bound = module.next_result_id,343 .id_bound = cg.next_result_id,
310 .owner_nav = cg.owner_nav,344 .owner_nav = cg.owner_nav,
311 .kind = owner_decl.kind,345 .kind = owner_decl.kind,
312 .decl_result_id = owner_decl.result_id,346 .decl_result_id = owner_decl.result_id,
313 .extended_instruction_set = try module.sections.extended_instruction_set.instructions.toOwnedSlice(gpa),347 .extended_instruction_set = try cg.sections.extended_instruction_set.instructions.toOwnedSlice(gpa),
314 .globals = try module.sections.globals.instructions.toOwnedSlice(gpa),348 .globals = try cg.sections.globals.instructions.toOwnedSlice(gpa),
315 .functions = try module.sections.functions.instructions.toOwnedSlice(gpa),349 .functions = try cg.sections.functions.instructions.toOwnedSlice(gpa),
316 .annotations = try module.sections.annotations.instructions.toOwnedSlice(gpa),350 .annotations = try cg.sections.annotations.instructions.toOwnedSlice(gpa),
317 .debug_names = try module.sections.debug_names.instructions.toOwnedSlice(gpa),351 .debug_names = try cg.sections.debug_names.instructions.toOwnedSlice(gpa),
318 .debug_strings = try module.sections.debug_strings.instructions.toOwnedSlice(gpa),352 .debug_strings = try cg.sections.debug_strings.instructions.toOwnedSlice(gpa),
319 .execution_modes = try module.sections.execution_modes.instructions.toOwnedSlice(gpa),353 .execution_modes = try cg.sections.execution_modes.instructions.toOwnedSlice(gpa),
320 .nav_refs = try nav_refs.toOwnedSlice(gpa),354 .nav_refs = try nav_refs.toOwnedSlice(gpa),
321 .uav_refs = try uav_refs.toOwnedSlice(gpa),355 .uav_refs = try uav_refs.toOwnedSlice(gpa),
322 .decl_deps = try decl_deps.toOwnedSlice(gpa),356 .decl_deps = try decl_deps.toOwnedSlice(gpa),
...@@ -325,11 +359,365 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {...@@ -325,11 +359,365 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
325 };359 };
326}360}
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
328const Error = error{ AlreadyReported, OutOfMemory };716const Error = error{ AlreadyReported, OutOfMemory };
329717
330pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {718pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
331 const gpa = cg.module.gpa;719 const gpa = cg.gpa;
332 const zcu = cg.module.zcu;720 const zcu = cg.zcu;
333 const ip = &zcu.intern_pool;721 const ip = &zcu.intern_pool;
334 const target = zcu.getTarget();722 const target = zcu.getTarget();
335723
...@@ -339,17 +727,17 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -339,17 +727,17 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
339727
340 if (!do_codegen and !ty.hasRuntimeBits(zcu)) return;728 if (!do_codegen and !ty.hasRuntimeBits(zcu)) return;
341729
342 const spv_decl_index = try cg.module.resolveNav(ip, cg.owner_nav);730 const spv_decl_index = try cg.resolveNav(ip, cg.owner_nav);
343 const decl = cg.module.declPtr(spv_decl_index);731 const decl = cg.declPtr(spv_decl_index);
344 const result_id = decl.result_id;732 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
347 switch (decl.kind) {735 switch (decl.kind) {
348 .func => {736 .func => {
349 if (nav.resolved.?.is_extern_decl) {737 if (nav.resolved.?.is_extern_decl) {
350 _ = try cg.resolveType(ty, .direct);738 _ = try cg.resolveType(ty, .direct);
351 try emitExternFnStub(cg, nav, decl, ty);739 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;
353 return;741 return;
354 }742 }
355743
...@@ -357,7 +745,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -357,7 +745,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
357 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));745 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
358 const is_test = zcu.test_functions.contains(cg.owner_nav);746 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;
361 const prototype_ty_id = try cg.resolveType(ty, .direct);749 const prototype_ty_id = try cg.resolveType(ty, .direct);
362 try cg.prologue.emit(gpa, .OpFunction, .{750 try cg.prologue.emit(gpa, .OpFunction, .{
363 .id_result_type = return_ty_id,751 .id_result_type = return_ty_id,
...@@ -368,14 +756,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -368,14 +756,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
368 .function_control = .{},756 .function_control = .{},
369 });757 });
370758
371 comptime assert(zig_call_abi_ver == 3);
372 try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len);759 try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len);
373 for (fn_info.param_types.get(ip)) |param_ty_index| {760 for (fn_info.param_types.get(ip)) |param_ty_index| {
374 const param_ty: Type = .fromInterned(param_ty_index);761 const param_ty: Type = .fromInterned(param_ty_index);
375 if (!param_ty.hasRuntimeBits(zcu)) continue;762 if (!param_ty.hasRuntimeBits(zcu)) continue;
376763
377 const param_type_id = try cg.resolveType(param_ty, .direct);764 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();
379 try cg.prologue.emit(gpa, .OpFunctionParameter, .{766 try cg.prologue.emit(gpa, .OpFunctionParameter, .{
380 .id_result_type = param_type_id,767 .id_result_type = param_type_id,
381 .id_result = arg_result_id,768 .id_result = arg_result_id,
...@@ -384,7 +771,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -384,7 +771,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
384 }771 }
385772
386 // TODO: This could probably be done in a better way...773 // 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
389 // The root block of a function declaration should appear before OpVariable instructions,776 // The root block of a function declaration should appear before OpVariable instructions,
390 // so it is generated into the function's prologue.777 // so it is generated into the function's prologue.
...@@ -400,26 +787,26 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -400,26 +787,26 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
400 try cg.body.emit(gpa, .OpUnreachable, {});787 try cg.body.emit(gpa, .OpUnreachable, {});
401 try cg.body.emit(gpa, .OpFunctionEnd, {});788 try cg.body.emit(gpa, .OpFunctionEnd, {});
402 // Append the actual code into the functions section.789 // Append the actual code into the functions section.
403 try cg.module.sections.functions.append(gpa, cg.prologue);790 try cg.sections.functions.append(gpa, cg.prologue);
404 try cg.module.sections.functions.append(gpa, cg.body);791 try cg.sections.functions.append(gpa, cg.body);
405792
406 // Temporarily generate a test kernel declaration if this is a test function.793 // Temporarily generate a test kernel declaration if this is a test function.
407 if (is_test) {794 if (is_test) {
408 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);795 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);
409 }796 }
410797
411 try cg.module.debugName(func_result_id, nav.fqn.toSlice(ip));798 try cg.debugName(func_result_id, nav.fqn.toSlice(ip));
412 },799 },
413 .global => {800 .global => {
414 const key = ip.indexToKey(val.toIntern()).@"extern";801 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");
417 assert(storage_class != .generic); // These should be instance globals804 assert(storage_class != .generic); // These should be instance globals
418805
419 const ty_id = try cg.resolveType(ty, .indirect);806 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, .{
423 .id_result_type = ptr_ty_id,810 .id_result_type = ptr_ty_id,
424 .id_result = result_id,811 .id_result = result_id,
425 .storage_class = storage_class,812 .storage_class = storage_class,
...@@ -430,11 +817,11 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -430,11 +817,11 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
430 switch (storage_class) {817 switch (storage_class) {
431 .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => {818 .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => {
432 if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) {819 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);
434 }821 }
435822
436 if (ty.hasRuntimeBits(zcu)) {823 if (ty.hasRuntimeBits(zcu)) {
437 try cg.module.decorate(ptr_ty_id, .{824 try cg.decorate(ptr_ty_id, .{
438 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },825 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },
439 });826 });
440 try cg.decorateLayout(ty, ty_id);827 try cg.decorateLayout(ty, ty_id);
...@@ -448,23 +835,23 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -448,23 +835,23 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
448 if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) {835 if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) {
449 return cg.fail("storage class must be one of (output, input, uniform_constant) but is {s}", .{@tagName(storage_class)});836 return cg.fail("storage class must be one of (output, input, uniform_constant) but is {s}", .{@tagName(storage_class)});
450 }837 }
451 try cg.module.decorate(result_id, .{838 try cg.decorate(result_id, .{
452 .location = .{ .location = location },839 .location = .{ .location = location },
453 });840 });
454 },841 },
455 .flat => |location| {842 .flat => |location| {
456 try cg.module.decorate(result_id, .{ .location = .{ .location = location } });843 try cg.decorate(result_id, .{ .location = .{ .location = location } });
457 try cg.module.decorate(result_id, .flat);844 try cg.decorate(result_id, .flat);
458 },845 },
459 .descriptor => |descriptor| {846 .descriptor => |descriptor| {
460 if (storage_class != .storage_buffer and storage_class != .uniform and storage_class != .uniform_constant) {847 if (storage_class != .storage_buffer and storage_class != .uniform and storage_class != .uniform_constant) {
461 return cg.fail("storage class must be one of (storage_buffer, uniform, uniform_constant) but is {s}", .{@tagName(storage_class)});848 return cg.fail("storage class must be one of (storage_buffer, uniform, uniform_constant) but is {s}", .{@tagName(storage_class)});
462 }849 }
463 try cg.module.decorate(result_id, .{850 try cg.decorate(result_id, .{
464 .binding = .{ .binding_point = descriptor.binding },851 .binding = .{ .binding_point = descriptor.binding },
465 });852 });
466853
467 try cg.module.decorate(result_id, .{854 try cg.decorate(result_id, .{
468 .descriptor_set = .{ .descriptor_set = descriptor.set },855 .descriptor_set = .{ .descriptor_set = descriptor.set },
469 });856 });
470 },857 },
...@@ -474,10 +861,10 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -474,10 +861,10 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
474 }861 }
475862
476 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |built_in| {863 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 } });
478 }865 }
479866
480 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));867 try cg.debugName(result_id, nav.fqn.toSlice(ip));
481 },868 },
482 .invocation_global => {869 .invocation_global => {
483 // `@extern()` produces an invocation_global whose value is a870 // `@extern()` produces an invocation_global whose value is a
...@@ -488,18 +875,18 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -488,18 +875,18 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
488 if (ptr_key.base_addr != .nav or ptr_key.byte_offset != 0) break :alias;875 if (ptr_key.base_addr != .nav or ptr_key.byte_offset != 0) break :alias;
489 const underlying_nav = ip.getNav(ptr_key.base_addr.nav);876 const underlying_nav = ip.getNav(ptr_key.base_addr.nav);
490 if (!underlying_nav.resolved.?.is_extern_decl) break :alias;877 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;
492 return;879 return;
493 }880 }
494881
495 const ty_id = try cg.resolveType(ty, .indirect);882 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
498 // TODO: Combine with resolveAnonDecl?885 // TODO: Combine with resolveAnonDecl?
499 const void_ty_id = try cg.resolveType(.void, .direct);886 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();
503 try cg.prologue.emit(gpa, .OpFunction, .{890 try cg.prologue.emit(gpa, .OpFunction, .{
504 .id_result_type = try cg.resolveType(.void, .direct),891 .id_result_type = try cg.resolveType(.void, .direct),
505 .id_result = initializer_id,892 .id_result = initializer_id,
...@@ -507,7 +894,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -507,7 +894,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
507 .function_type = initializer_proto_ty_id,894 .function_type = initializer_proto_ty_id,
508 });895 });
509896
510 const root_block_id = cg.module.allocId();897 const root_block_id = cg.allocId();
511 try cg.prologue.emit(gpa, .OpLabel, .{898 try cg.prologue.emit(gpa, .OpLabel, .{
512 .id_result = root_block_id,899 .id_result = root_block_id,
513 });900 });
...@@ -521,33 +908,33 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -521,33 +908,33 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
521908
522 try cg.body.emit(gpa, .OpReturn, {});909 try cg.body.emit(gpa, .OpReturn, {});
523 try cg.body.emit(gpa, .OpFunctionEnd, {});910 try cg.body.emit(gpa, .OpFunctionEnd, {});
524 try cg.module.sections.functions.append(gpa, cg.prologue);911 try cg.sections.functions.append(gpa, cg.prologue);
525 try cg.module.sections.functions.append(gpa, cg.body);912 try cg.sections.functions.append(gpa, cg.body);
526913
527 try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});914 try cg.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
528 try cg.module.debugName(result_id, nav.fqn.toSlice(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, .{
531 .id_result_type = ptr_ty_id,918 .id_result_type = ptr_ty_id,
532 .id_result = result_id,919 .id_result = result_id,
533 .set = try cg.module.importInstructionSet(.zig),920 .set = try cg.importInstructionSet(.zig),
534 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },921 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
535 .id_ref_4 = &.{initializer_id},922 .id_ref_4 = &.{initializer_id},
536 });923 });
537 },924 },
538 }925 }
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;
541}928}
542929
543fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {930fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
544 const zcu = cg.module.zcu;931 const zcu = cg.zcu;
545 const ip = &zcu.intern_pool;932 const ip = &zcu.intern_pool;
546 switch (ty.zigTypeTag(zcu)) {933 switch (ty.zigTypeTag(zcu)) {
547 .array => {934 .array => {
548 const elem_ty = ty.childType(zcu);935 const elem_ty = ty.childType(zcu);
549 if (!elem_ty.hasRuntimeBits(zcu)) return;936 if (!elem_ty.hasRuntimeBits(zcu)) return;
550 try cg.module.decorate(ty_id, .{937 try cg.decorate(ty_id, .{
551 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },938 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
552 });939 });
553 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));940 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 {...@@ -556,7 +943,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
556 const elem_ty = ty.childType(zcu);943 const elem_ty = ty.childType(zcu);
557 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));944 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
558 if (cg.isSpvVector(ty)) return;945 if (cg.isSpvVector(ty)) return;
559 try cg.module.decorate(ty_id, .{946 try cg.decorate(ty_id, .{
560 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },947 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
561 });948 });
562 },949 },
...@@ -570,7 +957,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {...@@ -570,7 +957,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
570 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);957 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
571 if (!field_ty.hasRuntimeBits(zcu)) continue;958 if (!field_ty.hasRuntimeBits(zcu)) continue;
572 const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu));959 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 } });
574 try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect));961 try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect));
575 member += 1;962 member += 1;
576 }963 }
...@@ -598,13 +985,13 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {...@@ -598,13 +985,13 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
598 const u8_id = try cg.resolveType(.u8, .direct);985 const u8_id = try cg.resolveType(.u8, .direct);
599 if (layout.payload_padding_size != 0) {986 if (layout.payload_padding_size != 0) {
600 const len_id = try cg.constInt(.u32, layout.payload_padding_size);987 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
601 const arr_id = try cg.module.arrayType(len_id, u8_id);988 const arr_id = try cg.arrayType(len_id, u8_id);
602 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });989 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
603 }990 }
604 if (layout.padding_size != 0) {991 if (layout.padding_size != 0) {
605 const len_id = try cg.constInt(.u32, layout.padding_size);992 const len_id = try cg.constInt(.u32, layout.padding_size);
606 const arr_id = try cg.module.arrayType(len_id, u8_id);993 const arr_id = try cg.arrayType(len_id, u8_id);
607 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });994 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
608 }995 }
609 },996 },
610 .optional => {997 .optional => {
...@@ -621,7 +1008,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {...@@ -621,7 +1008,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
6211008
622pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {1009pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
623 @branchHint(.cold);1010 @branchHint(.cold);
624 return cg.module.zcu.codegenFail(cg.owner_nav, format, args);1011 return cg.zcu.codegenFail(cg.owner_nav, format, args);
625}1012}
6261013
627pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {1014pub 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 {...@@ -631,17 +1018,17 @@ pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
631/// This imports the "default" extended instruction set for the target1018/// This imports the "default" extended instruction set for the target
632/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.1019/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.
633fn importExtendedSet(cg: *CodeGen) !Id {1020fn importExtendedSet(cg: *CodeGen) !Id {
634 const target = cg.module.zcu.getTarget();1021 const target = cg.zcu.getTarget();
635 return switch (target.os.tag) {1022 return switch (target.os.tag) {
636 .opencl, .amdhsa => try cg.module.importInstructionSet(.@"OpenCL.std"),1023 .opencl, .amdhsa => try cg.importInstructionSet(.@"OpenCL.std"),
637 .vulkan, .opengl => try cg.module.importInstructionSet(.@"GLSL.std.450"),1024 .vulkan, .opengl => try cg.importInstructionSet(.@"GLSL.std.450"),
638 else => unreachable,1025 else => unreachable,
639 };1026 };
640}1027}
6411028
642/// Fetch the result-id for a previously generated instruction or constant.1029/// Fetch the result-id for a previously generated instruction or constant.
643fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {1030fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
644 const zcu = cg.module.zcu;1031 const zcu = cg.zcu;
645 const ip = &zcu.intern_pool;1032 const ip = &zcu.intern_pool;
646 if (inst.toInterned()) |val_ip_index| {1033 if (inst.toInterned()) |val_ip_index| {
647 const ty = cg.typeOf(inst);1034 const ty = cg.typeOf(inst);
...@@ -652,9 +1039,9 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {...@@ -652,9 +1039,9 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
652 .func => |func| func.owner_nav,1039 .func => |func| func.owner_nav,
653 else => unreachable,1040 else => unreachable,
654 };1041 };
655 const spv_decl_index = try cg.module.resolveNav(ip, fn_nav);1042 const spv_decl_index = try cg.resolveNav(ip, fn_nav);
656 try cg.module.decl_deps.append(cg.module.gpa, spv_decl_index);1043 try cg.decl_deps.append(cg.gpa, spv_decl_index);
657 const decl = cg.module.declPtr(spv_decl_index);1044 const decl = cg.declPtr(spv_decl_index);
658 if (val_key == .@"extern") {1045 if (val_key == .@"extern") {
659 const nav = ip.getNav(fn_nav);1046 const nav = ip.getNav(fn_nav);
660 const nav_ty: Type = .fromInterned(nav.resolved.?.type);1047 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
...@@ -670,22 +1057,22 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {...@@ -670,22 +1057,22 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
670}1057}
6711058
672fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {1059fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
673 const gpa = cg.module.gpa;1060 const gpa = cg.gpa;
6741061
675 // TODO: This cannot be a function at this point, but it should probably be handled anyway.1062 // 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;
678 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));1065 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
679 const ty_id = try cg.resolveType(ty, .indirect);1066 const ty_id = try cg.resolveType(ty, .indirect);
6801067
681 const spv_decl_index = blk: {1068 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 });
683 if (entry.found_existing) {1070 if (entry.found_existing) {
684 try cg.addFunctionDep(entry.value_ptr.*, .function);1071 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;
686 }1073 }
6871074
688 const spv_decl_index = try cg.module.allocDecl(.invocation_global);1075 const spv_decl_index = try cg.allocDecl(.invocation_global);
689 try cg.addFunctionDep(spv_decl_index, .function);1076 try cg.addFunctionDep(spv_decl_index, .function);
690 entry.value_ptr.* = spv_decl_index;1077 entry.value_ptr.* = spv_decl_index;
691 break :blk spv_decl_index;1078 break :blk spv_decl_index;
...@@ -697,7 +1084,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -697,7 +1084,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
697 // constant lowering of this value will need to be deferred to an initializer similar to1084 // constant lowering of this value will need to be deferred to an initializer similar to
698 // other globals.1085 // 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
702 {1089 {
703 // Save the current state so that we can temporarily generate into a different function.1090 // 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 {...@@ -719,16 +1106,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
719 }1106 }
7201107
721 const void_ty_id = try cg.resolveType(.void, .direct);1108 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();
725 try cg.prologue.emit(gpa, .OpFunction, .{1112 try cg.prologue.emit(gpa, .OpFunction, .{
726 .id_result_type = try cg.resolveType(.void, .direct),1113 .id_result_type = try cg.resolveType(.void, .direct),
727 .id_result = initializer_id,1114 .id_result = initializer_id,
728 .function_control = .{},1115 .function_control = .{},
729 .function_type = initializer_proto_ty_id,1116 .function_type = initializer_proto_ty_id,
730 });1117 });
731 const root_block_id = cg.module.allocId();1118 const root_block_id = cg.allocId();
732 try cg.prologue.emit(gpa, .OpLabel, .{1119 try cg.prologue.emit(gpa, .OpLabel, .{
733 .id_result = root_block_id,1120 .id_result = root_block_id,
734 });1121 });
...@@ -743,16 +1130,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -743,16 +1130,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
743 try cg.body.emit(gpa, .OpReturn, {});1130 try cg.body.emit(gpa, .OpReturn, {});
744 try cg.body.emit(gpa, .OpFunctionEnd, {});1131 try cg.body.emit(gpa, .OpFunctionEnd, {});
7451132
746 try cg.module.sections.functions.append(gpa, cg.prologue);1133 try cg.sections.functions.append(gpa, cg.prologue);
747 try cg.module.sections.functions.append(gpa, cg.body);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);1138 const fn_decl_ptr_ty_id = try cg.ptrType(ty_id, .function);
752 try cg.module.sections.globals.emit(gpa, .OpExtInst, .{1139 try cg.sections.globals.emit(gpa, .OpExtInst, .{
753 .id_result_type = fn_decl_ptr_ty_id,1140 .id_result_type = fn_decl_ptr_ty_id,
754 .id_result = result_id,1141 .id_result = result_id,
755 .set = try cg.module.importInstructionSet(.zig),1142 .set = try cg.importInstructionSet(.zig),
756 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },1143 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
757 .id_ref_4 = &.{initializer_id},1144 .id_ref_4 = &.{initializer_id},
758 });1145 });
...@@ -761,15 +1148,21 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -761,15 +1148,21 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
761 return result_id;1148 return result_id;
762}1149}
7631150
764fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void {1151fn resolvePtr(cg: *CodeGen, ref: Air.Inst.Ref) !Ptr {
765 const gpa = cg.module.gpa;1152 const id = try cg.resolve(ref);
766 const target = cg.module.zcu.getTarget();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();
767 if (target.cpu.has(.spirv, .v1_4)) {1160 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);
769 } else {1162 } else {
770 // Before version 1.4, the interface’s storage classes are limited to the Input and Output1163 // Before version 1.4, the interface’s storage classes are limited to the Input and Output
771 if (storage_class == .input or storage_class == .output) {1164 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);
773 }1166 }
774 }1167 }
775}1168}
...@@ -779,25 +1172,11 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St...@@ -779,25 +1172,11 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St
779/// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to1172/// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to
780/// keep track of the previous block.1173/// keep track of the previous block.
781fn beginSpvBlock(cg: *CodeGen, label: Id) !void {1174fn 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 });
783 cg.block_label = label;1176 cg.block_label = label;
784 cg.block_terminated = false;1177 cg.block_terminated = false;
785}1178}
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
801const ArithmeticTypeInfo = struct {1180const ArithmeticTypeInfo = struct {
802 const Class = enum {1181 const Class = enum {
803 bool,1182 bool,
...@@ -835,8 +1214,8 @@ const ArithmeticTypeInfo = struct {...@@ -835,8 +1214,8 @@ const ArithmeticTypeInfo = struct {
835};1214};
8361215
837fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {1216fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
838 const zcu = cg.module.zcu;1217 const zcu = cg.zcu;
839 const target = cg.module.zcu.getTarget();1218 const target = cg.zcu.getTarget();
840 var scalar_ty = ty.scalarType(zcu);1219 var scalar_ty = ty.scalarType(zcu);
841 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {1220 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {
842 scalar_ty = scalar_ty.intTagType(zcu);1221 scalar_ty = scalar_ty.intTagType(zcu);
...@@ -845,7 +1224,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -845,7 +1224,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
845 return switch (scalar_ty.zigTypeTag(zcu)) {1224 return switch (scalar_ty.zigTypeTag(zcu)) {
846 .bool => .{1225 .bool => .{
847 .bits = 1, // Doesn't matter for this class.1226 .bits = 1, // Doesn't matter for this class.
848 .backing_bits = cg.module.backingIntBits(1).@"0",1227 .backing_bits = cg.backingIntBits(1).@"0",
849 .vector_len = vector_len,1228 .vector_len = vector_len,
850 .signedness = .unsigned, // Technically, but doesn't matter for this class.1229 .signedness = .unsigned, // Technically, but doesn't matter for this class.
851 .class = .bool,1230 .class = .bool,
...@@ -860,7 +1239,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -860,7 +1239,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
860 .int => blk: {1239 .int => blk: {
861 const int_info = scalar_ty.intInfo(zcu);1240 const int_info = scalar_ty.intInfo(zcu);
862 // TODO: Maybe it's useful to also return this value.1241 // 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);
864 break :blk .{1243 break :blk .{
865 .bits = int_info.bits,1244 .bits = int_info.bits,
866 .backing_bits = backing_bits,1245 .backing_bits = backing_bits,
...@@ -880,8 +1259,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -880,8 +1259,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8801259
881/// Checks whether the type can be directly translated to SPIR-V vectors1260/// Checks whether the type can be directly translated to SPIR-V vectors
882fn isSpvVector(cg: *CodeGen, ty: Type) bool {1261fn isSpvVector(cg: *CodeGen, ty: Type) bool {
883 const zcu = cg.module.zcu;1262 const zcu = cg.zcu;
884 const target = cg.module.zcu.getTarget();1263 const target = cg.zcu.getTarget();
885 if (ty.zigTypeTag(zcu) != .vector) return false;1264 if (ty.zigTypeTag(zcu) != .vector) return false;
8861265
887 // TODO: This check must be expanded for types that can be represented1266 // TODO: This check must be expanded for types that can be represented
...@@ -909,23 +1288,34 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {...@@ -909,23 +1288,34 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {
9091288
910/// Emits a bool constant in a particular representation.1289/// Emits a bool constant in a particular representation.
911fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {1290fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {
912 return switch (repr) {1291 switch (repr) {
913 .indirect => cg.constInt(.u1, @intFromBool(value)),1292 .indirect => return cg.constInt(.u1, @intFromBool(value)),
914 .direct => cg.module.constBool(value),1293 .direct => {
915 };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 }
916}1306}
9171307
918/// Emits an integer constant.1308/// Emits an integer constant.
919/// This function, unlike Module.constInt, takes care to bitcast1309/// This function, unlike cg.constInt, takes care to bitcast
920/// the value to an unsigned int first for Kernels.1310/// the value to an unsigned int first for Kernels.
921fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {1311fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
922 const gpa = cg.module.gpa;1312 const gpa = cg.gpa;
923 const zcu = cg.module.zcu;1313 const zcu = cg.zcu;
924 const target = cg.module.zcu.getTarget();1314 const target = cg.zcu.getTarget();
925 const scalar_ty = ty.scalarType(zcu);1315 const scalar_ty = ty.scalarType(zcu);
926 const int_info = scalar_ty.intInfo(zcu);1316 const int_info = scalar_ty.intInfo(zcu);
927 // Use backing bits so that negatives are sign extended1317 // 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);
929 assert(backing_bits != 0); // u0 is comptime1319 assert(backing_bits != 0); // u0 is comptime
9301320
931 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);1321 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);
...@@ -939,7 +1329,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -939,7 +1329,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
939 .signed => @bitCast(@as(i64, @intCast(value))),1329 .signed => @bitCast(@as(i64, @intCast(value))),
940 .unsigned => @as(u64, @intCast(value)),1330 .unsigned => @as(u64, @intCast(value)),
941 };1331 };
942 const n_limbs = backing_bits / Module.big_int_bits;1332 const n_limbs = backing_bits / big_int_bits;
943 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;1333 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;
944 const scratch_top = cg.id_scratch.items.len;1334 const scratch_top = cg.id_scratch.items.len;
945 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);1335 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
...@@ -979,61 +1369,45 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -979,61 +1369,45 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
979 },1369 },
980 };1370 };
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
984 if (!ty.isVector(zcu)) return result_id;1379 if (!ty.isVector(zcu)) return result_id;
985 return cg.constructCompositeSplat(ty, result_id);1380 return cg.constructCompositeSplat(ty, result_id);
986}1381}
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
1017/// Construct a composite value from its constituents.1383/// Construct a composite value from its constituents.
1018/// In logical addressing mode (Vulkan/OpenGL), OpCompositeConstruct cannot accept1384/// In logical addressing mode (Vulkan/OpenGL), OpCompositeConstruct cannot accept
1019/// pointer operands, so for struct types we use alloc, store for each field and load instead.1385/// pointer operands, so for struct types we use alloc, store for each field and load instead.
1020pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id {1386pub 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| {
1024 assert(fields.len == constituents.len);1393 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);
1026 const var_id = try cg.alloc(result_ty_id, null);1395 const var_id = try cg.alloc(result_ty_id, null);
1027 for (fields, constituents, 0..) |field_ty_id, constituent, i| {1396 for (fields, constituents, 0..) |field_ty_id, constituent, i| {
1028 const field_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);1397 const field_ptr_ty_id = try cg.ptrType(field_ty_id, .function);
1029 const index_id = try cg.module.constant(u32_ty_id, .{ .uint32 = @intCast(i) });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 });
1030 const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id});1404 const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id});
1031 try cg.body.emit(gpa, .OpStore, .{1405 try cg.body.emit(gpa, .OpStore, .{
1032 .pointer = field_ptr,1406 .pointer = field_ptr,
1033 .object = constituent,1407 .object = constituent,
1034 });1408 });
1035 }1409 }
1036 const result_id = cg.module.allocId();1410 const result_id = cg.allocId();
1037 try cg.body.emit(gpa, .OpLoad, .{1411 try cg.body.emit(gpa, .OpLoad, .{
1038 .id_result_type = result_ty_id,1412 .id_result_type = result_ty_id,
1039 .id_result = result_id,1413 .id_result = result_id,
...@@ -1042,7 +1416,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const...@@ -1042,7 +1416,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
1042 return result_id;1416 return result_id;
1043 }1417 }
10441418
1045 const result_id = cg.module.allocId();1419 const result_id = cg.allocId();
1046 try cg.body.emit(gpa, .OpCompositeConstruct, .{1420 try cg.body.emit(gpa, .OpCompositeConstruct, .{
1047 .id_result_type = result_ty_id,1421 .id_result_type = result_ty_id,
1048 .id_result = result_id,1422 .id_result = result_id,
...@@ -1054,8 +1428,8 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const...@@ -1054,8 +1428,8 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
1054/// Construct a composite at runtime with all lanes set to the same value.1428/// Construct a composite at runtime with all lanes set to the same value.
1055/// ty must be an aggregate type.1429/// ty must be an aggregate type.
1056fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {1430fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
1057 const gpa = cg.module.gpa;1431 const gpa = cg.gpa;
1058 const zcu = cg.module.zcu;1432 const zcu = cg.zcu;
1059 const n: usize = @intCast(ty.arrayLen(zcu));1433 const n: usize = @intCast(ty.arrayLen(zcu));
10601434
1061 const scratch_top = cg.id_scratch.items.len;1435 const scratch_top = cg.id_scratch.items.len;
...@@ -1075,24 +1449,17 @@ fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {...@@ -1075,24 +1449,17 @@ fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
1075//1449//
1076/// This function should only be called during function code generation.1450/// This function should only be called during function code generation.
1077fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {1451fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1078 const gpa = cg.module.gpa;1452 const gpa = cg.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 }
10861453
1087 const pt = cg.pt;1454 const pt = cg.pt;
1088 const zcu = cg.module.zcu;1455 const zcu = cg.zcu;
1089 const target = cg.module.zcu.getTarget();1456 const target = cg.zcu.getTarget();
1090 const result_ty_id = try cg.resolveType(ty, repr);1457 const result_ty_id = try cg.resolveType(ty, repr);
1091 const ip = &zcu.intern_pool;1458 const ip = &zcu.intern_pool;
10921459
1093 log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });1460 log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });
1094 if (val.isUndef(zcu)) {1461 if (val.isUndef(zcu)) {
1095 return cg.module.constUndef(result_ty_id);1462 return cg.constUndef(result_ty_id);
1096 }1463 }
10971464
1098 const cacheable_id = cache: {1465 const cacheable_id = cache: {
...@@ -1133,9 +1500,25 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1133,9 +1500,25 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1133 },1500 },
1134 .int => {1501 .int => {
1135 const int_info = ty.intInfo(zcu);1502 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);
1137 if (is_big_int) {1504 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);
1139 }1522 }
1140 if (ty.isSignedInt(zcu)) {1523 if (ty.isSignedInt(zcu)) {
1141 break :cache try cg.constInt(ty, val.toSignedInt(zcu));1524 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 {...@@ -1151,7 +1534,13 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1151 80, 128 => unreachable, // TODO1534 80, 128 => unreachable, // TODO
1152 else => unreachable,1535 else => unreachable,
1153 };1536 };
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;
1155 },1544 },
1156 .err => |err| {1545 .err => |err| {
1157 const value = try pt.getErrorValue(err.name);1546 const value = try pt.getErrorValue(err.name);
...@@ -1218,7 +1607,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1218,7 +1607,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1218 if (maybe_payload_val) |payload_val| {1607 if (maybe_payload_val) |payload_val| {
1219 return try cg.constant(payload_ty, payload_val, .indirect);1608 return try cg.constant(payload_ty, payload_val, .indirect);
1220 } else {1609 } else {
1221 break :cache try cg.module.constNull(result_ty_id);1610 break :cache try cg.constNull(result_ty_id);
1222 }1611 }
1223 }1612 }
12241613
...@@ -1229,7 +1618,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1229,7 +1618,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1229 const payload_id = if (maybe_payload_val) |payload_val|1618 const payload_id = if (maybe_payload_val) |payload_val|
1230 try cg.constant(payload_ty, payload_val, .indirect)1619 try cg.constant(payload_ty, payload_val, .indirect)
1231 else1620 else
1232 try cg.module.constUndef(try cg.resolveType(payload_ty, .indirect));1621 try cg.constUndef(try cg.resolveType(payload_ty, .indirect));
12331622
1234 const comp_ty_id = try cg.resolveType(ty, .direct);1623 const comp_ty_id = try cg.resolveType(ty, .direct);
1235 return try cg.constructComposite(comp_ty_id, &.{ payload_id, has_pl_id });1624 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 {...@@ -1339,21 +1728,18 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1339 .memoized_call => unreachable,1728 .memoized_call => unreachable,
1340 }1729 }
1341 };1730 };
1342
1343 try cg.module.intern_map.putNoClobber(gpa, .{ val.toIntern(), repr }, cacheable_id);
1344
1345 return cacheable_id;1731 return cacheable_id;
1346}1732}
13471733
1348fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {1734fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
1349 const pt = cg.pt;1735 const pt = cg.pt;
1350 const zcu = cg.module.zcu;1736 const zcu = cg.zcu;
1351 const gpa = cg.module.gpa;1737 const gpa = cg.gpa;
13521738
1353 if (ptr_val.isUndef(zcu)) {1739 if (ptr_val.isUndef(zcu)) {
1354 const result_ty = ptr_val.typeOf(zcu);1740 const result_ty = ptr_val.typeOf(zcu);
1355 const result_ty_id = try cg.resolveType(result_ty, .direct);1741 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);
1357 }1743 }
13581744
1359 var arena = std.heap.ArenaAllocator.init(gpa);1745 var arena = std.heap.ArenaAllocator.init(gpa);
...@@ -1364,9 +1750,9 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {...@@ -1364,9 +1750,9 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
1364}1750}
13651751
1366fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {1752fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1367 const gpa = cg.module.gpa;1753 const gpa = cg.gpa;
1368 const pt = cg.pt;1754 const pt = cg.pt;
1369 const zcu = cg.module.zcu;1755 const zcu = cg.zcu;
1370 const target = zcu.getTarget();1756 const target = zcu.getTarget();
1371 switch (derivation) {1757 switch (derivation) {
1372 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,1758 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
...@@ -1383,7 +1769,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1383,7 +1769,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1383 // TODO: This can probably be an OpSpecConstantOp Bitcast, but1769 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
1384 // that is not implemented by Mesa yet. Therefore, just generate it1770 // that is not implemented by Mesa yet. Therefore, just generate it
1385 // as a runtime operation.1771 // as a runtime operation.
1386 const result_ptr_id = cg.module.allocId();1772 const result_ptr_id = cg.allocId();
1387 const value_id = try cg.constInt(.usize, int.addr);1773 const value_id = try cg.constInt(.usize, int.addr);
1388 try cg.body.emit(gpa, .OpConvertUToPtr, .{1774 try cg.body.emit(gpa, .OpConvertUToPtr, .{
1389 .id_result_type = result_ty_id,1775 .id_result_type = result_ty_id,
...@@ -1392,13 +1778,83 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1392,13 +1778,83 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1392 });1778 });
1393 return result_ptr_id;1779 return result_ptr_id;
1394 },1780 },
1395 .nav_ptr => |nav| {1781 .nav_ptr => |nav_index| {
1396 const result_ptr_ty = try pt.navPtrType(nav);1782 const ip = &zcu.intern_pool;
1397 return cg.constantNavRef(result_ptr_ty, nav);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;
1398 },1825 },
1399 .uav_ptr => |uav| {1826 .uav_ptr => |uav| {
1827 const ip = &zcu.intern_pool;
1400 const result_ptr_ty: Type = .fromInterned(uav.orig_ty);1828 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;
1402 },1858 },
1403 .eu_payload_ptr => @panic("TODO"),1859 .eu_payload_ptr => @panic("TODO"),
1404 .opt_payload_ptr => @panic("TODO"),1860 .opt_payload_ptr => @panic("TODO"),
...@@ -1450,7 +1906,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1450,7 +1906,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1450 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);1906 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);
1451 }1907 }
1452 if (target.os.tag == .opencl) {1908 if (target.os.tag == .opencl) {
1453 const result_ptr_id = cg.module.allocId();1909 const result_ptr_id = cg.allocId();
1454 try cg.body.emit(gpa, .OpBitcast, .{1910 try cg.body.emit(gpa, .OpBitcast, .{
1455 .id_result_type = result_ty_id,1911 .id_result_type = result_ty_id,
1456 .id_result = result_ptr_id,1912 .id_result = result_ptr_id,
...@@ -1468,59 +1924,15 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1468,59 +1924,15 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1468 }1924 }
1469}1925}
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
1515/// Emit a stub OpFunction/OpFunctionEnd + Import linkage decoration for an1927/// Emit a stub OpFunction/OpFunctionEnd + Import linkage decoration for an
1516/// extern function so the module is structurally valid. The stub will be1928/// extern function so the module is structurally valid. The stub will be
1517/// replaced by the real definition at link time.1929/// 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 {
1519 if (decl.has_extern_stub) return;1931 if (decl.has_extern_stub) return;
1520 decl.has_extern_stub = true;1932 decl.has_extern_stub = true;
15211933
1522 const gpa = cg.module.gpa;1934 const gpa = cg.gpa;
1523 const zcu = cg.module.zcu;1935 const zcu = cg.zcu;
1524 const ip = &zcu.intern_pool;1936 const ip = &zcu.intern_pool;
1525 const fn_info = zcu.typeToFunc(fn_ty).?;1937 const fn_info = zcu.typeToFunc(fn_ty).?;
1526 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));1938 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...@@ -1540,81 +1952,25 @@ fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Module.Decl, fn_ty
1540 const param_type_id = try cg.resolveType(param_ty, .direct);1952 const param_type_id = try cg.resolveType(param_ty, .direct);
1541 try stub.emit(gpa, .OpFunctionParameter, .{1953 try stub.emit(gpa, .OpFunctionParameter, .{
1542 .id_result_type = param_type_id,1954 .id_result_type = param_type_id,
1543 .id_result = cg.module.allocId(),1955 .id_result = cg.allocId(),
1544 });1956 });
1545 }1957 }
1546 try stub.emit(gpa, .OpFunctionEnd, {});1958 try stub.emit(gpa, .OpFunctionEnd, {});
1547 try cg.module.sections.functions.append(gpa, stub);1959 try cg.sections.functions.append(gpa, stub);
15481960
1549 const extern_name = nav.getExtern(ip).?.name.toSlice(ip);1961 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, .{
1551 .target = decl.result_id,1963 .target = decl.result_id,
1552 .decoration = .{ .linkage_attributes = .{1964 .decoration = .{ .linkage_attributes = .{
1553 .name = extern_name,1965 .name = extern_name,
1554 .linkage_type = .import,1966 .linkage_type = .import,
1555 } },1967 } },
1556 });1968 });
1557 try cg.module.debugName(decl.result_id, extern_name);1969 try cg.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;
1613}1970}
16141971
1615// Turn a Zig type's name into a cache reference.
1616fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {1972fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1617 const gpa = cg.module.gpa;1973 const gpa = cg.gpa;
1618 var aw: std.Io.Writer.Allocating = .init(gpa);1974 var aw: std.Io.Writer.Allocating = .init(gpa);
1619 defer aw.deinit();1975 defer aw.deinit();
1620 ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) {1976 ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) {
...@@ -1641,67 +1997,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {...@@ -1641,67 +1997,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1641/// padding: [padding_size]u8,1997/// padding: [padding_size]u8,
1642/// }1998/// }
1643/// If any of the fields' size is 0, it will be omitted.1999/// 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
1703fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {2000fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1704 const zcu = cg.module.zcu;2001 const zcu = cg.zcu;
1705 if (!ret_ty.hasRuntimeBits(zcu)) {2002 if (!ret_ty.hasRuntimeBits(zcu)) {
1706 // If the return type is an error set or an error union, then we make this2003 // If the return type is an error set or an error union, then we make this
1707 // anyerror return type instead, so that it can be coerced into a function2004 // 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 {...@@ -1717,38 +2014,38 @@ fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1717}2014}
17182015
1719fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {2016fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1720 const gpa = cg.module.gpa;2017 const gpa = cg.gpa;
1721 const pt = cg.pt;2018 const pt = cg.pt;
1722 const zcu = cg.module.zcu;2019 const zcu = cg.zcu;
1723 const ip = &zcu.intern_pool;2020 const ip = &zcu.intern_pool;
1724 const target = cg.module.zcu.getTarget();2021 const target = cg.zcu.getTarget();
17252022
1726 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});2023 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});
17272024
1728 switch (ty.zigTypeTag(zcu)) {2025 switch (ty.zigTypeTag(zcu)) {
1729 .noreturn => {2026 .noreturn => {
1730 assert(repr == .direct);2027 assert(repr == .direct);
1731 return try cg.module.voidType();2028 return try cg.voidType();
1732 },2029 },
1733 .void => switch (repr) {2030 .void => switch (repr) {
1734 .direct => return try cg.module.voidType(),2031 .direct => return try cg.voidType(),
1735 .indirect => {2032 .indirect => {
1736 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2033 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");
1738 },2035 },
1739 },2036 },
1740 .bool => switch (repr) {2037 .bool => switch (repr) {
1741 .direct => return try cg.module.boolType(),2038 .direct => return try cg.boolType(),
1742 .indirect => return try cg.resolveType(.u1, .indirect),2039 .indirect => return try cg.resolveType(.u1, .indirect),
1743 },2040 },
1744 .int => {2041 .int => {
1745 if (ty.toIntern() == .u0_type) {2042 if (ty.toIntern() == .u0_type) {
1746 assert(repr == .indirect);2043 assert(repr == .indirect);
1747 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2044 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");
1749 }2046 }
1750 const int_info = ty.intInfo(zcu);2047 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);
1752 },2049 },
1753 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),2050 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
1754 .float => {2051 .float => {
...@@ -1767,7 +2064,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1767,7 +2064,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1767 );2064 );
1768 }2065 }
17692066
1770 return try cg.module.floatType(bits);2067 return try cg.floatType(bits);
1771 },2068 },
1772 .array => {2069 .array => {
1773 const elem_ty = ty.childType(zcu);2070 const elem_ty = ty.childType(zcu);
...@@ -1779,7 +2076,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1779,7 +2076,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1779 if (!elem_ty.hasRuntimeBits(zcu)) {2076 if (!elem_ty.hasRuntimeBits(zcu)) {
1780 assert(repr == .indirect);2077 assert(repr == .indirect);
1781 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2078 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");
1783 } else if (total_len == 0) {2080 } else if (total_len == 0) {
1784 // The size of the array would be 0, but that is not allowed in SPIR-V.2081 // The size of the array would be 0, but that is not allowed in SPIR-V.
1785 // This path can be reached for example when there is a slicing of a pointer2082 // 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 {...@@ -1790,25 +2087,24 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1790 // generate an array of 1 element instead, so that ptr_elem_ptr instructions2087 // generate an array of 1 element instead, so that ptr_elem_ptr instructions
1791 // can be lowered to ptrAccessChain instead of manually performing the math.2088 // can be lowered to ptrAccessChain instead of manually performing the math.
1792 const len_id = try cg.constInt(.u32, 1);2089 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);
1794 } else {2091 } else {
1795 const total_len_id = try cg.constInt(.u32, total_len);2092 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);
1797 }2094 }
1798 },2095 },
1799 .vector => {2096 .vector => {
1800 const elem_ty = ty.childType(zcu);2097 const elem_ty = ty.childType(zcu);
1801 const elem_ty_id = try cg.resolveType(elem_ty, repr);2098 const elem_ty_id = try cg.resolveType(elem_ty, repr);
1802 const len = ty.vectorLen(zcu);2099 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);
1804 const len_id = try cg.constInt(.u32, len);2101 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);
1806 },2103 },
1807 .@"fn" => switch (repr) {2104 .@"fn" => switch (repr) {
1808 .direct => {2105 .direct => {
1809 const fn_info = zcu.typeToFunc(ty).?;2106 const fn_info = zcu.typeToFunc(ty).?;
18102107
1811 comptime assert(zig_call_abi_ver == 3);
1812 assert(!fn_info.is_var_args);2108 assert(!fn_info.is_var_args);
1813 switch (fn_info.cc) {2109 switch (fn_info.cc) {
1814 .auto,2110 .auto,
...@@ -1837,7 +2133,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1837,7 +2133,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1837 param_index += 1;2133 param_index += 1;
1838 }2134 }
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]);
1841 },2137 },
1842 .indirect => {2138 .indirect => {
1843 // TODO: Represent function pointers properly.2139 // TODO: Represent function pointers properly.
...@@ -1860,15 +2156,15 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1860,15 +2156,15 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1860 },2156 },
1861 };2157 };
1862 const child_ty_id = try cg.resolveType(child_ty, .indirect);2158 const child_ty_id = try cg.resolveType(child_ty, .indirect);
1863 const storage_class = cg.module.storageClass(ptr_info.flags.address_space);2159 const storage_class = cg.storageClass(ptr_info.flags.address_space);
1864 const ptr_ty_id = try cg.module.ptrType(child_ty_id, storage_class);2160 const ptr_ty_id = try cg.ptrType(child_ty_id, storage_class);
18652161
1866 if (ptr_info.flags.size != .slice) {2162 if (ptr_info.flags.size != .slice) {
1867 return ptr_ty_id;2163 return ptr_ty_id;
1868 }2164 }
18692165
1870 const size_ty_id = try cg.resolveType(.usize, .direct);2166 const size_ty_id = try cg.resolveType(.usize, .direct);
1871 return try cg.module.structType(2167 return try cg.structType(
1872 &.{ ptr_ty_id, size_ty_id },2168 &.{ ptr_ty_id, size_ty_id },
1873 &.{ "ptr", "len" },2169 &.{ "ptr", "len" },
1874 .none,2170 .none,
...@@ -1889,14 +2185,14 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1889,14 +2185,14 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1889 member_index += 1;2185 member_index += 1;
1890 }2186 }
18912187
1892 const result_id = try cg.module.structType(2188 const result_id = try cg.structType(
1893 member_types[0..member_index],2189 member_types[0..member_index],
1894 null,2190 null,
1895 .none,2191 .none,
1896 );2192 );
1897 const type_name = try cg.resolveTypeName(ty);2193 const type_name = try cg.resolveTypeName(ty);
1898 defer gpa.free(type_name);2194 defer gpa.free(type_name);
1899 try cg.module.debugName(result_id, type_name);2195 try cg.debugName(result_id, type_name);
1900 return result_id;2196 return result_id;
1901 },2197 },
1902 .struct_type => ip.loadStructType(ty.toIntern()),2198 .struct_type => ip.loadStructType(ty.toIntern()),
...@@ -1923,7 +2219,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1923,7 +2219,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1923 try member_names.append(field_name.toSlice(ip));2219 try member_names.append(field_name.toSlice(ip));
1924 }2220 }
19252221
1926 const result_id = try cg.module.structType(2222 const result_id = try cg.structType(
1927 member_types.items,2223 member_types.items,
1928 member_names.items,2224 member_names.items,
1929 ty.toIntern(),2225 ty.toIntern(),
...@@ -1931,7 +2227,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1931,7 +2227,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19312227
1932 const type_name = try cg.resolveTypeName(ty);2228 const type_name = try cg.resolveTypeName(ty);
1933 defer gpa.free(type_name);2229 defer gpa.free(type_name);
1934 try cg.module.debugName(result_id, type_name);2230 try cg.debugName(result_id, type_name);
19352231
1936 return result_id;2232 return result_id;
1937 },2233 },
...@@ -1952,13 +2248,52 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1952,13 +2248,52 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19522248
1953 const bool_ty_id = try cg.resolveType(.bool, .indirect);2249 const bool_ty_id = try cg.resolveType(.bool, .indirect);
19542250
1955 return try cg.module.structType(2251 return try cg.structType(
1956 &.{ payload_ty_id, bool_ty_id },2252 &.{ payload_ty_id, bool_ty_id },
1957 &.{ "payload", "valid" },2253 &.{ "payload", "valid" },
1958 .none,2254 .none,
1959 );2255 );
1960 },2256 },
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 },
1962 .error_set => {2297 .error_set => {
1963 const err_int_ty = try pt.errorIntType();2298 const err_int_ty = try pt.errorIntType();
1964 return try cg.resolveType(err_int_ty, repr);2299 return try cg.resolveType(err_int_ty, repr);
...@@ -1989,46 +2324,46 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1989,46 +2324,46 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1989 // TODO: ABI padding?2324 // TODO: ABI padding?
1990 }2325 }
19912326
1992 return try cg.module.structType(&member_types, &member_names, .none);2327 return try cg.structType(&member_types, &member_names, .none);
1993 },2328 },
1994 .@"opaque" => {2329 .@"opaque" => {
1995 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2330 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1996 const type_name = try cg.resolveTypeName(ty);2331 const type_name = try cg.resolveTypeName(ty);
1997 defer gpa.free(type_name);2332 defer gpa.free(type_name);
1998 return try cg.module.opaqueType(type_name);2333 return try cg.opaqueType(type_name);
1999 },2334 },
2000 .spirv => {2335 .spirv => {
2001 const ip_index = ty.toIntern();2336 const spirv_type = ip.loadSpirvType(ty.toIntern());
2002 const spirv_type = ip.loadSpirvType(ip_index);2337 const result_id = cg.allocId();
2003 switch (spirv_type.flags.tag) {2338 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 }),
2005 .image => {2340 .image => {
2006 const sampled_type_id = blk: {2341 const sampled_type_id = if (spirv_type.ty == .none)
2007 if (spirv_type.ty == .none) break :blk try cg.module.intType(.unsigned, 32);2342 try cg.intType(.unsigned, 32)
2008 break :blk try cg.resolveType(Type.fromInterned(spirv_type.ty), .direct);2343 else
2009 };2344 try cg.resolveType(Type.fromInterned(spirv_type.ty), .direct);
2010 return try cg.module.imageType(2345 try cg.sections.globals.emit(gpa, .OpTypeImage, .{
2011 ip_index,2346 .id_result = result_id,
2012 sampled_type_id,2347 .sampled_type = sampled_type_id,
2013 switch (spirv_type.flags.dim) {2348 .dim = switch (spirv_type.flags.dim) {
2014 .@"1d" => .@"1d",2349 .@"1d" => .@"1d",
2015 .@"2d" => .@"2d",2350 .@"2d" => .@"2d",
2016 .@"3d" => .@"3d",2351 .@"3d" => .@"3d",
2017 .cube => .cube,2352 .cube => .cube,
2018 },2353 },
2019 switch (spirv_type.flags.depth) {2354 .depth = switch (spirv_type.flags.depth) {
2020 .not_depth => 0,2355 .not_depth => 0,
2021 .depth => 1,2356 .depth => 1,
2022 .unknown => 2,2357 .unknown => 2,
2023 },2358 },
2024 @intFromBool(spirv_type.flags.is_arrayed),2359 .arrayed = @intFromBool(spirv_type.flags.is_arrayed),
2025 @intFromBool(spirv_type.flags.is_multisampled),2360 .ms = @intFromBool(spirv_type.flags.is_multisampled),
2026 switch (spirv_type.flags.usage) {2361 .sampled = switch (spirv_type.flags.usage) {
2027 .unknown => 1,2362 .unknown => 1,
2028 .sampled => 1,2363 .sampled => 1,
2029 .storage => 2,2364 .storage => 2,
2030 },2365 },
2031 switch (spirv_type.flags.format) {2366 .image_format = switch (spirv_type.flags.format) {
2032 .unknown => .unknown,2367 .unknown => .unknown,
2033 .rgba32f => .rgba32f,2368 .rgba32f => .rgba32f,
2034 .rgba32i => .rgba32i,2369 .rgba32i => .rgba32i,
...@@ -2044,31 +2379,36 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -2044,31 +2379,36 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
2044 .r32i => .r32i,2379 .r32i => .r32i,
2045 .r32u => .r32ui,2380 .r32u => .r32ui,
2046 },2381 },
2047 switch (spirv_type.flags.access) {2382 .access_qualifier = switch (spirv_type.flags.access) {
2048 .unknown => null,2383 .unknown => null,
2049 .read_only => .read_only,2384 .read_only => .read_only,
2050 .write_only => .write_only,2385 .write_only => .write_only,
2051 .read_write => .read_write,2386 .read_write => .read_write,
2052 },2387 },
2053 );2388 });
2054 },2389 },
2055 .sampled_image => {2390 .sampled_image => {
2056 const image_ty_id = try cg.resolveType(.fromInterned(spirv_type.ty), .indirect);2391 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 });
2058 },2396 },
2059 .runtime_array => {2397 .runtime_array => {
2060 const elem_ty: Type = .fromInterned(spirv_type.ty);2398 const elem_ty: Type = .fromInterned(spirv_type.ty);
2061 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);2399 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
2062 const result_id = try cg.module.runtimeArrayType(ip_index, elem_ty_id);2400 try cg.sections.globals.emit(gpa, .OpTypeRuntimeArray, .{
20632401 .id_result = result_id,
2402 .element_type = elem_ty_id,
2403 });
2064 if (elem_ty.hasRuntimeBits(zcu)) {2404 if (elem_ty.hasRuntimeBits(zcu)) {
2065 try cg.module.decorate(result_id, .{ .array_stride = .{2405 try cg.decorate(result_id, .{ .array_stride = .{
2066 .array_stride = @intCast(elem_ty.abiSize(zcu)),2406 .array_stride = @intCast(elem_ty.abiSize(zcu)),
2067 } });2407 } });
2068 }2408 }
2069 return result_id;
2070 },2409 },
2071 }2410 }
2411 return result_id;
2072 },2412 },
20732413
2074 .null,2414 .null,
...@@ -2099,7 +2439,7 @@ const ErrorUnionLayout = struct {...@@ -2099,7 +2439,7 @@ const ErrorUnionLayout = struct {
2099};2439};
21002440
2101fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {2441fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {
2102 const zcu = cg.module.zcu;2442 const zcu = cg.zcu;
21032443
2104 const error_align = Type.abiAlignment(.anyerror, zcu);2444 const error_align = Type.abiAlignment(.anyerror, zcu);
2105 const payload_align = payload_ty.abiAlignment(zcu);2445 const payload_align = payload_ty.abiAlignment(zcu);
...@@ -2130,7 +2470,7 @@ const UnionLayout = struct {...@@ -2130,7 +2470,7 @@ const UnionLayout = struct {
2130};2470};
21312471
2132fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {2472fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {
2133 const zcu = cg.module.zcu;2473 const zcu = cg.zcu;
2134 const ip = &zcu.intern_pool;2474 const ip = &zcu.intern_pool;
2135 const layout = ty.unionGetLayout(zcu);2475 const layout = ty.unionGetLayout(zcu);
2136 const union_obj = zcu.typeToUnion(ty).?;2476 const union_obj = zcu.typeToUnion(ty).?;
...@@ -2220,8 +2560,8 @@ const Temporary = struct {...@@ -2220,8 +2560,8 @@ const Temporary = struct {
2220 }2560 }
22212561
2222 fn materialize(temp: Temporary, cg: *CodeGen) !Id {2562 fn materialize(temp: Temporary, cg: *CodeGen) !Id {
2223 const gpa = cg.module.gpa;2563 const gpa = cg.gpa;
2224 const zcu = cg.module.zcu;2564 const zcu = cg.zcu;
2225 switch (temp.value) {2565 switch (temp.value) {
2226 .singleton => |id| return id,2566 .singleton => |id| return id,
2227 .exploded_vector => |range| {2567 .exploded_vector => |range| {
...@@ -2255,7 +2595,7 @@ const Temporary = struct {...@@ -2255,7 +2595,7 @@ const Temporary = struct {
2255 /// 'Explode' a temporary into separate elements. This turns a vector2595 /// 'Explode' a temporary into separate elements. This turns a vector
2256 /// into a bag of elements.2596 /// into a bag of elements.
2257 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {2597 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {
2258 const zcu = cg.module.zcu;2598 const zcu = cg.zcu;
22592599
2260 // If the value is a scalar, then this is a no-op.2600 // If the value is a scalar, then this is a no-op.
2261 if (!temp.ty.isVector(zcu)) {2601 if (!temp.ty.isVector(zcu)) {
...@@ -2267,7 +2607,7 @@ const Temporary = struct {...@@ -2267,7 +2607,7 @@ const Temporary = struct {
22672607
2268 const ty_id = try cg.resolveType(temp.ty.scalarType(zcu), .direct);2608 const ty_id = try cg.resolveType(temp.ty.scalarType(zcu), .direct);
2269 const n = temp.ty.vectorLen(zcu);2609 const n = temp.ty.vectorLen(zcu);
2270 const results = cg.module.allocIds(n);2610 const results = cg.allocIds(n);
22712611
2272 const id = switch (temp.value) {2612 const id = switch (temp.value) {
2273 .singleton => |id| id,2613 .singleton => |id| id,
...@@ -2276,7 +2616,7 @@ const Temporary = struct {...@@ -2276,7 +2616,7 @@ const Temporary = struct {
22762616
2277 for (0..n) |i| {2617 for (0..n) |i| {
2278 const indexes = [_]u32{@intCast(i)};2618 const indexes = [_]u32{@intCast(i)};
2279 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{2619 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
2280 .id_result_type = ty_id,2620 .id_result_type = ty_id,
2281 .id_result = results.at(i),2621 .id_result = results.at(i),
2282 .composite = id,2622 .composite = id,
...@@ -2296,12 +2636,12 @@ const CompositeInt = struct {...@@ -2296,12 +2636,12 @@ const CompositeInt = struct {
2296 info: ArithmeticTypeInfo,2636 info: ArithmeticTypeInfo,
22972637
2298 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {2638 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {
2299 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;2639 const n_limbs: u16 = info.backing_bits / big_int_bits;
2300 const gpa = cg.module.gpa;2640 const gpa = cg.gpa;
2301 const u32_ty_id = try cg.resolveType(.u32, .direct);2641 const u32_ty_id = try cg.resolveType(.u32, .direct);
2302 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);2642 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
2303 for (limbs, 0..) |*limb, i| {2643 for (limbs, 0..) |*limb, i| {
2304 const result_id = cg.module.allocId();2644 const result_id = cg.allocId();
2305 try cg.body.emit(gpa, .OpCompositeExtract, .{2645 try cg.body.emit(gpa, .OpCompositeExtract, .{
2306 .id_result_type = u32_ty_id,2646 .id_result_type = u32_ty_id,
2307 .id_result = result_id,2647 .id_result = result_id,
...@@ -2323,8 +2663,8 @@ const CompositeInt = struct {...@@ -2323,8 +2663,8 @@ const CompositeInt = struct {
2323 }2663 }
23242664
2325 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {2665 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {
2326 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;2666 const n_limbs: u16 = info.backing_bits / big_int_bits;
2327 const limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, n_limbs);2667 const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs);
2328 const zero_id = try cg.constInt(.u32, @as(u32, 0));2668 const zero_id = try cg.constInt(.u32, @as(u32, 0));
2329 for (limbs) |*limb| limb.* = zero_id;2669 for (limbs) |*limb| limb.* = zero_id;
2330 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };2670 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
...@@ -2337,9 +2677,9 @@ const CompositeInt = struct {...@@ -2337,9 +2677,9 @@ const CompositeInt = struct {
23372677
2338 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {2678 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {
2339 const cg = ci.cg;2679 const cg = ci.cg;
2340 const gpa = cg.module.gpa;2680 const gpa = cg.gpa;
2341 const u32_ty_id = try cg.resolveType(.u32, .direct);2681 const u32_ty_id = try cg.resolveType(.u32, .direct);
2342 const result_id = cg.module.allocId();2682 const result_id = cg.allocId();
2343 try cg.body.emitRaw(gpa, opcode, 4);2683 try cg.body.emitRaw(gpa, opcode, 4);
2344 cg.body.writeOperand(Id, u32_ty_id);2684 cg.body.writeOperand(Id, u32_ty_id);
2345 cg.body.writeOperand(Id, result_id);2685 cg.body.writeOperand(Id, result_id);
...@@ -2350,9 +2690,9 @@ const CompositeInt = struct {...@@ -2350,9 +2690,9 @@ const CompositeInt = struct {
23502690
2351 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {2691 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {
2352 const cg = ci.cg;2692 const cg = ci.cg;
2353 const gpa = cg.module.gpa;2693 const gpa = cg.gpa;
2354 const u32_ty_id = try cg.resolveType(.u32, .direct);2694 const u32_ty_id = try cg.resolveType(.u32, .direct);
2355 const result_id = cg.module.allocId();2695 const result_id = cg.allocId();
2356 try cg.body.emitRaw(gpa, opcode, 3);2696 try cg.body.emitRaw(gpa, opcode, 3);
2357 cg.body.writeOperand(Id, u32_ty_id);2697 cg.body.writeOperand(Id, u32_ty_id);
2358 cg.body.writeOperand(Id, result_id);2698 cg.body.writeOperand(Id, result_id);
...@@ -2362,7 +2702,7 @@ const CompositeInt = struct {...@@ -2362,7 +2702,7 @@ const CompositeInt = struct {
23622702
2363 fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt {2703 fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt {
2364 const cg = ci.cg;2704 const cg = ci.cg;
2365 const gpa = cg.module.gpa;2705 const gpa = cg.gpa;
2366 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);2706 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2367 for (result_limbs, 0..) |*r, i| {2707 for (result_limbs, 0..) |*r, i| {
2368 r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]);2708 r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]);
...@@ -2372,7 +2712,7 @@ const CompositeInt = struct {...@@ -2372,7 +2712,7 @@ const CompositeInt = struct {
23722712
2373 fn bitwiseNot(ci: CompositeInt) !CompositeInt {2713 fn bitwiseNot(ci: CompositeInt) !CompositeInt {
2374 const cg = ci.cg;2714 const cg = ci.cg;
2375 const gpa = cg.module.gpa;2715 const gpa = cg.gpa;
2376 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);2716 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2377 for (result_limbs, 0..) |*r, i| {2717 for (result_limbs, 0..) |*r, i| {
2378 r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]);2718 r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]);
...@@ -2382,41 +2722,45 @@ const CompositeInt = struct {...@@ -2382,41 +2722,45 @@ const CompositeInt = struct {
23822722
2383 fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id {2723 fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id {
2384 const cg = ci.cg;2724 const cg = ci.cg;
2385 const gpa = cg.module.gpa;2725 const gpa = cg.gpa;
2386 const bool_ty_id = try cg.resolveType(.bool, .direct);2726 const bool_ty_id = try cg.resolveType(.bool, .direct);
23872727
2388 switch (op) {2728 switch (op) {
2389 .eq, .neq => {2729 .eq, .neq => {
2390 var result = blk: {2730 var result = blk: {
2391 const r = cg.module.allocId();2731 const r = cg.allocId();
2392 try cg.body.emitRaw(gpa, .OpIEqual, 4);2732 try cg.body.emit(gpa, .OpIEqual, .{
2393 cg.body.writeOperand(Id, bool_ty_id);2733 .id_result_type = bool_ty_id,
2394 cg.body.writeOperand(Id, r);2734 .id_result = r,
2395 cg.body.writeOperand(Id, ci.limbs[0]);2735 .operand_1 = ci.limbs[0],
2396 cg.body.writeOperand(Id, other.limbs[0]);2736 .operand_2 = other.limbs[0],
2737 });
2397 break :blk r;2738 break :blk r;
2398 };2739 };
2399 for (1..ci.n_limbs) |i| {2740 for (1..ci.n_limbs) |i| {
2400 const limb_eq = cg.module.allocId();2741 const limb_eq = cg.allocId();
2401 try cg.body.emitRaw(gpa, .OpIEqual, 4);2742 try cg.body.emit(gpa, .OpIEqual, .{
2402 cg.body.writeOperand(Id, bool_ty_id);2743 .id_result_type = bool_ty_id,
2403 cg.body.writeOperand(Id, limb_eq);2744 .id_result = limb_eq,
2404 cg.body.writeOperand(Id, ci.limbs[i]);2745 .operand_1 = ci.limbs[i],
2405 cg.body.writeOperand(Id, other.limbs[i]);2746 .operand_2 = other.limbs[i],
2406 const combined = cg.module.allocId();2747 });
2407 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);2748 const combined = cg.allocId();
2408 cg.body.writeOperand(Id, bool_ty_id);2749 try cg.body.emit(gpa, .OpLogicalAnd, .{
2409 cg.body.writeOperand(Id, combined);2750 .id_result_type = bool_ty_id,
2410 cg.body.writeOperand(Id, result);2751 .id_result = combined,
2411 cg.body.writeOperand(Id, limb_eq);2752 .operand_1 = result,
2753 .operand_2 = limb_eq,
2754 });
2412 result = combined;2755 result = combined;
2413 }2756 }
2414 if (op == .neq) {2757 if (op == .neq) {
2415 const negated = cg.module.allocId();2758 const negated = cg.allocId();
2416 try cg.body.emitRaw(gpa, .OpLogicalNot, 3);2759 try cg.body.emit(gpa, .OpLogicalNot, .{
2417 cg.body.writeOperand(Id, bool_ty_id);2760 .id_result_type = bool_ty_id,
2418 cg.body.writeOperand(Id, negated);2761 .id_result = negated,
2419 cg.body.writeOperand(Id, result);2762 .operand = result,
2763 });
2420 result = negated;2764 result = negated;
2421 }2765 }
2422 return result;2766 return result;
...@@ -2429,12 +2773,13 @@ const CompositeInt = struct {...@@ -2429,12 +2773,13 @@ const CompositeInt = struct {
2429 for (0..ci.n_limbs) |i| {2773 for (0..ci.n_limbs) |i| {
2430 const l = ci.limbs[i];2774 const l = ci.limbs[i];
2431 const r = other.limbs[i];2775 const r = other.limbs[i];
2432 const limb_ne = cg.module.allocId();2776 const limb_ne = cg.allocId();
2433 try cg.body.emitRaw(gpa, .OpINotEqual, 4);2777 try cg.body.emit(gpa, .OpINotEqual, .{
2434 cg.body.writeOperand(Id, bool_ty_id);2778 .id_result_type = bool_ty_id,
2435 cg.body.writeOperand(Id, limb_ne);2779 .id_result = limb_ne,
2436 cg.body.writeOperand(Id, l);2780 .operand_1 = l,
2437 cg.body.writeOperand(Id, r);2781 .operand_2 = r,
2782 });
24382783
2439 const is_top = (i == ci.n_limbs - 1);2784 const is_top = (i == ci.n_limbs - 1);
2440 const use_signed = is_top and ci.info.signedness == .signed;2785 const use_signed = is_top and ci.info.signedness == .signed;
...@@ -2442,13 +2787,13 @@ const CompositeInt = struct {...@@ -2442,13 +2787,13 @@ const CompositeInt = struct {
2442 var cmp_r = r;2787 var cmp_r = r;
2443 if (use_signed) {2788 if (use_signed) {
2444 const i32_ty_id = try cg.resolveType(.i32, .direct);2789 const i32_ty_id = try cg.resolveType(.i32, .direct);
2445 const sl = cg.module.allocId();2790 const sl = cg.allocId();
2446 try cg.body.emit(gpa, .OpBitcast, .{2791 try cg.body.emit(gpa, .OpBitcast, .{
2447 .id_result_type = i32_ty_id,2792 .id_result_type = i32_ty_id,
2448 .id_result = sl,2793 .id_result = sl,
2449 .operand = l,2794 .operand = l,
2450 });2795 });
2451 const sr = cg.module.allocId();2796 const sr = cg.allocId();
2452 try cg.body.emit(gpa, .OpBitcast, .{2797 try cg.body.emit(gpa, .OpBitcast, .{
2453 .id_result_type = i32_ty_id,2798 .id_result_type = i32_ty_id,
2454 .id_result = sr,2799 .id_result = sr,
...@@ -2463,14 +2808,14 @@ const CompositeInt = struct {...@@ -2463,14 +2808,14 @@ const CompositeInt = struct {
2463 else2808 else
2464 (if (use_signed) .OpSGreaterThan else .OpUGreaterThan);2809 (if (use_signed) .OpSGreaterThan else .OpUGreaterThan);
24652810
2466 const limb_cmp = cg.module.allocId();2811 const limb_cmp = cg.allocId();
2467 try cg.body.emitRaw(gpa, cmp_opcode, 4);2812 try cg.body.emitRaw(gpa, cmp_opcode, 4);
2468 cg.body.writeOperand(Id, bool_ty_id);2813 cg.body.writeOperand(Id, bool_ty_id);
2469 cg.body.writeOperand(Id, limb_cmp);2814 cg.body.writeOperand(Id, limb_cmp);
2470 cg.body.writeOperand(Id, cmp_l);2815 cg.body.writeOperand(Id, cmp_l);
2471 cg.body.writeOperand(Id, cmp_r);2816 cg.body.writeOperand(Id, cmp_r);
24722817
2473 const selected = cg.module.allocId();2818 const selected = cg.allocId();
2474 try cg.body.emit(gpa, .OpSelect, .{2819 try cg.body.emit(gpa, .OpSelect, .{
2475 .id_result_type = bool_ty_id,2820 .id_result_type = bool_ty_id,
2476 .id_result = selected,2821 .id_result = selected,
...@@ -2487,9 +2832,9 @@ const CompositeInt = struct {...@@ -2487,9 +2832,9 @@ const CompositeInt = struct {
24872832
2488 fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt {2833 fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt {
2489 const cg = ci.cg;2834 const cg = ci.cg;
2490 const gpa = cg.module.gpa;2835 const gpa = cg.gpa;
2491 const pt = cg.pt;2836 const pt = cg.pt;
2492 const zcu = cg.module.zcu;2837 const zcu = cg.zcu;
2493 const ip = &zcu.intern_pool;2838 const ip = &zcu.intern_pool;
2494 const comp = zcu.comp;2839 const comp = zcu.comp;
2495 const io = comp.io;2840 const io = comp.io;
...@@ -2508,21 +2853,21 @@ const CompositeInt = struct {...@@ -2508,21 +2853,21 @@ const CompositeInt = struct {
2508 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;2853 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;
25092854
2510 for (0..ci.n_limbs) |i| {2855 for (0..ci.n_limbs) |i| {
2511 const op1 = cg.module.allocId();2856 const op1 = cg.allocId();
2512 try cg.body.emitRaw(gpa, opcode, 4);2857 try cg.body.emitRaw(gpa, opcode, 4);
2513 cg.body.writeOperand(Id, carry_struct_ty_id);2858 cg.body.writeOperand(Id, carry_struct_ty_id);
2514 cg.body.writeOperand(Id, op1);2859 cg.body.writeOperand(Id, op1);
2515 cg.body.writeOperand(Id, ci.limbs[i]);2860 cg.body.writeOperand(Id, ci.limbs[i]);
2516 cg.body.writeOperand(Id, other.limbs[i]);2861 cg.body.writeOperand(Id, other.limbs[i]);
25172862
2518 const sum1 = cg.module.allocId();2863 const sum1 = cg.allocId();
2519 try cg.body.emit(gpa, .OpCompositeExtract, .{2864 try cg.body.emit(gpa, .OpCompositeExtract, .{
2520 .id_result_type = u32_ty_id,2865 .id_result_type = u32_ty_id,
2521 .id_result = sum1,2866 .id_result = sum1,
2522 .composite = op1,2867 .composite = op1,
2523 .indexes = &.{0},2868 .indexes = &.{0},
2524 });2869 });
2525 const carry1 = cg.module.allocId();2870 const carry1 = cg.allocId();
2526 try cg.body.emit(gpa, .OpCompositeExtract, .{2871 try cg.body.emit(gpa, .OpCompositeExtract, .{
2527 .id_result_type = u32_ty_id,2872 .id_result_type = u32_ty_id,
2528 .id_result = carry1,2873 .id_result = carry1,
...@@ -2530,21 +2875,21 @@ const CompositeInt = struct {...@@ -2530,21 +2875,21 @@ const CompositeInt = struct {
2530 .indexes = &.{1},2875 .indexes = &.{1},
2531 });2876 });
25322877
2533 const op2 = cg.module.allocId();2878 const op2 = cg.allocId();
2534 try cg.body.emitRaw(gpa, opcode, 4);2879 try cg.body.emitRaw(gpa, opcode, 4);
2535 cg.body.writeOperand(Id, carry_struct_ty_id);2880 cg.body.writeOperand(Id, carry_struct_ty_id);
2536 cg.body.writeOperand(Id, op2);2881 cg.body.writeOperand(Id, op2);
2537 cg.body.writeOperand(Id, sum1);2882 cg.body.writeOperand(Id, sum1);
2538 cg.body.writeOperand(Id, carry_id);2883 cg.body.writeOperand(Id, carry_id);
25392884
2540 result_limbs[i] = cg.module.allocId();2885 result_limbs[i] = cg.allocId();
2541 try cg.body.emit(gpa, .OpCompositeExtract, .{2886 try cg.body.emit(gpa, .OpCompositeExtract, .{
2542 .id_result_type = u32_ty_id,2887 .id_result_type = u32_ty_id,
2543 .id_result = result_limbs[i],2888 .id_result = result_limbs[i],
2544 .composite = op2,2889 .composite = op2,
2545 .indexes = &.{0},2890 .indexes = &.{0},
2546 });2891 });
2547 const carry2 = cg.module.allocId();2892 const carry2 = cg.allocId();
2548 try cg.body.emit(gpa, .OpCompositeExtract, .{2893 try cg.body.emit(gpa, .OpCompositeExtract, .{
2549 .id_result_type = u32_ty_id,2894 .id_result_type = u32_ty_id,
2550 .id_result = carry2,2895 .id_result = carry2,
...@@ -2560,7 +2905,7 @@ const CompositeInt = struct {...@@ -2560,7 +2905,7 @@ const CompositeInt = struct {
25602905
2561 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {2906 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {
2562 const cg = ci.cg;2907 const cg = ci.cg;
2563 const gpa = cg.module.gpa;2908 const gpa = cg.gpa;
2564 const u32_ty_id = try cg.resolveType(.u32, .direct);2909 const u32_ty_id = try cg.resolveType(.u32, .direct);
2565 const bool_ty_id = try cg.resolveType(.bool, .direct);2910 const bool_ty_id = try cg.resolveType(.bool, .direct);
2566 const zero_id = try cg.constInt(.u32, @as(u32, 0));2911 const zero_id = try cg.constInt(.u32, @as(u32, 0));
...@@ -2572,12 +2917,13 @@ const CompositeInt = struct {...@@ -2572,12 +2917,13 @@ const CompositeInt = struct {
2572 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);2917 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
2573 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);2918 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
2574 const frac_is_zero = blk: {2919 const frac_is_zero = blk: {
2575 const r = cg.module.allocId();2920 const r = cg.allocId();
2576 try cg.body.emitRaw(gpa, .OpIEqual, 4);2921 try cg.body.emit(gpa, .OpIEqual, .{
2577 cg.body.writeOperand(Id, bool_ty_id);2922 .id_result_type = bool_ty_id,
2578 cg.body.writeOperand(Id, r);2923 .id_result = r,
2579 cg.body.writeOperand(Id, frac);2924 .operand_1 = frac,
2580 cg.body.writeOperand(Id, zero_id);2925 .operand_2 = zero_id,
2926 });
2581 break :blk r;2927 break :blk r;
2582 };2928 };
25832929
...@@ -2593,17 +2939,18 @@ const CompositeInt = struct {...@@ -2593,17 +2939,18 @@ const CompositeInt = struct {
2593 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);2939 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);
25942940
2595 const is_main = blk: {2941 const is_main = blk: {
2596 const r = cg.module.allocId();2942 const r = cg.allocId();
2597 try cg.body.emitRaw(gpa, .OpIEqual, 4);2943 try cg.body.emit(gpa, .OpIEqual, .{
2598 cg.body.writeOperand(Id, bool_ty_id);2944 .id_result_type = bool_ty_id,
2599 cg.body.writeOperand(Id, r);2945 .id_result = r,
2600 cg.body.writeOperand(Id, j_plus_whole);2946 .operand_1 = j_plus_whole,
2601 cg.body.writeOperand(Id, i_id);2947 .operand_2 = i_id,
2948 });
2602 break :blk r;2949 break :blk r;
2603 };2950 };
2604 const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac);2951 const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac);
2605 main_val = blk: {2952 main_val = blk: {
2606 const r = cg.module.allocId();2953 const r = cg.allocId();
2607 try cg.body.emit(gpa, .OpSelect, .{2954 try cg.body.emit(gpa, .OpSelect, .{
2608 .id_result_type = u32_ty_id,2955 .id_result_type = u32_ty_id,
2609 .id_result = r,2956 .id_result = r,
...@@ -2617,17 +2964,18 @@ const CompositeInt = struct {...@@ -2617,17 +2964,18 @@ const CompositeInt = struct {
2617 const one_id = try cg.constInt(.u32, @as(u32, 1));2964 const one_id = try cg.constInt(.u32, @as(u32, 1));
2618 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);2965 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);
2619 const is_carry = blk: {2966 const is_carry = blk: {
2620 const r = cg.module.allocId();2967 const r = cg.allocId();
2621 try cg.body.emitRaw(gpa, .OpIEqual, 4);2968 try cg.body.emit(gpa, .OpIEqual, .{
2622 cg.body.writeOperand(Id, bool_ty_id);2969 .id_result_type = bool_ty_id,
2623 cg.body.writeOperand(Id, r);2970 .id_result = r,
2624 cg.body.writeOperand(Id, j_plus_whole_plus_1);2971 .operand_1 = j_plus_whole_plus_1,
2625 cg.body.writeOperand(Id, i_id);2972 .operand_2 = i_id,
2973 });
2626 break :blk r;2974 break :blk r;
2627 };2975 };
2628 const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac);2976 const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac);
2629 const guarded_carry = blk: {2977 const guarded_carry = blk: {
2630 const r = cg.module.allocId();2978 const r = cg.allocId();
2631 try cg.body.emit(gpa, .OpSelect, .{2979 try cg.body.emit(gpa, .OpSelect, .{
2632 .id_result_type = u32_ty_id,2980 .id_result_type = u32_ty_id,
2633 .id_result = r,2981 .id_result = r,
...@@ -2638,7 +2986,7 @@ const CompositeInt = struct {...@@ -2638,7 +2986,7 @@ const CompositeInt = struct {
2638 break :blk r;2986 break :blk r;
2639 };2987 };
2640 carry_val = blk: {2988 carry_val = blk: {
2641 const r = cg.module.allocId();2989 const r = cg.allocId();
2642 try cg.body.emit(gpa, .OpSelect, .{2990 try cg.body.emit(gpa, .OpSelect, .{
2643 .id_result_type = u32_ty_id,2991 .id_result_type = u32_ty_id,
2644 .id_result = r,2992 .id_result = r,
...@@ -2658,7 +3006,7 @@ const CompositeInt = struct {...@@ -2658,7 +3006,7 @@ const CompositeInt = struct {
26583006
2659 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {3007 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {
2660 const cg = ci.cg;3008 const cg = ci.cg;
2661 const gpa = cg.module.gpa;3009 const gpa = cg.gpa;
2662 const u32_ty_id = try cg.resolveType(.u32, .direct);3010 const u32_ty_id = try cg.resolveType(.u32, .direct);
2663 const bool_ty_id = try cg.resolveType(.bool, .direct);3011 const bool_ty_id = try cg.resolveType(.bool, .direct);
2664 const zero_id = try cg.constInt(.u32, @as(u32, 0));3012 const zero_id = try cg.constInt(.u32, @as(u32, 0));
...@@ -2670,31 +3018,33 @@ const CompositeInt = struct {...@@ -2670,31 +3018,33 @@ const CompositeInt = struct {
2670 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);3018 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
2671 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);3019 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
2672 const frac_is_zero = blk: {3020 const frac_is_zero = blk: {
2673 const r = cg.module.allocId();3021 const r = cg.allocId();
2674 try cg.body.emitRaw(gpa, .OpIEqual, 4);3022 try cg.body.emit(gpa, .OpIEqual, .{
2675 cg.body.writeOperand(Id, bool_ty_id);3023 .id_result_type = bool_ty_id,
2676 cg.body.writeOperand(Id, r);3024 .id_result = r,
2677 cg.body.writeOperand(Id, frac);3025 .operand_1 = frac,
2678 cg.body.writeOperand(Id, zero_id);3026 .operand_2 = zero_id,
3027 });
2679 break :blk r;3028 break :blk r;
2680 };3029 };
26813030
2682 const fill_id = if (is_arithmetic) blk: {3031 const fill_id = if (is_arithmetic) blk: {
2683 const i32_ty_id = try cg.resolveType(.i32, .direct);3032 const i32_ty_id = try cg.resolveType(.i32, .direct);
2684 const msb_signed = cg.module.allocId();3033 const msb_signed = cg.allocId();
2685 try cg.body.emit(gpa, .OpBitcast, .{3034 try cg.body.emit(gpa, .OpBitcast, .{
2686 .id_result_type = i32_ty_id,3035 .id_result_type = i32_ty_id,
2687 .id_result = msb_signed,3036 .id_result = msb_signed,
2688 .operand = ci.limbs[ci.n_limbs - 1],3037 .operand = ci.limbs[ci.n_limbs - 1],
2689 });3038 });
2690 const shift31 = try cg.constInt(.i32, @as(i32, 31));3039 const shift31 = try cg.constInt(.i32, @as(i32, 31));
2691 const sign_ext = cg.module.allocId();3040 const sign_ext = cg.allocId();
2692 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);3041 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
2693 cg.body.writeOperand(Id, i32_ty_id);3042 .id_result_type = i32_ty_id,
2694 cg.body.writeOperand(Id, sign_ext);3043 .id_result = sign_ext,
2695 cg.body.writeOperand(Id, msb_signed);3044 .base = msb_signed,
2696 cg.body.writeOperand(Id, shift31);3045 .shift = shift31,
2697 const back = cg.module.allocId();3046 });
3047 const back = cg.allocId();
2698 try cg.body.emit(gpa, .OpBitcast, .{3048 try cg.body.emit(gpa, .OpBitcast, .{
2699 .id_result_type = u32_ty_id,3049 .id_result_type = u32_ty_id,
2700 .id_result = back,3050 .id_result = back,
...@@ -2707,7 +3057,7 @@ const CompositeInt = struct {...@@ -2707,7 +3057,7 @@ const CompositeInt = struct {
27073057
2708 const arith_carry_init = if (is_arithmetic) blk: {3058 const arith_carry_init = if (is_arithmetic) blk: {
2709 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);3059 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);
2710 const guarded = cg.module.allocId();3060 const guarded = cg.allocId();
2711 try cg.body.emit(gpa, .OpSelect, .{3061 try cg.body.emit(gpa, .OpSelect, .{
2712 .id_result_type = u32_ty_id,3062 .id_result_type = u32_ty_id,
2713 .id_result = guarded,3063 .id_result = guarded,
...@@ -2727,17 +3077,18 @@ const CompositeInt = struct {...@@ -2727,17 +3077,18 @@ const CompositeInt = struct {
2727 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));3077 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));
2728 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);3078 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);
2729 const is_main = blk: {3079 const is_main = blk: {
2730 const r = cg.module.allocId();3080 const r = cg.allocId();
2731 try cg.body.emitRaw(gpa, .OpIEqual, 4);3081 try cg.body.emit(gpa, .OpIEqual, .{
2732 cg.body.writeOperand(Id, bool_ty_id);3082 .id_result_type = bool_ty_id,
2733 cg.body.writeOperand(Id, r);3083 .id_result = r,
2734 cg.body.writeOperand(Id, j_id);3084 .operand_1 = j_id,
2735 cg.body.writeOperand(Id, i_plus_whole);3085 .operand_2 = i_plus_whole,
3086 });
2736 break :blk r;3087 break :blk r;
2737 };3088 };
2738 const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac);3089 const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac);
2739 main_val = blk: {3090 main_val = blk: {
2740 const r = cg.module.allocId();3091 const r = cg.allocId();
2741 try cg.body.emit(gpa, .OpSelect, .{3092 try cg.body.emit(gpa, .OpSelect, .{
2742 .id_result_type = u32_ty_id,3093 .id_result_type = u32_ty_id,
2743 .id_result = r,3094 .id_result = r,
...@@ -2751,17 +3102,18 @@ const CompositeInt = struct {...@@ -2751,17 +3102,18 @@ const CompositeInt = struct {
2751 const one_id = try cg.constInt(.u32, @as(u32, 1));3102 const one_id = try cg.constInt(.u32, @as(u32, 1));
2752 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);3103 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);
2753 const is_carry = blk: {3104 const is_carry = blk: {
2754 const r = cg.module.allocId();3105 const r = cg.allocId();
2755 try cg.body.emitRaw(gpa, .OpIEqual, 4);3106 try cg.body.emit(gpa, .OpIEqual, .{
2756 cg.body.writeOperand(Id, bool_ty_id);3107 .id_result_type = bool_ty_id,
2757 cg.body.writeOperand(Id, r);3108 .id_result = r,
2758 cg.body.writeOperand(Id, j_id);3109 .operand_1 = j_id,
2759 cg.body.writeOperand(Id, i_plus_whole_plus_1);3110 .operand_2 = i_plus_whole_plus_1,
3111 });
2760 break :blk r;3112 break :blk r;
2761 };3113 };
2762 const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac);3114 const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac);
2763 const guarded_carry = blk: {3115 const guarded_carry = blk: {
2764 const r = cg.module.allocId();3116 const r = cg.allocId();
2765 try cg.body.emit(gpa, .OpSelect, .{3117 try cg.body.emit(gpa, .OpSelect, .{
2766 .id_result_type = u32_ty_id,3118 .id_result_type = u32_ty_id,
2767 .id_result = r,3119 .id_result = r,
...@@ -2772,7 +3124,7 @@ const CompositeInt = struct {...@@ -2772,7 +3124,7 @@ const CompositeInt = struct {
2772 break :blk r;3124 break :blk r;
2773 };3125 };
2774 carry_val = blk: {3126 carry_val = blk: {
2775 const r = cg.module.allocId();3127 const r = cg.allocId();
2776 try cg.body.emit(gpa, .OpSelect, .{3128 try cg.body.emit(gpa, .OpSelect, .{
2777 .id_result_type = u32_ty_id,3129 .id_result_type = u32_ty_id,
2778 .id_result = r,3130 .id_result = r,
...@@ -2792,9 +3144,9 @@ const CompositeInt = struct {...@@ -2792,9 +3144,9 @@ const CompositeInt = struct {
27923144
2793 fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id {3145 fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id {
2794 const cg = ci.cg;3146 const cg = ci.cg;
2795 const gpa = cg.module.gpa;3147 const gpa = cg.gpa;
2796 const pt = cg.pt;3148 const pt = cg.pt;
2797 const zcu = cg.module.zcu;3149 const zcu = cg.zcu;
2798 const ip = &zcu.intern_pool;3150 const ip = &zcu.intern_pool;
2799 const comp = zcu.comp;3151 const comp = zcu.comp;
2800 const io = comp.io;3152 const io = comp.io;
...@@ -2825,15 +3177,16 @@ const CompositeInt = struct {...@@ -2825,15 +3177,16 @@ const CompositeInt = struct {
2825 var hi: Id = undefined;3177 var hi: Id = undefined;
2826 switch (target.os.tag) {3178 switch (target.os.tag) {
2827 .opencl => {3179 .opencl => {
2828 lo = cg.module.allocId();3180 lo = cg.allocId();
2829 try cg.body.emitRaw(gpa, .OpIMul, 4);3181 try cg.body.emit(gpa, .OpIMul, .{
2830 cg.body.writeOperand(Id, u32_ty_id);3182 .id_result_type = u32_ty_id,
2831 cg.body.writeOperand(Id, lo);3183 .id_result = lo,
2832 cg.body.writeOperand(Id, ci.limbs[i]);3184 .operand_1 = ci.limbs[i],
2833 cg.body.writeOperand(Id, other.limbs[j]);3185 .operand_2 = other.limbs[j],
3186 });
28343187
2835 const set = try cg.importExtendedSet();3188 const set = try cg.importExtendedSet();
2836 hi = cg.module.allocId();3189 hi = cg.allocId();
2837 try cg.body.emit(gpa, .OpExtInst, .{3190 try cg.body.emit(gpa, .OpExtInst, .{
2838 .id_result_type = u32_ty_id,3191 .id_result_type = u32_ty_id,
2839 .id_result = hi,3192 .id_result = hi,
...@@ -2843,21 +3196,22 @@ const CompositeInt = struct {...@@ -2843,21 +3196,22 @@ const CompositeInt = struct {
2843 });3196 });
2844 },3197 },
2845 else => {3198 else => {
2846 const mul_result = cg.module.allocId();3199 const mul_result = cg.allocId();
2847 try cg.body.emitRaw(gpa, .OpUMulExtended, 4);3200 try cg.body.emit(gpa, .OpUMulExtended, .{
2848 cg.body.writeOperand(Id, pair_struct_ty_id);3201 .id_result_type = pair_struct_ty_id,
2849 cg.body.writeOperand(Id, mul_result);3202 .id_result = mul_result,
2850 cg.body.writeOperand(Id, ci.limbs[i]);3203 .operand_1 = ci.limbs[i],
2851 cg.body.writeOperand(Id, other.limbs[j]);3204 .operand_2 = other.limbs[j],
28523205 });
2853 lo = cg.module.allocId();3206
3207 lo = cg.allocId();
2854 try cg.body.emit(gpa, .OpCompositeExtract, .{3208 try cg.body.emit(gpa, .OpCompositeExtract, .{
2855 .id_result_type = u32_ty_id,3209 .id_result_type = u32_ty_id,
2856 .id_result = lo,3210 .id_result = lo,
2857 .composite = mul_result,3211 .composite = mul_result,
2858 .indexes = &.{0},3212 .indexes = &.{0},
2859 });3213 });
2860 hi = cg.module.allocId();3214 hi = cg.allocId();
2861 try cg.body.emit(gpa, .OpCompositeExtract, .{3215 try cg.body.emit(gpa, .OpCompositeExtract, .{
2862 .id_result_type = u32_ty_id,3216 .id_result_type = u32_ty_id,
2863 .id_result = hi,3217 .id_result = hi,
...@@ -2867,21 +3221,22 @@ const CompositeInt = struct {...@@ -2867,21 +3221,22 @@ const CompositeInt = struct {
2867 },3221 },
2868 }3222 }
28693223
2870 const add1 = cg.module.allocId();3224 const add1 = cg.allocId();
2871 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);3225 try cg.body.emit(gpa, .OpIAddCarry, .{
2872 cg.body.writeOperand(Id, pair_struct_ty_id);3226 .id_result_type = pair_struct_ty_id,
2873 cg.body.writeOperand(Id, add1);3227 .id_result = add1,
2874 cg.body.writeOperand(Id, result_limbs[k]);3228 .operand_1 = result_limbs[k],
2875 cg.body.writeOperand(Id, lo);3229 .operand_2 = lo,
3230 });
28763231
2877 const sum1 = cg.module.allocId();3232 const sum1 = cg.allocId();
2878 try cg.body.emit(gpa, .OpCompositeExtract, .{3233 try cg.body.emit(gpa, .OpCompositeExtract, .{
2879 .id_result_type = u32_ty_id,3234 .id_result_type = u32_ty_id,
2880 .id_result = sum1,3235 .id_result = sum1,
2881 .composite = add1,3236 .composite = add1,
2882 .indexes = &.{0},3237 .indexes = &.{0},
2883 });3238 });
2884 const c1 = cg.module.allocId();3239 const c1 = cg.allocId();
2885 try cg.body.emit(gpa, .OpCompositeExtract, .{3240 try cg.body.emit(gpa, .OpCompositeExtract, .{
2886 .id_result_type = u32_ty_id,3241 .id_result_type = u32_ty_id,
2887 .id_result = c1,3242 .id_result = c1,
...@@ -2889,21 +3244,22 @@ const CompositeInt = struct {...@@ -2889,21 +3244,22 @@ const CompositeInt = struct {
2889 .indexes = &.{1},3244 .indexes = &.{1},
2890 });3245 });
28913246
2892 const add2 = cg.module.allocId();3247 const add2 = cg.allocId();
2893 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);3248 try cg.body.emit(gpa, .OpIAddCarry, .{
2894 cg.body.writeOperand(Id, pair_struct_ty_id);3249 .id_result_type = pair_struct_ty_id,
2895 cg.body.writeOperand(Id, add2);3250 .id_result = add2,
2896 cg.body.writeOperand(Id, sum1);3251 .operand_1 = sum1,
2897 cg.body.writeOperand(Id, carry_id);3252 .operand_2 = carry_id,
3253 });
28983254
2899 result_limbs[k] = cg.module.allocId();3255 result_limbs[k] = cg.allocId();
2900 try cg.body.emit(gpa, .OpCompositeExtract, .{3256 try cg.body.emit(gpa, .OpCompositeExtract, .{
2901 .id_result_type = u32_ty_id,3257 .id_result_type = u32_ty_id,
2902 .id_result = result_limbs[k],3258 .id_result = result_limbs[k],
2903 .composite = add2,3259 .composite = add2,
2904 .indexes = &.{0},3260 .indexes = &.{0},
2905 });3261 });
2906 const c2 = cg.module.allocId();3262 const c2 = cg.allocId();
2907 try cg.body.emit(gpa, .OpCompositeExtract, .{3263 try cg.body.emit(gpa, .OpCompositeExtract, .{
2908 .id_result_type = u32_ty_id,3264 .id_result_type = u32_ty_id,
2909 .id_result = c2,3265 .id_result = c2,
...@@ -2925,8 +3281,8 @@ const CompositeInt = struct {...@@ -2925,8 +3281,8 @@ const CompositeInt = struct {
2925 fn normalize(ci: CompositeInt) !CompositeInt {3281 fn normalize(ci: CompositeInt) !CompositeInt {
2926 if (ci.info.bits == ci.info.backing_bits) return ci;3282 if (ci.info.bits == ci.info.backing_bits) return ci;
2927 const cg = ci.cg;3283 const cg = ci.cg;
2928 const gpa = cg.module.gpa;3284 const gpa = cg.gpa;
2929 const top_bits: u16 = ci.info.bits % Module.big_int_bits;3285 const top_bits: u16 = ci.info.bits % big_int_bits;
2930 assert(top_bits != 0);3286 assert(top_bits != 0);
29313287
2932 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);3288 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
...@@ -2947,25 +3303,27 @@ const CompositeInt = struct {...@@ -2947,25 +3303,27 @@ const CompositeInt = struct {
2947 const shift_amt: u32 = 32 - top_bits;3303 const shift_amt: u32 = 32 - top_bits;
2948 const shift_id = try cg.constInt(.u32, shift_amt);3304 const shift_id = try cg.constInt(.u32, shift_amt);
29493305
2950 const as_signed = cg.module.allocId();3306 const as_signed = cg.allocId();
2951 try cg.body.emit(gpa, .OpBitcast, .{3307 try cg.body.emit(gpa, .OpBitcast, .{
2952 .id_result_type = i32_ty_id,3308 .id_result_type = i32_ty_id,
2953 .id_result = as_signed,3309 .id_result = as_signed,
2954 .operand = top_limb,3310 .operand = top_limb,
2955 });3311 });
2956 const shifted_left = cg.module.allocId();3312 const shifted_left = cg.allocId();
2957 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);3313 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
2958 cg.body.writeOperand(Id, i32_ty_id);3314 .id_result_type = i32_ty_id,
2959 cg.body.writeOperand(Id, shifted_left);3315 .id_result = shifted_left,
2960 cg.body.writeOperand(Id, as_signed);3316 .base = as_signed,
2961 cg.body.writeOperand(Id, shift_id);3317 .shift = shift_id,
2962 const shifted_right = cg.module.allocId();3318 });
2963 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);3319 const shifted_right = cg.allocId();
2964 cg.body.writeOperand(Id, i32_ty_id);3320 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
2965 cg.body.writeOperand(Id, shifted_right);3321 .id_result_type = i32_ty_id,
2966 cg.body.writeOperand(Id, shifted_left);3322 .id_result = shifted_right,
2967 cg.body.writeOperand(Id, shift_id);3323 .base = shifted_left,
2968 const back = cg.module.allocId();3324 .shift = shift_id,
3325 });
3326 const back = cg.allocId();
2969 try cg.body.emit(gpa, .OpBitcast, .{3327 try cg.body.emit(gpa, .OpBitcast, .{
2970 .id_result_type = u32_ty_id,3328 .id_result_type = u32_ty_id,
2971 .id_result = back,3329 .id_result = back,
...@@ -3000,7 +3358,7 @@ const Vectorization = union(enum) {...@@ -3000,7 +3358,7 @@ const Vectorization = union(enum) {
30003358
3001 /// Derive a vectorization from a particular type3359 /// Derive a vectorization from a particular type
3002 fn fromType(ty: Type, cg: *CodeGen) Vectorization {3360 fn fromType(ty: Type, cg: *CodeGen) Vectorization {
3003 const zcu = cg.module.zcu;3361 const zcu = cg.zcu;
3004 if (!ty.isVector(zcu)) return .scalar;3362 if (!ty.isVector(zcu)) return .scalar;
3005 return .{ .unrolled = ty.vectorLen(zcu) };3363 return .{ .unrolled = ty.vectorLen(zcu) };
3006 }3364 }
...@@ -3034,7 +3392,7 @@ const Vectorization = union(enum) {...@@ -3034,7 +3392,7 @@ const Vectorization = union(enum) {
3034 /// `ty` may be a scalar or vector, it doesn't matter.3392 /// `ty` may be a scalar or vector, it doesn't matter.
3035 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {3393 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {
3036 const pt = cg.pt;3394 const pt = cg.pt;
3037 const zcu = cg.module.zcu;3395 const zcu = cg.zcu;
3038 const scalar_ty = ty.scalarType(zcu);3396 const scalar_ty = ty.scalarType(zcu);
3039 return switch (vec) {3397 return switch (vec) {
3040 .scalar => scalar_ty,3398 .scalar => scalar_ty,
...@@ -3046,7 +3404,7 @@ const Vectorization = union(enum) {...@@ -3046,7 +3404,7 @@ const Vectorization = union(enum) {
3046 /// this setup, and returns a new type that holds the relevant information on how to access3404 /// this setup, and returns a new type that holds the relevant information on how to access
3047 /// elements of the input.3405 /// elements of the input.
3048 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {3406 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {
3049 const zcu = cg.module.zcu;3407 const zcu = cg.zcu;
3050 const is_vector = tmp.ty.isVector(zcu);3408 const is_vector = tmp.ty.isVector(zcu);
3051 const value: PreparedOperand.Value = switch (tmp.value) {3409 const value: PreparedOperand.Value = switch (tmp.value) {
3052 .singleton => |id| switch (vec) {3410 .singleton => |id| switch (vec) {
...@@ -3146,26 +3504,28 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {...@@ -3146,26 +3504,28 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {
3146/// This function builds an OpSConvert of OpUConvert depending on the3504/// This function builds an OpSConvert of OpUConvert depending on the
3147/// signedness of the types.3505/// signedness of the types.
3148fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {3506fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3149 const zcu = cg.module.zcu;3507 const zcu = cg.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);
31533508
3154 const v = cg.vectorization(.{ dst_ty, src });3509 const v = cg.vectorization(.{ dst_ty, src });
3155 const result_ty = try v.resultType(cg, dst_ty);3510 const result_ty = try v.resultType(cg, dst_ty);
31563511
3157 // We can directly compare integers, because those type-IDs are cached.3512 const dst_scalar = dst_ty.scalarType(zcu);
3158 if (dst_ty_id == src_ty_id) {3513 const src_scalar = src.ty.scalarType(zcu);
3159 // Nothing to do, type-pun to the right value.3514 if (dst_scalar.toIntern() == src_scalar.toIntern()) {
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.
3164 return src.pun(result_ty);3515 return src.pun(result_ty);
3165 }3516 }
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
3167 const ops = v.components();3527 const ops = v.components();
3168 const results = cg.module.allocIds(ops);3528 const results = cg.allocIds(ops);
31693529
3170 const op_result_ty = dst_ty.scalarType(zcu);3530 const op_result_ty = dst_ty.scalarType(zcu);
3171 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3531 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 {...@@ -3179,7 +3539,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3179 const op_src = try v.prepare(cg, src);3539 const op_src = try v.prepare(cg, src);
31803540
3181 for (0..ops) |i| {3541 for (0..ops) |i| {
3182 try cg.body.emitRaw(cg.module.gpa, opcode, 3);3542 try cg.body.emitRaw(cg.gpa, opcode, 3);
3183 cg.body.writeOperand(Id, op_result_ty_id);3543 cg.body.writeOperand(Id, op_result_ty_id);
3184 cg.body.writeOperand(Id, results.at(i));3544 cg.body.writeOperand(Id, results.at(i));
3185 cg.body.writeOperand(Id, op_src.at(i));3545 cg.body.writeOperand(Id, op_src.at(i));
...@@ -3188,51 +3548,12 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {...@@ -3188,51 +3548,12 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3188 return v.finalize(result_ty, results);3548 return v.finalize(result_ty, results);
3189}3549}
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
3230fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary {3551fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary {
3231 const zcu = cg.module.zcu;3552 const zcu = cg.zcu;
32323553
3233 const v = cg.vectorization(.{ condition, lhs, rhs });3554 const v = cg.vectorization(.{ condition, lhs, rhs });
3234 const ops = v.components();3555 const ops = v.components();
3235 const results = cg.module.allocIds(ops);3556 const results = cg.allocIds(ops);
32363557
3237 const op_result_ty = lhs.ty.scalarType(zcu);3558 const op_result_ty = lhs.ty.scalarType(zcu);
3238 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3559 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...@@ -3245,7 +3566,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar
3245 const object_2 = try v.prepare(cg, rhs);3566 const object_2 = try v.prepare(cg, rhs);
32463567
3247 for (0..ops) |i| {3568 for (0..ops) |i| {
3248 try cg.body.emit(cg.module.gpa, .OpSelect, .{3569 try cg.body.emit(cg.gpa, .OpSelect, .{
3249 .id_result_type = op_result_ty_id,3570 .id_result_type = op_result_ty_id,
3250 .id_result = results.at(i),3571 .id_result = results.at(i),
3251 .condition = cond.at(i),3572 .condition = cond.at(i),
...@@ -3260,7 +3581,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar...@@ -3260,7 +3581,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar
3260fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {3581fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
3261 const v = cg.vectorization(.{ lhs, rhs });3582 const v = cg.vectorization(.{ lhs, rhs });
3262 const ops = v.components();3583 const ops = v.components();
3263 const results = cg.module.allocIds(ops);3584 const results = cg.allocIds(ops);
32643585
3265 const op_result_ty: Type = .bool;3586 const op_result_ty: Type = .bool;
3266 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3587 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...@@ -3270,7 +3591,7 @@ fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Tempo
3270 const op_rhs = try v.prepare(cg, rhs);3591 const op_rhs = try v.prepare(cg, rhs);
32713592
3272 for (0..ops) |i| {3593 for (0..ops) |i| {
3273 try cg.body.emitRaw(cg.module.gpa, opcode, 4);3594 try cg.body.emitRaw(cg.gpa, opcode, 4);
3274 cg.body.writeOperand(Id, op_result_ty_id);3595 cg.body.writeOperand(Id, op_result_ty_id);
3275 cg.body.writeOperand(Id, results.at(i));3596 cg.body.writeOperand(Id, results.at(i));
3276 cg.body.writeOperand(Id, op_lhs.at(i));3597 cg.body.writeOperand(Id, op_lhs.at(i));
...@@ -3351,11 +3672,11 @@ const UnaryOp = enum {...@@ -3351,11 +3672,11 @@ const UnaryOp = enum {
3351};3672};
33523673
3353fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {3674fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3354 const zcu = cg.module.zcu;3675 const zcu = cg.zcu;
3355 const target = cg.module.zcu.getTarget();3676 const target = cg.zcu.getTarget();
3356 const v = cg.vectorization(.{operand});3677 const v = cg.vectorization(.{operand});
3357 const ops = v.components();3678 const ops = v.components();
3358 const results = cg.module.allocIds(ops);3679 const results = cg.allocIds(ops);
3359 const op_result_ty = operand.ty.scalarType(zcu);3680 const op_result_ty = operand.ty.scalarType(zcu);
3360 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3681 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
3361 const result_ty = try v.resultType(cg, operand.ty);3682 const result_ty = try v.resultType(cg, operand.ty);
...@@ -3364,7 +3685,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {...@@ -3364,7 +3685,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3364 if (op.extInstOpcode(target)) |opcode| {3685 if (op.extInstOpcode(target)) |opcode| {
3365 const set = try cg.importExtendedSet();3686 const set = try cg.importExtendedSet();
3366 for (0..ops) |i| {3687 for (0..ops) |i| {
3367 try cg.body.emit(cg.module.gpa, .OpExtInst, .{3688 try cg.body.emit(cg.gpa, .OpExtInst, .{
3368 .id_result_type = op_result_ty_id,3689 .id_result_type = op_result_ty_id,
3369 .id_result = results.at(i),3690 .id_result = results.at(i),
3370 .set = set,3691 .set = set,
...@@ -3384,7 +3705,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {...@@ -3384,7 +3705,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3384 ),3705 ),
3385 };3706 };
3386 for (0..ops) |i| {3707 for (0..ops) |i| {
3387 try cg.body.emitRaw(cg.module.gpa, opcode, 3);3708 try cg.body.emitRaw(cg.gpa, opcode, 3);
3388 cg.body.writeOperand(Id, op_result_ty_id);3709 cg.body.writeOperand(Id, op_result_ty_id);
3389 cg.body.writeOperand(Id, results.at(i));3710 cg.body.writeOperand(Id, results.at(i));
3390 cg.body.writeOperand(Id, op_operand.at(i));3711 cg.body.writeOperand(Id, op_operand.at(i));
...@@ -3395,11 +3716,11 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {...@@ -3395,11 +3716,11 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3395}3716}
33963717
3397fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {3718fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
3398 const zcu = cg.module.zcu;3719 const zcu = cg.zcu;
33993720
3400 const v = cg.vectorization(.{ lhs, rhs });3721 const v = cg.vectorization(.{ lhs, rhs });
3401 const ops = v.components();3722 const ops = v.components();
3402 const results = cg.module.allocIds(ops);3723 const results = cg.allocIds(ops);
34033724
3404 const op_result_ty = lhs.ty.scalarType(zcu);3725 const op_result_ty = lhs.ty.scalarType(zcu);
3405 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3726 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...@@ -3409,7 +3730,7 @@ fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Te
3409 const op_rhs = try v.prepare(cg, rhs);3730 const op_rhs = try v.prepare(cg, rhs);
34103731
3411 for (0..ops) |i| {3732 for (0..ops) |i| {
3412 try cg.body.emitRaw(cg.module.gpa, opcode, 4);3733 try cg.body.emitRaw(cg.gpa, opcode, 4);
3413 cg.body.writeOperand(Id, op_result_ty_id);3734 cg.body.writeOperand(Id, op_result_ty_id);
3414 cg.body.writeOperand(Id, results.at(i));3735 cg.body.writeOperand(Id, results.at(i));
3415 cg.body.writeOperand(Id, op_lhs.at(i));3736 cg.body.writeOperand(Id, op_lhs.at(i));
...@@ -3428,11 +3749,11 @@ fn buildWideMul(...@@ -3428,11 +3749,11 @@ fn buildWideMul(
3428 rhs: Temporary,3749 rhs: Temporary,
3429) !struct { Temporary, Temporary } {3750) !struct { Temporary, Temporary } {
3430 const pt = cg.pt;3751 const pt = cg.pt;
3431 const zcu = cg.module.zcu;3752 const zcu = cg.zcu;
3432 const comp = zcu.comp;3753 const comp = zcu.comp;
3433 const gpa = comp.gpa;3754 const gpa = comp.gpa;
3434 const io = comp.io;3755 const io = comp.io;
3435 const target = cg.module.zcu.getTarget();3756 const target = cg.zcu.getTarget();
3436 const ip = &zcu.intern_pool;3757 const ip = &zcu.intern_pool;
34373758
3438 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));3759 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));
...@@ -3444,8 +3765,8 @@ fn buildWideMul(...@@ -3444,8 +3765,8 @@ fn buildWideMul(
3444 const lhs_op = try v.prepare(cg, lhs);3765 const lhs_op = try v.prepare(cg, lhs);
3445 const rhs_op = try v.prepare(cg, rhs);3766 const rhs_op = try v.prepare(cg, rhs);
34463767
3447 const value_results = cg.module.allocIds(ops);3768 const value_results = cg.allocIds(ops);
3448 const overflow_results = cg.module.allocIds(ops);3769 const overflow_results = cg.allocIds(ops);
34493770
3450 switch (target.os.tag) {3771 switch (target.os.tag) {
3451 .opencl => {3772 .opencl => {
...@@ -3490,7 +3811,7 @@ fn buildWideMul(...@@ -3490,7 +3811,7 @@ fn buildWideMul(
3490 };3811 };
34913812
3492 for (0..ops) |i| {3813 for (0..ops) |i| {
3493 const op_result = cg.module.allocId();3814 const op_result = cg.allocId();
34943815
3495 try cg.body.emitRaw(gpa, opcode, 4);3816 try cg.body.emitRaw(gpa, opcode, 4);
3496 cg.body.writeOperand(Id, op_result_ty_id);3817 cg.body.writeOperand(Id, op_result_ty_id);
...@@ -3550,12 +3871,12 @@ fn buildWideMul(...@@ -3550,12 +3871,12 @@ fn buildWideMul(
3550fn generateTestEntryPoint(3871fn generateTestEntryPoint(
3551 cg: *CodeGen,3872 cg: *CodeGen,
3552 name: []const u8,3873 name: []const u8,
3553 spv_decl_index: Module.Decl.Index,3874 spv_decl_index: Decl.Index,
3554 test_id: Id,3875 test_id: Id,
3555) !void {3876) !void {
3556 const gpa = cg.module.gpa;3877 const gpa = cg.gpa;
3557 const zcu = cg.module.zcu;3878 const zcu = cg.zcu;
3558 const target = cg.module.zcu.getTarget();3879 const target = cg.zcu.getTarget();
35593880
3560 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);3881 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);
3561 const ptr_anyerror_ty = try cg.pt.ptrType(.{3882 const ptr_anyerror_ty = try cg.pt.ptrType(.{
...@@ -3564,15 +3885,15 @@ fn generateTestEntryPoint(...@@ -3564,15 +3885,15 @@ fn generateTestEntryPoint(
3564 });3885 });
3565 const ptr_anyerror_ty_id = try cg.resolveType(ptr_anyerror_ty, .direct);3886 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();
3572 switch (target.os.tag) {3893 switch (target.os.tag) {
3573 .opencl, .amdhsa => {3894 .opencl, .amdhsa => {
3574 const void_ty_id = try cg.resolveType(.void, .direct);3895 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
3577 try section.emit(gpa, .OpFunction, .{3898 try section.emit(gpa, .OpFunction, .{
3578 .id_result_type = try cg.resolveType(.void, .direct),3899 .id_result_type = try cg.resolveType(.void, .direct),
...@@ -3587,43 +3908,43 @@ fn generateTestEntryPoint(...@@ -3587,43 +3908,43 @@ fn generateTestEntryPoint(
3587 });3908 });
35883909
3589 try section.emit(gpa, .OpLabel, .{3910 try section.emit(gpa, .OpLabel, .{
3590 .id_result = cg.module.allocId(),3911 .id_result = cg.allocId(),
3591 });3912 });
3592 },3913 },
3593 .vulkan, .opengl => {3914 .vulkan, .opengl => {
3594 if (cg.module.error_buffer == null) {3915 if (cg.error_buffer == null) {
3595 const spv_err_decl_index = try cg.module.allocDecl(.global);3916 const spv_err_decl_index = try cg.allocDecl(.global);
3596 const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id;3917 const err_buf_result_id = cg.declPtr(spv_err_decl_index).result_id;
35973918
3598 const buffer_struct_ty_id = cg.module.allocId();3919 const buffer_struct_ty_id = cg.allocId();
3599 try cg.module.sections.globals.emit(gpa, .OpTypeStruct, .{3920 try cg.sections.globals.emit(gpa, .OpTypeStruct, .{
3600 .id_result = buffer_struct_ty_id,3921 .id_result = buffer_struct_ty_id,
3601 .id_ref = &.{anyerror_ty_id},3922 .id_ref = &.{anyerror_ty_id},
3602 });3923 });
3603 try cg.module.memberDebugName(buffer_struct_ty_id, 0, "error_out");3924 try cg.memberDebugName(buffer_struct_ty_id, 0, "error_out");
3604 try cg.module.decorate(buffer_struct_ty_id, .block);3925 try cg.decorate(buffer_struct_ty_id, .block);
3605 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });3926 try cg.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
36063927
3607 const ptr_buffer_struct_ty_id = cg.module.allocId();3928 const ptr_buffer_struct_ty_id = cg.allocId();
3608 try cg.module.sections.globals.emit(gpa, .OpTypePointer, .{3929 try cg.sections.globals.emit(gpa, .OpTypePointer, .{
3609 .id_result = ptr_buffer_struct_ty_id,3930 .id_result = ptr_buffer_struct_ty_id,
3610 .storage_class = cg.module.storageClass(.global),3931 .storage_class = cg.storageClass(.global),
3611 .type = buffer_struct_ty_id,3932 .type = buffer_struct_ty_id,
3612 });3933 });
36133934
3614 try cg.module.sections.globals.emit(gpa, .OpVariable, .{3935 try cg.sections.globals.emit(gpa, .OpVariable, .{
3615 .id_result_type = ptr_buffer_struct_ty_id,3936 .id_result_type = ptr_buffer_struct_ty_id,
3616 .id_result = err_buf_result_id,3937 .id_result = err_buf_result_id,
3617 .storage_class = cg.module.storageClass(.global),3938 .storage_class = cg.storageClass(.global),
3618 });3939 });
3619 try cg.module.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } });3940 try cg.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } });
3620 try cg.module.decorate(err_buf_result_id, .{ .binding = .{ .binding_point = 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;
3623 }3944 }
36243945
3625 const void_ty_id = try cg.resolveType(.void, .direct);3946 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, &.{});
3627 try section.emit(gpa, .OpFunction, .{3948 try section.emit(gpa, .OpFunction, .{
3628 .id_result_type = try cg.resolveType(.void, .direct),3949 .id_result_type = try cg.resolveType(.void, .direct),
3629 .id_result = kernel_id,3950 .id_result = kernel_id,
...@@ -3631,12 +3952,12 @@ fn generateTestEntryPoint(...@@ -3631,12 +3952,12 @@ fn generateTestEntryPoint(
3631 .function_type = kernel_proto_ty_id,3952 .function_type = kernel_proto_ty_id,
3632 });3953 });
3633 try section.emit(gpa, .OpLabel, .{3954 try section.emit(gpa, .OpLabel, .{
3634 .id_result = cg.module.allocId(),3955 .id_result = cg.allocId(),
3635 });3956 });
36363957
3637 const spv_err_decl_index = cg.module.error_buffer.?;3958 const spv_err_decl_index = cg.error_buffer.?;
3638 const buffer_id = cg.module.declPtr(spv_err_decl_index).result_id;3959 const buffer_id = cg.declPtr(spv_err_decl_index).result_id;
3639 try cg.module.decl_deps.append(gpa, spv_err_decl_index);3960 try cg.decl_deps.append(gpa, spv_err_decl_index);
36403961
3641 const zero_id = try cg.constInt(.u32, 0);3962 const zero_id = try cg.constInt(.u32, 0);
3642 try section.emit(gpa, .OpInBoundsAccessChain, .{3963 try section.emit(gpa, .OpInBoundsAccessChain, .{
...@@ -3649,7 +3970,7 @@ fn generateTestEntryPoint(...@@ -3649,7 +3970,7 @@ fn generateTestEntryPoint(
3649 else => unreachable,3970 else => unreachable,
3650 }3971 }
36513972
3652 const error_id = cg.module.allocId();3973 const error_id = cg.allocId();
3653 try section.emit(gpa, .OpFunctionCall, .{3974 try section.emit(gpa, .OpFunctionCall, .{
3654 .id_result_type = anyerror_ty_id,3975 .id_result_type = anyerror_ty_id,
3655 .id_result = error_id,3976 .id_result = error_id,
...@@ -3668,9 +3989,14 @@ fn generateTestEntryPoint(...@@ -3668,9 +3989,14 @@ fn generateTestEntryPoint(
36683989
3669 // Just generate a quick other name because the intel runtime crashes when the entry-3990 // Just generate a quick other name because the intel runtime crashes when the entry-
3670 // point name is the same as a different OpName.3991 // 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 };
3674}4000}
36754001
3676fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {4002fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
...@@ -3688,7 +4014,7 @@ fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {...@@ -3688,7 +4014,7 @@ fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
3688/// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct).4014/// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct).
3689fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {4015fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3690 const pt = cg.pt;4016 const pt = cg.pt;
3691 const zcu = cg.module.zcu;4017 const zcu = cg.zcu;
3692 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {4018 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
3693 .bool => {4019 .bool => {
3694 const false_id = try cg.constBool(false, .indirect);4020 const false_id = try cg.constBool(false, .indirect);
...@@ -3714,7 +4040,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {...@@ -3714,7 +4040,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3714/// Convert representation from direct (in 'register) to direct (in memory)4040/// Convert representation from direct (in 'register) to direct (in memory)
3715/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).4041/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).
3716fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {4042fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3717 const zcu = cg.module.zcu;4043 const zcu = cg.zcu;
3718 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {4044 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
3719 .bool => {4045 .bool => {
3720 const result = try cg.intFromBool(.init(ty, operand_id), .u1);4046 const result = try cg.intFromBool(.init(ty, operand_id), .u1);
...@@ -3726,9 +4052,9 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {...@@ -3726,9 +4052,9 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
37264052
3727fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {4053fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
3728 const result_ty_id = try cg.resolveType(result_ty, .indirect);4054 const result_ty_id = try cg.resolveType(result_ty, .indirect);
3729 const result_id = cg.module.allocId();4055 const result_id = cg.allocId();
3730 const indexes = [_]u32{field};4056 const indexes = [_]u32{field};
3731 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{4057 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
3732 .id_result_type = result_ty_id,4058 .id_result_type = result_ty_id,
3733 .id_result = result_id,4059 .id_result = result_id,
3734 .composite = object,4060 .composite = object,
...@@ -3740,9 +4066,9 @@ fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {...@@ -3740,9 +4066,9 @@ fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
37404066
3741fn extractVectorComponent(cg: *CodeGen, result_ty: Type, vector_id: Id, field: u32) !Id {4067fn extractVectorComponent(cg: *CodeGen, result_ty: Type, vector_id: Id, field: u32) !Id {
3742 const result_ty_id = try cg.resolveType(result_ty, .direct);4068 const result_ty_id = try cg.resolveType(result_ty, .direct);
3743 const result_id = cg.module.allocId();4069 const result_id = cg.allocId();
3744 const indexes = [_]u32{field};4070 const indexes = [_]u32{field};
3745 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{4071 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
3746 .id_result_type = result_ty_id,4072 .id_result_type = result_ty_id,
3747 .id_result = result_id,4073 .id_result = result_id,
3748 .composite = vector_id,4074 .composite = vector_id,
...@@ -3757,15 +4083,15 @@ const MemoryOptions = struct {...@@ -3757,15 +4083,15 @@ const MemoryOptions = struct {
3757};4083};
37584084
3759fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {4085fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
3760 const zcu = cg.module.zcu;4086 const zcu = cg.zcu;
3761 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);4087 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);
3762 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);4088 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);
3763 const result_id = cg.module.allocId();4089 const result_id = cg.allocId();
3764 const access: spec.MemoryAccess.Extended = .{4090 const access: spec.MemoryAccess.Extended = .{
3765 .@"volatile" = options.is_volatile,4091 .@"volatile" = options.is_volatile,
3766 .aligned = .{ .literal_integer = alignment },4092 .aligned = .{ .literal_integer = alignment },
3767 };4093 };
3768 try cg.body.emit(cg.module.gpa, .OpLoad, .{4094 try cg.body.emit(cg.gpa, .OpLoad, .{
3769 .id_result_type = indirect_value_ty_id,4095 .id_result_type = indirect_value_ty_id,
3770 .id_result = result_id,4096 .id_result = result_id,
3771 .pointer = ptr_id,4097 .pointer = ptr_id,
...@@ -3777,7 +4103,7 @@ fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {...@@ -3777,7 +4103,7 @@ fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
3777fn store(cg: *CodeGen, value_ty: Type, ptr_id: Id, value_id: Id, options: MemoryOptions) !void {4103fn store(cg: *CodeGen, value_ty: Type, ptr_id: Id, value_id: Id, options: MemoryOptions) !void {
3778 const indirect_value_id = try cg.convertToIndirect(value_ty, value_id);4104 const indirect_value_id = try cg.convertToIndirect(value_ty, value_id);
3779 const access: spec.MemoryAccess.Extended = .{ .@"volatile" = options.is_volatile };4105 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, .{
3781 .pointer = ptr_id,4107 .pointer = ptr_id,
3782 .object = indirect_value_id,4108 .object = indirect_value_id,
3783 .memory_access = access,4109 .memory_access = access,
...@@ -3791,8 +4117,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {...@@ -3791,8 +4117,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {
3791}4117}
37924118
3793fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {4119fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
3794 const gpa = cg.module.gpa;4120 const gpa = cg.gpa;
3795 const zcu = cg.module.zcu;4121 const zcu = cg.zcu;
3796 const ip = &zcu.intern_pool;4122 const ip = &zcu.intern_pool;
3797 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))4123 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))
3798 return;4124 return;
...@@ -4028,7 +4354,7 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {...@@ -4028,7 +4354,7 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {
4028}4354}
40294355
4030fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id {4356fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id {
4031 const zcu = cg.module.zcu;4357 const zcu = cg.zcu;
4032 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4358 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
40334359
4034 if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) {4360 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...@@ -4048,8 +4374,8 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
4048 .composite_integer => blk: {4374 .composite_integer => blk: {
4049 const shift_id = try shift.materialize(cg);4375 const shift_id = try shift.materialize(cg);
4050 const u32_ty_id = try cg.resolveType(.u32, .direct);4376 const u32_ty_id = try cg.resolveType(.u32, .direct);
4051 const result_id = cg.module.allocId();4377 const result_id = cg.allocId();
4052 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{4378 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
4053 .id_result_type = u32_ty_id,4379 .id_result_type = u32_ty_id,
4054 .id_result = result_id,4380 .id_result = result_id,
4055 .composite = shift_id,4381 .composite = shift_id,
...@@ -4156,13 +4482,13 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id {...@@ -4156,13 +4482,13 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id {
4156}4482}
41574483
4158fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {4484fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4159 const zcu = cg.module.zcu;4485 const zcu = cg.zcu;
4160 const target = zcu.getTarget();4486 const target = zcu.getTarget();
4161 const info = cg.arithmeticTypeInfo(lhs.ty);4487 const info = cg.arithmeticTypeInfo(lhs.ty);
41624488
4163 const v = cg.vectorization(.{ lhs, rhs });4489 const v = cg.vectorization(.{ lhs, rhs });
4164 const ops = v.components();4490 const ops = v.components();
4165 const results = cg.module.allocIds(ops);4491 const results = cg.allocIds(ops);
41664492
4167 const op_result_ty = lhs.ty.scalarType(zcu);4493 const op_result_ty = lhs.ty.scalarType(zcu);
4168 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);4494 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 {...@@ -4174,7 +4500,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4174 const set = try cg.importExtendedSet();4500 const set = try cg.importExtendedSet();
4175 const opcode = op.extInstOpcode(target, info);4501 const opcode = op.extInstOpcode(target, info);
4176 for (0..ops) |i| {4502 for (0..ops) |i| {
4177 try cg.body.emit(cg.module.gpa, .OpExtInst, .{4503 try cg.body.emit(cg.gpa, .OpExtInst, .{
4178 .id_result_type = op_result_ty_id,4504 .id_result_type = op_result_ty_id,
4179 .id_result = results.at(i),4505 .id_result = results.at(i),
4180 .set = set,4506 .set = set,
...@@ -4195,7 +4521,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {...@@ -4195,7 +4521,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4195/// All other values are returned unmodified (this makes strange integer4521/// All other values are returned unmodified (this makes strange integer
4196/// wrapping easier to use in generic operations).4522/// wrapping easier to use in generic operations).
4197fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {4523fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {
4198 const zcu = cg.module.zcu;4524 const zcu = cg.zcu;
4199 const ty = value.ty;4525 const ty = value.ty;
4200 switch (info.class) {4526 switch (info.class) {
4201 .integer, .bool, .float => return value,4527 .integer, .bool, .float => return value,
...@@ -4341,29 +4667,24 @@ fn airArithOp(...@@ -4341,29 +4667,24 @@ fn airArithOp(
4341}4667}
43424668
4343fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4669fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4670 const zcu = cg.zcu;
4671 const target = zcu.getTarget();
4344 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4672 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4345 const operand = try cg.temporary(ty_op.operand);4673 const value = try cg.temporary(ty_op.operand);
4346 // Note: operand_ty may be signed, while ty is always unsigned!4674 // Note: operand_ty may be signed, while ty is always unsigned.
4347 const result_ty = cg.typeOfIndex(inst);4675 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();
4355 const operand_info = cg.arithmeticTypeInfo(value.ty);4676 const operand_info = cg.arithmeticTypeInfo(value.ty);
4356 switch (operand_info.class) {4677 const result: Temporary = switch (operand_info.class) {
4357 .float => return try cg.buildUnary(.f_abs, value),4678 .float => try cg.buildUnary(.f_abs, value),
4358 .integer, .strange_integer => {4679 .integer, .strange_integer => abs: {
4359 var abs_value = try cg.buildUnary(.i_abs, value);4680 var abs_value = try cg.buildUnary(.i_abs, value);
4360 switch (target.os.tag) {4681 switch (target.os.tag) {
4361 .vulkan, .opengl => {4682 .vulkan, .opengl => {
4362 if (value.ty.intInfo(zcu).signedness == .signed) {4683 if (value.ty.intInfo(zcu).signedness == .signed) {
4363 const abs_id = try abs_value.materialize(cg);4684 const abs_id = try abs_value.materialize(cg);
4364 const dst_ty_id = try cg.resolveType(result_ty, .direct);4685 const dst_ty_id = try cg.resolveType(result_ty, .direct);
4365 const cast_id = cg.module.allocId();4686 const cast_id = cg.allocId();
4366 try cg.body.emit(cg.module.gpa, .OpBitcast, .{4687 try cg.body.emit(cg.gpa, .OpBitcast, .{
4367 .id_result_type = dst_ty_id,4688 .id_result_type = dst_ty_id,
4368 .id_result = cast_id,4689 .id_result = cast_id,
4369 .operand = abs_id,4690 .operand = abs_id,
...@@ -4373,9 +4694,9 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -4373,9 +4694,9 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
4373 },4694 },
4374 else => {},4695 else => {},
4375 }4696 }
4376 return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));4697 break :abs try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
4377 },4698 },
4378 .composite_integer => {4699 .composite_integer => abs: {
4379 const val_id = try value.materialize(cg);4700 const val_id = try value.materialize(cg);
4380 const scratch_top = cg.id_scratch.items.len;4701 const scratch_top = cg.id_scratch.items.len;
4381 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);4702 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
...@@ -4385,10 +4706,10 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -4385,10 +4706,10 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
4385 const ci_neg = try ci_z.addSub(ci, false);4706 const ci_neg = try ci_z.addSub(ci, false);
4386 const result_info = cg.arithmeticTypeInfo(result_ty);4707 const result_info = cg.arithmeticTypeInfo(result_ty);
4387 const u32_ty_id = try cg.resolveType(.u32, .direct);4708 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);
4389 for (0..ci.n_limbs) |i| {4710 for (0..ci.n_limbs) |i| {
4390 result_limbs[i] = cg.module.allocId();4711 result_limbs[i] = cg.allocId();
4391 try cg.body.emit(cg.module.gpa, .OpSelect, .{4712 try cg.body.emit(cg.gpa, .OpSelect, .{
4392 .id_result_type = u32_ty_id,4713 .id_result_type = u32_ty_id,
4393 .id_result = result_limbs[i],4714 .id_result = result_limbs[i],
4394 .condition = is_neg,4715 .condition = is_neg,
...@@ -4398,10 +4719,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -4398,10 +4719,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
4398 }4719 }
4399 const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info);4720 const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info);
4400 const normalized = try ci_result.normalize();4721 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));
4402 },4723 },
4403 .bool => unreachable,4724 .bool => unreachable,
4404 }4725 };
4726 return try result.materialize(cg);
4405}4727}
44064728
4407fn airAddSubOverflow(4729fn airAddSubOverflow(
...@@ -4457,32 +4779,36 @@ fn airAddSubOverflow(...@@ -4457,32 +4779,36 @@ fn airAddSubOverflow(
4457 const res_neg = try ci_res2.cmp(ci_z, .lt);4779 const res_neg = try ci_res2.cmp(ci_z, .lt);
44584780
4459 const bool_ty_id = try cg.resolveType(.bool, .direct);4781 const bool_ty_id = try cg.resolveType(.bool, .direct);
4460 const signs_match = cg.module.allocId();4782 const signs_match = cg.allocId();
4461 try cg.body.emitRaw(cg.module.gpa, .OpLogicalEqual, 4);4783 try cg.body.emit(cg.gpa, .OpLogicalEqual, .{
4462 cg.body.writeOperand(Id, bool_ty_id);4784 .id_result_type = bool_ty_id,
4463 cg.body.writeOperand(Id, signs_match);4785 .id_result = signs_match,
4464 cg.body.writeOperand(Id, lhs_neg);4786 .operand_1 = lhs_neg,
4465 cg.body.writeOperand(Id, rhs_neg);4787 .operand_2 = rhs_neg,
4466 const res_sign_diff = cg.module.allocId();4788 });
4467 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNotEqual, 4);4789 const res_sign_diff = cg.allocId();
4468 cg.body.writeOperand(Id, bool_ty_id);4790 try cg.body.emit(cg.gpa, .OpLogicalNotEqual, .{
4469 cg.body.writeOperand(Id, res_sign_diff);4791 .id_result_type = bool_ty_id,
4470 cg.body.writeOperand(Id, lhs_neg);4792 .id_result = res_sign_diff,
4471 cg.body.writeOperand(Id, res_neg);4793 .operand_1 = lhs_neg,
4794 .operand_2 = res_neg,
4795 });
4472 const ov_cond = if (add == .OpIAdd) signs_match else blk2: {4796 const ov_cond = if (add == .OpIAdd) signs_match else blk2: {
4473 const not_match = cg.module.allocId();4797 const not_match = cg.allocId();
4474 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNot, 3);4798 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
4475 cg.body.writeOperand(Id, bool_ty_id);4799 .id_result_type = bool_ty_id,
4476 cg.body.writeOperand(Id, not_match);4800 .id_result = not_match,
4477 cg.body.writeOperand(Id, signs_match);4801 .operand = signs_match,
4802 });
4478 break :blk2 not_match;4803 break :blk2 not_match;
4479 };4804 };
4480 const ov_result = cg.module.allocId();4805 const ov_result = cg.allocId();
4481 try cg.body.emitRaw(cg.module.gpa, .OpLogicalAnd, 4);4806 try cg.body.emit(cg.gpa, .OpLogicalAnd, .{
4482 cg.body.writeOperand(Id, bool_ty_id);4807 .id_result_type = bool_ty_id,
4483 cg.body.writeOperand(Id, ov_result);4808 .id_result = ov_result,
4484 cg.body.writeOperand(Id, ov_cond);4809 .operand_1 = ov_cond,
4485 cg.body.writeOperand(Id, res_sign_diff);4810 .operand_2 = res_sign_diff,
4811 });
4486 break :blk ov_result;4812 break :blk ov_result;
4487 },4813 },
4488 };4814 };
...@@ -4531,7 +4857,7 @@ fn airAddSubOverflow(...@@ -4531,7 +4857,7 @@ fn airAddSubOverflow(
45314857
4532fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4858fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4533 const pt = cg.pt;4859 const pt = cg.pt;
4534 const gpa = cg.module.gpa;4860 const gpa = cg.gpa;
4535 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4861 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4536 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;4862 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
4537 const lhs = try cg.temporary(extra.lhs);4863 const lhs = try cg.temporary(extra.lhs);
...@@ -4559,32 +4885,35 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4559,32 +4885,35 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45594885
4560 const bool_ty_id = try cg.resolveType(.bool, .direct);4886 const bool_ty_id = try cg.resolveType(.bool, .direct);
4561 const u32_ty_id = try cg.resolveType(.u32, .direct);4887 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
4564 const ov_bool = switch (info.signedness) {4890 const ov_bool = switch (info.signedness) {
4565 .unsigned => blk: {4891 .unsigned => blk: {
4566 const zero_id = try cg.constInt(.u32, @as(u32, 0));4892 const zero_id = try cg.constInt(.u32, @as(u32, 0));
4567 var any_nonzero = cg.module.allocId();4893 var any_nonzero = cg.allocId();
4568 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4894 try cg.body.emit(gpa, .OpINotEqual, .{
4569 cg.body.writeOperand(Id, bool_ty_id);4895 .id_result_type = bool_ty_id,
4570 cg.body.writeOperand(Id, any_nonzero);4896 .id_result = any_nonzero,
4571 cg.body.writeOperand(Id, high_limbs[0]);4897 .operand_1 = high_limbs[0],
4572 cg.body.writeOperand(Id, zero_id);4898 .operand_2 = zero_id,
4899 });
45734900
4574 for (1..n) |i| {4901 for (1..n) |i| {
4575 const limb_nz = cg.module.allocId();4902 const limb_nz = cg.allocId();
4576 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4903 try cg.body.emit(gpa, .OpINotEqual, .{
4577 cg.body.writeOperand(Id, bool_ty_id);4904 .id_result_type = bool_ty_id,
4578 cg.body.writeOperand(Id, limb_nz);4905 .id_result = limb_nz,
4579 cg.body.writeOperand(Id, high_limbs[i]);4906 .operand_1 = high_limbs[i],
4580 cg.body.writeOperand(Id, zero_id);4907 .operand_2 = zero_id,
45814908 });
4582 const combined = cg.module.allocId();4909
4583 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);4910 const combined = cg.allocId();
4584 cg.body.writeOperand(Id, bool_ty_id);4911 try cg.body.emit(gpa, .OpLogicalOr, .{
4585 cg.body.writeOperand(Id, combined);4912 .id_result_type = bool_ty_id,
4586 cg.body.writeOperand(Id, any_nonzero);4913 .id_result = combined,
4587 cg.body.writeOperand(Id, limb_nz);4914 .operand_1 = any_nonzero,
4915 .operand_2 = limb_nz,
4916 });
4588 any_nonzero = combined;4917 any_nonzero = combined;
4589 }4918 }
45904919
...@@ -4595,92 +4924,99 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4595,92 +4924,99 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4595 const top_limb = ci_res.limbs[n - 1];4924 const top_limb = ci_res.limbs[n - 1];
4596 const i32_ty_id = try cg.resolveType(.i32, .direct);4925 const i32_ty_id = try cg.resolveType(.i32, .direct);
45974926
4598 const top_bits: u16 = if (info.bits % Module.big_int_bits == 0)4927 const top_bits: u16 = if (info.bits % big_int_bits == 0)
4599 Module.big_int_bits4928 big_int_bits
4600 else4929 else
4601 info.bits % Module.big_int_bits;4930 info.bits % big_int_bits;
46024931
4603 const shift_amt: u32 = top_bits - 1;4932 const shift_amt: u32 = top_bits - 1;
4604 const shift_id = try cg.constInt(.u32, shift_amt);4933 const shift_id = try cg.constInt(.u32, shift_amt);
46054934
4606 const as_signed = cg.module.allocId();4935 const as_signed = cg.allocId();
4607 try cg.body.emit(gpa, .OpBitcast, .{4936 try cg.body.emit(gpa, .OpBitcast, .{
4608 .id_result_type = i32_ty_id,4937 .id_result_type = i32_ty_id,
4609 .id_result = as_signed,4938 .id_result = as_signed,
4610 .operand = top_limb,4939 .operand = top_limb,
4611 });4940 });
4612 const sign_ext = cg.module.allocId();4941 const sign_ext = cg.allocId();
4613 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);4942 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4614 cg.body.writeOperand(Id, i32_ty_id);4943 .id_result_type = i32_ty_id,
4615 cg.body.writeOperand(Id, sign_ext);4944 .id_result = sign_ext,
4616 cg.body.writeOperand(Id, as_signed);4945 .base = as_signed,
4617 cg.body.writeOperand(Id, shift_id);4946 .shift = shift_id,
4618 const expected = cg.module.allocId();4947 });
4948 const expected = cg.allocId();
4619 try cg.body.emit(gpa, .OpBitcast, .{4949 try cg.body.emit(gpa, .OpBitcast, .{
4620 .id_result_type = u32_ty_id,4950 .id_result_type = u32_ty_id,
4621 .id_result = expected,4951 .id_result = expected,
4622 .operand = sign_ext,4952 .operand = sign_ext,
4623 });4953 });
46244954
4625 var any_mismatch = cg.module.allocId();4955 var any_mismatch = cg.allocId();
4626 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4956 try cg.body.emit(gpa, .OpINotEqual, .{
4627 cg.body.writeOperand(Id, bool_ty_id);4957 .id_result_type = bool_ty_id,
4628 cg.body.writeOperand(Id, any_mismatch);4958 .id_result = any_mismatch,
4629 cg.body.writeOperand(Id, high_limbs[0]);4959 .operand_1 = high_limbs[0],
4630 cg.body.writeOperand(Id, expected);4960 .operand_2 = expected,
4961 });
46314962
4632 for (1..n) |i| {4963 for (1..n) |i| {
4633 const limb_ne = cg.module.allocId();4964 const limb_ne = cg.allocId();
4634 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4965 try cg.body.emit(gpa, .OpINotEqual, .{
4635 cg.body.writeOperand(Id, bool_ty_id);4966 .id_result_type = bool_ty_id,
4636 cg.body.writeOperand(Id, limb_ne);4967 .id_result = limb_ne,
4637 cg.body.writeOperand(Id, high_limbs[i]);4968 .operand_1 = high_limbs[i],
4638 cg.body.writeOperand(Id, expected);4969 .operand_2 = expected,
46394970 });
4640 const combined = cg.module.allocId();4971
4641 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);4972 const combined = cg.allocId();
4642 cg.body.writeOperand(Id, bool_ty_id);4973 try cg.body.emit(gpa, .OpLogicalOr, .{
4643 cg.body.writeOperand(Id, combined);4974 .id_result_type = bool_ty_id,
4644 cg.body.writeOperand(Id, any_mismatch);4975 .id_result = combined,
4645 cg.body.writeOperand(Id, limb_ne);4976 .operand_1 = any_mismatch,
4977 .operand_2 = limb_ne,
4978 });
4646 any_mismatch = combined;4979 any_mismatch = combined;
4647 }4980 }
46484981
4649 if (info.bits != info.backing_bits) {4982 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;
4651 const s_shift_id = try cg.constInt(.u32, top_bits_s - 1);4984 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();
4654 try cg.body.emit(gpa, .OpBitcast, .{4987 try cg.body.emit(gpa, .OpBitcast, .{
4655 .id_result_type = i32_ty_id,4988 .id_result_type = i32_ty_id,
4656 .id_result = top_as_signed,4989 .id_result = top_as_signed,
4657 .operand = top_limb,4990 .operand = top_limb,
4658 });4991 });
4659 const top_sign_ext = cg.module.allocId();4992 const top_sign_ext = cg.allocId();
4660 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);4993 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4661 cg.body.writeOperand(Id, i32_ty_id);4994 .id_result_type = i32_ty_id,
4662 cg.body.writeOperand(Id, top_sign_ext);4995 .id_result = top_sign_ext,
4663 cg.body.writeOperand(Id, top_as_signed);4996 .base = top_as_signed,
4664 cg.body.writeOperand(Id, s_shift_id);4997 .shift = s_shift_id,
4665 const top_expected = cg.module.allocId();4998 });
4999 const top_expected = cg.allocId();
4666 try cg.body.emit(gpa, .OpBitcast, .{5000 try cg.body.emit(gpa, .OpBitcast, .{
4667 .id_result_type = u32_ty_id,5001 .id_result_type = u32_ty_id,
4668 .id_result = top_expected,5002 .id_result = top_expected,
4669 .operand = top_sign_ext,5003 .operand = top_sign_ext,
4670 });5004 });
4671 const top_mismatch = cg.module.allocId();5005 const top_mismatch = cg.allocId();
4672 try cg.body.emitRaw(gpa, .OpINotEqual, 4);5006 try cg.body.emit(gpa, .OpINotEqual, .{
4673 cg.body.writeOperand(Id, bool_ty_id);5007 .id_result_type = bool_ty_id,
4674 cg.body.writeOperand(Id, top_mismatch);5008 .id_result = top_mismatch,
4675 cg.body.writeOperand(Id, top_limb);5009 .operand_1 = top_limb,
4676 cg.body.writeOperand(Id, top_expected);5010 .operand_2 = top_expected,
46775011 });
4678 const combined = cg.module.allocId();5012
4679 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);5013 const combined = cg.allocId();
4680 cg.body.writeOperand(Id, bool_ty_id);5014 try cg.body.emit(gpa, .OpLogicalOr, .{
4681 cg.body.writeOperand(Id, combined);5015 .id_result_type = bool_ty_id,
4682 cg.body.writeOperand(Id, any_mismatch);5016 .id_result = combined,
4683 cg.body.writeOperand(Id, top_mismatch);5017 .operand_1 = any_mismatch,
5018 .operand_2 = top_mismatch,
5019 });
4684 any_mismatch = combined;5020 any_mismatch = combined;
4685 }5021 }
46865022
...@@ -4702,7 +5038,8 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4702,7 +5038,8 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4702 // - Additionally, if info.bits != 32, we'll have to check the high bits5038 // - Additionally, if info.bits != 32, we'll have to check the high bits
4703 // of the result too.5039 // 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;
4706 // If non-null, the number of bits that the multiplication should be performed in. If5043 // If non-null, the number of bits that the multiplication should be performed in. If
4707 // null, we have to use wide multiplication.5044 // null, we have to use wide multiplication.
4708 const maybe_op_ty_bits: ?u16 = switch (info.bits) {5045 const maybe_op_ty_bits: ?u16 = switch (info.bits) {
...@@ -4846,7 +5183,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4846,7 +5183,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4846}5183}
48475184
4848fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5185fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4849 const zcu = cg.module.zcu;5186 const zcu = cg.zcu;
48505187
4851 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5188 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4852 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;5189 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
...@@ -4898,14 +5235,48 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4898,14 +5235,48 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4898 const info = cg.arithmeticTypeInfo(result_ty);5235 const info = cg.arithmeticTypeInfo(result_ty);
4899 assert(info.class == .float); // .mul_add is only emitted for floats5236 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);
4902 return try result.materialize(cg);5273 return try result.materialize(cg);
4903}5274}
49045275
4905fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {5276fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {
4906 if (cg.liveness.isUnused(inst)) return null;5277 if (cg.liveness.isUnused(inst)) return null;
49075278
4908 const zcu = cg.module.zcu;5279 const zcu = cg.zcu;
4909 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5280 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4910 const operand = try cg.temporary(ty_op.operand);5281 const operand = try cg.temporary(ty_op.operand);
49115282
...@@ -4948,7 +5319,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4948,7 +5319,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4948}5319}
49495320
4950fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5321fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4951 const zcu = cg.module.zcu;5322 const zcu = cg.zcu;
4952 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;5323 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
4953 const operand = try cg.resolve(reduce.operand);5324 const operand = try cg.resolve(reduce.operand);
4954 const operand_ty = cg.typeOf(reduce.operand);5325 const operand_ty = cg.typeOf(reduce.operand);
...@@ -5016,7 +5387,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5016,7 +5387,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5016}5387}
50175388
5018fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5389fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5019 const zcu = cg.module.zcu;5390 const zcu = cg.zcu;
5020 const gpa = zcu.gpa;5391 const gpa = zcu.gpa;
50215392
5022 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);5393 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);
...@@ -5041,7 +5412,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5041,7 +5412,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5041}5412}
50425413
5043fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5414fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5044 const zcu = cg.module.zcu;5415 const zcu = cg.zcu;
5045 const gpa = zcu.gpa;5416 const gpa = zcu.gpa;
50465417
5047 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);5418 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);
...@@ -5060,7 +5431,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5060,7 +5431,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5060 id.* = switch (mask_elem.unwrap()) {5431 id.* = switch (mask_elem.unwrap()) {
5061 .a_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_a, idx),5432 .a_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_a, idx),
5062 .b_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_b, idx),5433 .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),
5064 };5435 };
5065 }5436 }
50665437
...@@ -5074,8 +5445,8 @@ fn accessChainId(...@@ -5074,8 +5445,8 @@ fn accessChainId(
5074 base: Id,5445 base: Id,
5075 indices: []const Id,5446 indices: []const Id,
5076) !Id {5447) !Id {
5077 const result_id = cg.module.allocId();5448 const result_id = cg.allocId();
5078 try cg.body.emit(cg.module.gpa, .OpInBoundsAccessChain, .{5449 try cg.body.emit(cg.gpa, .OpInBoundsAccessChain, .{
5079 .id_result_type = result_ty_id,5450 .id_result_type = result_ty_id,
5080 .id_result = result_id,5451 .id_result = result_id,
5081 .base = base,5452 .base = base,
...@@ -5094,7 +5465,7 @@ fn accessChain(...@@ -5094,7 +5465,7 @@ fn accessChain(
5094 base: Id,5465 base: Id,
5095 indices: []const u32,5466 indices: []const u32,
5096) !Id {5467) !Id {
5097 const gpa = cg.module.gpa;5468 const gpa = cg.gpa;
5098 const scratch_top = cg.id_scratch.items.len;5469 const scratch_top = cg.id_scratch.items.len;
5099 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);5470 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
5100 const ids = try cg.id_scratch.addManyAsSlice(gpa, indices.len);5471 const ids = try cg.id_scratch.addManyAsSlice(gpa, indices.len);
...@@ -5111,8 +5482,8 @@ fn ptrAccessChain(...@@ -5111,8 +5482,8 @@ fn ptrAccessChain(
5111 element: Id,5482 element: Id,
5112 indices: []const u32,5483 indices: []const u32,
5113) !Id {5484) !Id {
5114 const gpa = cg.module.gpa;5485 const gpa = cg.gpa;
5115 const target = cg.module.zcu.getTarget();5486 const target = cg.zcu.getTarget();
51165487
5117 const scratch_top = cg.id_scratch.items.len;5488 const scratch_top = cg.id_scratch.items.len;
5118 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);5489 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
...@@ -5121,7 +5492,7 @@ fn ptrAccessChain(...@@ -5121,7 +5492,7 @@ fn ptrAccessChain(
5121 id.* = try cg.constInt(.u32, index);5492 id.* = try cg.constInt(.u32, index);
5122 }5493 }
51235494
5124 const result_id = cg.module.allocId();5495 const result_id = cg.allocId();
5125 switch (target.os.tag) {5496 switch (target.os.tag) {
5126 .opencl, .amdhsa => {5497 .opencl, .amdhsa => {
5127 try cg.body.emit(gpa, .OpInBoundsPtrAccessChain, .{5498 try cg.body.emit(gpa, .OpInBoundsPtrAccessChain, .{
...@@ -5147,7 +5518,7 @@ fn ptrAccessChain(...@@ -5147,7 +5518,7 @@ fn ptrAccessChain(
5147}5518}
51485519
5149fn ptrAdd(cg: *CodeGen, result_ty: Type, ptr_ty: Type, ptr_id: Id, offset_id: Id) !Id {5520fn 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;
5151 const result_ty_id = try cg.resolveType(result_ty, .direct);5522 const result_ty_id = try cg.resolveType(result_ty, .direct);
51525523
5153 switch (ptr_ty.ptrSize(zcu)) {5524 switch (ptr_ty.ptrSize(zcu)) {
...@@ -5188,8 +5559,8 @@ fn airPtrSub(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5188,8 +5559,8 @@ fn airPtrSub(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5188 const offset_ty_id = try cg.resolveType(offset_ty, .direct);5559 const offset_ty_id = try cg.resolveType(offset_ty, .direct);
5189 const result_ty = cg.typeOfIndex(inst);5560 const result_ty = cg.typeOfIndex(inst);
51905561
5191 const negative_offset_id = cg.module.allocId();5562 const negative_offset_id = cg.allocId();
5192 try cg.body.emit(cg.module.gpa, .OpSNegate, .{5563 try cg.body.emit(cg.gpa, .OpSNegate, .{
5193 .id_result_type = offset_ty_id,5564 .id_result_type = offset_ty_id,
5194 .id_result = negative_offset_id,5565 .id_result = negative_offset_id,
5195 .operand = offset_id,5566 .operand = offset_id,
...@@ -5203,9 +5574,9 @@ fn cmp(...@@ -5203,9 +5574,9 @@ fn cmp(
5203 lhs: Temporary,5574 lhs: Temporary,
5204 rhs: Temporary,5575 rhs: Temporary,
5205) !Temporary {5576) !Temporary {
5206 const gpa = cg.module.gpa;5577 const gpa = cg.gpa;
5207 const pt = cg.pt;5578 const pt = cg.pt;
5208 const zcu = cg.module.zcu;5579 const zcu = cg.zcu;
5209 const scalar_ty = lhs.ty.scalarType(zcu);5580 const scalar_ty = lhs.ty.scalarType(zcu);
5210 const is_vector = lhs.ty.isVector(zcu);5581 const is_vector = lhs.ty.isVector(zcu);
52115582
...@@ -5234,14 +5605,14 @@ fn cmp(...@@ -5234,14 +5605,14 @@ fn cmp(
52345605
5235 const usize_ty_id = try cg.resolveType(.usize, .direct);5606 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();
5238 try cg.body.emit(gpa, .OpConvertPtrToU, .{5609 try cg.body.emit(gpa, .OpConvertPtrToU, .{
5239 .id_result_type = usize_ty_id,5610 .id_result_type = usize_ty_id,
5240 .id_result = lhs_int_id,5611 .id_result = lhs_int_id,
5241 .pointer = try lhs.materialize(cg),5612 .pointer = try lhs.materialize(cg),
5242 });5613 });
52435614
5244 const rhs_int_id = cg.module.allocId();5615 const rhs_int_id = cg.allocId();
5245 try cg.body.emit(gpa, .OpConvertPtrToU, .{5616 try cg.body.emit(gpa, .OpConvertPtrToU, .{
5246 .id_result_type = usize_ty_id,5617 .id_result_type = usize_ty_id,
5247 .id_result = rhs_int_id,5618 .id_result = rhs_int_id,
...@@ -5410,14 +5781,29 @@ fn bitCast(...@@ -5410,14 +5781,29 @@ fn bitCast(
5410 src_ty: Type,5781 src_ty: Type,
5411 src_id: Id,5782 src_id: Id,
5412) !Id {5783) !Id {
5413 const gpa = cg.module.gpa;5784 const gpa = cg.gpa;
5414 const zcu = cg.module.zcu;5785 const zcu = cg.zcu;
5415 const target = zcu.getTarget();5786 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);
5419 const result_id = blk: {5795 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
5422 // TODO: Some more cases are missing here5808 // TODO: Some more cases are missing here
5423 // See fn bitCast in llvm.zig5809 // See fn bitCast in llvm.zig
...@@ -5432,7 +5818,7 @@ fn bitCast(...@@ -5432,7 +5818,7 @@ fn bitCast(
5432 }5818 }
5433 }5819 }
54345820
5435 const result_id = cg.module.allocId();5821 const result_id = cg.allocId();
5436 try cg.body.emit(gpa, .OpConvertUToPtr, .{5822 try cg.body.emit(gpa, .OpConvertUToPtr, .{
5437 .id_result_type = dst_ty_id,5823 .id_result_type = dst_ty_id,
5438 .id_result = result_id,5824 .id_result = result_id,
...@@ -5446,7 +5832,7 @@ fn bitCast(...@@ -5446,7 +5832,7 @@ fn bitCast(
5446 // otherwise use a temporary and perform a pointer cast.5832 // otherwise use a temporary and perform a pointer cast.
5447 const can_bitcast = (src_ty.isNumeric(zcu) and dst_ty.isNumeric(zcu)) or (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu));5833 const can_bitcast = (src_ty.isNumeric(zcu) and dst_ty.isNumeric(zcu)) or (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu));
5448 if (can_bitcast) {5834 if (can_bitcast) {
5449 const result_id = cg.module.allocId();5835 const result_id = cg.allocId();
5450 try cg.body.emit(gpa, .OpBitcast, .{5836 try cg.body.emit(gpa, .OpBitcast, .{
5451 .id_result_type = dst_ty_id,5837 .id_result_type = dst_ty_id,
5452 .id_result = result_id,5838 .id_result = result_id,
...@@ -5456,12 +5842,24 @@ fn bitCast(...@@ -5456,12 +5842,24 @@ fn bitCast(
5456 break :blk result_id;5842 break :blk result_id;
5457 }5843 }
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
5461 const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect);5859 const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect);
5462 const tmp_id = try cg.alloc(src_ty_indirect_id, null);5860 const tmp_id = try cg.alloc(src_ty_indirect_id, null);
5463 try cg.store(src_ty, tmp_id, src_id, .{});5861 try cg.store(src_ty, tmp_id, src_id, .{});
5464 const casted_ptr_id = cg.module.allocId();5862 const casted_ptr_id = cg.allocId();
5465 try cg.body.emit(gpa, .OpBitcast, .{5863 try cg.body.emit(gpa, .OpBitcast, .{
5466 .id_result_type = dst_ptr_ty_id,5864 .id_result_type = dst_ptr_ty_id,
5467 .id_result = casted_ptr_id,5865 .id_result = casted_ptr_id,
...@@ -5492,8 +5890,13 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5492,8 +5890,13 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5492 const result = try cg.intFromBool(operand, .u1);5890 const result = try cg.intFromBool(operand, .u1);
5493 return try result.materialize(cg);5891 return try result.materialize(cg);
5494 }5892 }
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 }
5495 const operand_id = try cg.resolve(ty_op.operand);5899 const operand_id = try cg.resolve(ty_op.operand);
5496 if (cg.virtual_allocas.contains(operand_id)) return operand_id;
5497 return try cg.bitCast(result_ty, operand_ty, operand_id);5900 return try cg.bitCast(result_ty, operand_ty, operand_id);
5498}5901}
54995902
...@@ -5509,19 +5912,19 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5509,19 +5912,19 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5509 const dst_composite = dst_info.class == .composite_integer;5912 const dst_composite = dst_info.class == .composite_integer;
55105913
5511 if (src_composite or dst_composite) {5914 if (src_composite or dst_composite) {
5512 const gpa = cg.module.gpa;5915 const gpa = cg.gpa;
5513 const scratch_top = cg.id_scratch.items.len;5916 const scratch_top = cg.id_scratch.items.len;
5514 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);5917 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
55155918
5516 if (src_composite and dst_composite) {5919 if (src_composite and dst_composite) {
5517 const src_id = try src.materialize(cg);5920 const src_id = try src.materialize(cg);
5518 const src_n: u16 = src_info.backing_bits / Module.big_int_bits;5921 const src_n: u16 = src_info.backing_bits / big_int_bits;
5519 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;5922 const dst_n: u16 = dst_info.backing_bits / big_int_bits;
5520 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);5923 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
5521 const min_n = @min(src_n, dst_n);5924 const min_n = @min(src_n, dst_n);
5522 const u32_ty_id = try cg.resolveType(.u32, .direct);5925 const u32_ty_id = try cg.resolveType(.u32, .direct);
5523 for (0..min_n) |i| {5926 for (0..min_n) |i| {
5524 result_limbs[i] = cg.module.allocId();5927 result_limbs[i] = cg.allocId();
5525 try cg.body.emit(gpa, .OpCompositeExtract, .{5928 try cg.body.emit(gpa, .OpCompositeExtract, .{
5526 .id_result_type = u32_ty_id,5929 .id_result_type = u32_ty_id,
5527 .id_result = result_limbs[i],5930 .id_result = result_limbs[i],
...@@ -5533,20 +5936,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5533,20 +5936,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5533 const fill = if (src_info.signedness == .signed) blk: {5936 const fill = if (src_info.signedness == .signed) blk: {
5534 const i32_ty_id = try cg.resolveType(.i32, .direct);5937 const i32_ty_id = try cg.resolveType(.i32, .direct);
5535 const msb = result_limbs[src_n - 1];5938 const msb = result_limbs[src_n - 1];
5536 const msb_signed = cg.module.allocId();5939 const msb_signed = cg.allocId();
5537 try cg.body.emit(gpa, .OpBitcast, .{5940 try cg.body.emit(gpa, .OpBitcast, .{
5538 .id_result_type = i32_ty_id,5941 .id_result_type = i32_ty_id,
5539 .id_result = msb_signed,5942 .id_result = msb_signed,
5540 .operand = msb,5943 .operand = msb,
5541 });5944 });
5542 const shift31 = try cg.constInt(.i32, @as(i32, 31));5945 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5543 const sign_ext = cg.module.allocId();5946 const sign_ext = cg.allocId();
5544 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);5947 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5545 cg.body.writeOperand(Id, i32_ty_id);5948 .id_result_type = i32_ty_id,
5546 cg.body.writeOperand(Id, sign_ext);5949 .id_result = sign_ext,
5547 cg.body.writeOperand(Id, msb_signed);5950 .base = msb_signed,
5548 cg.body.writeOperand(Id, shift31);5951 .shift = shift31,
5549 const back = cg.module.allocId();5952 });
5953 const back = cg.allocId();
5550 try cg.body.emit(gpa, .OpBitcast, .{5954 try cg.body.emit(gpa, .OpBitcast, .{
5551 .id_result_type = u32_ty_id,5955 .id_result_type = u32_ty_id,
5552 .id_result = back,5956 .id_result = back,
...@@ -5565,7 +5969,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5565,7 +5969,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5565 const src_id = try src.materialize(cg);5969 const src_id = try src.materialize(cg);
5566 const u32_ty_id = try cg.resolveType(.u32, .direct);5970 const u32_ty_id = try cg.resolveType(.u32, .direct);
5567 if (dst_info.backing_bits <= 32) {5971 if (dst_info.backing_bits <= 32) {
5568 const limb0 = cg.module.allocId();5972 const limb0 = cg.allocId();
5569 try cg.body.emit(gpa, .OpCompositeExtract, .{5973 try cg.body.emit(gpa, .OpCompositeExtract, .{
5570 .id_result_type = u32_ty_id,5974 .id_result_type = u32_ty_id,
5571 .id_result = limb0,5975 .id_result = limb0,
...@@ -5580,14 +5984,14 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5580,14 +5984,14 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5580 converted;5984 converted;
5581 return try result.materialize(cg);5985 return try result.materialize(cg);
5582 } else {5986 } else {
5583 const limb0 = cg.module.allocId();5987 const limb0 = cg.allocId();
5584 try cg.body.emit(gpa, .OpCompositeExtract, .{5988 try cg.body.emit(gpa, .OpCompositeExtract, .{
5585 .id_result_type = u32_ty_id,5989 .id_result_type = u32_ty_id,
5586 .id_result = limb0,5990 .id_result = limb0,
5587 .composite = src_id,5991 .composite = src_id,
5588 .indexes = &.{@as(u32, 0)},5992 .indexes = &.{@as(u32, 0)},
5589 });5993 });
5590 const limb1 = cg.module.allocId();5994 const limb1 = cg.allocId();
5591 try cg.body.emit(gpa, .OpCompositeExtract, .{5995 try cg.body.emit(gpa, .OpCompositeExtract, .{
5592 .id_result_type = u32_ty_id,5996 .id_result_type = u32_ty_id,
5593 .id_result = limb1,5997 .id_result = limb1,
...@@ -5595,29 +5999,33 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5595,29 +5999,33 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5595 .indexes = &.{@as(u32, 1)},5999 .indexes = &.{@as(u32, 1)},
5596 });6000 });
5597 const u64_ty_id = try cg.resolveType(.u64, .direct);6001 const u64_ty_id = try cg.resolveType(.u64, .direct);
5598 const lo = cg.module.allocId();6002 const lo = cg.allocId();
5599 try cg.body.emitRaw(gpa, .OpUConvert, 3);6003 try cg.body.emit(gpa, .OpUConvert, .{
5600 cg.body.writeOperand(Id, u64_ty_id);6004 .id_result_type = u64_ty_id,
5601 cg.body.writeOperand(Id, lo);6005 .id_result = lo,
5602 cg.body.writeOperand(Id, limb0);6006 .unsigned_value = limb0,
5603 const hi = cg.module.allocId();6007 });
5604 try cg.body.emitRaw(gpa, .OpUConvert, 3);6008 const hi = cg.allocId();
5605 cg.body.writeOperand(Id, u64_ty_id);6009 try cg.body.emit(gpa, .OpUConvert, .{
5606 cg.body.writeOperand(Id, hi);6010 .id_result_type = u64_ty_id,
5607 cg.body.writeOperand(Id, limb1);6011 .id_result = hi,
6012 .unsigned_value = limb1,
6013 });
5608 const shift32 = try cg.constInt(.u64, @as(u64, 32));6014 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5609 const hi_shifted = cg.module.allocId();6015 const hi_shifted = cg.allocId();
5610 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);6016 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
5611 cg.body.writeOperand(Id, u64_ty_id);6017 .id_result_type = u64_ty_id,
5612 cg.body.writeOperand(Id, hi_shifted);6018 .id_result = hi_shifted,
5613 cg.body.writeOperand(Id, hi);6019 .base = hi,
5614 cg.body.writeOperand(Id, shift32);6020 .shift = shift32,
5615 const combined = cg.module.allocId();6021 });
5616 try cg.body.emitRaw(gpa, .OpBitwiseOr, 4);6022 const combined = cg.allocId();
5617 cg.body.writeOperand(Id, u64_ty_id);6023 try cg.body.emit(gpa, .OpBitwiseOr, .{
5618 cg.body.writeOperand(Id, combined);6024 .id_result_type = u64_ty_id,
5619 cg.body.writeOperand(Id, lo);6025 .id_result = combined,
5620 cg.body.writeOperand(Id, hi_shifted);6026 .operand_1 = lo,
6027 .operand_2 = hi_shifted,
6028 });
5621 const tmp: Temporary = .init(.u64, combined);6029 const tmp: Temporary = .init(.u64, combined);
5622 const converted = try cg.buildConvert(dst_ty, tmp);6030 const converted = try cg.buildConvert(dst_ty, tmp);
5623 const result = if (dst_info.bits < src_info.bits)6031 const result = if (dst_info.bits < src_info.bits)
...@@ -5627,7 +6035,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5627,7 +6035,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5627 return try result.materialize(cg);6035 return try result.materialize(cg);
5628 }6036 }
5629 } else {6037 } 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;
5631 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);6039 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
5632 const u32_ty_id = try cg.resolveType(.u32, .direct);6040 const u32_ty_id = try cg.resolveType(.u32, .direct);
56336041
...@@ -5637,44 +6045,48 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5637,44 +6045,48 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5637 } else {6045 } else {
5638 const src_as_u64 = try cg.buildConvert(.u64, src);6046 const src_as_u64 = try cg.buildConvert(.u64, src);
5639 const src_id = try src_as_u64.materialize(cg);6047 const src_id = try src_as_u64.materialize(cg);
5640 result_limbs[0] = cg.module.allocId();6048 result_limbs[0] = cg.allocId();
5641 try cg.body.emitRaw(gpa, .OpUConvert, 3);6049 try cg.body.emit(gpa, .OpUConvert, .{
5642 cg.body.writeOperand(Id, u32_ty_id);6050 .id_result_type = u32_ty_id,
5643 cg.body.writeOperand(Id, result_limbs[0]);6051 .id_result = result_limbs[0],
5644 cg.body.writeOperand(Id, src_id);6052 .unsigned_value = src_id,
6053 });
5645 const u64_ty_id = try cg.resolveType(.u64, .direct);6054 const u64_ty_id = try cg.resolveType(.u64, .direct);
5646 const shift32 = try cg.constInt(.u64, @as(u64, 32));6055 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5647 const hi = cg.module.allocId();6056 const hi = cg.allocId();
5648 try cg.body.emitRaw(gpa, .OpShiftRightLogical, 4);6057 try cg.body.emit(gpa, .OpShiftRightLogical, .{
5649 cg.body.writeOperand(Id, u64_ty_id);6058 .id_result_type = u64_ty_id,
5650 cg.body.writeOperand(Id, hi);6059 .id_result = hi,
5651 cg.body.writeOperand(Id, src_id);6060 .base = src_id,
5652 cg.body.writeOperand(Id, shift32);6061 .shift = shift32,
5653 result_limbs[1] = cg.module.allocId();6062 });
5654 try cg.body.emitRaw(gpa, .OpUConvert, 3);6063 result_limbs[1] = cg.allocId();
5655 cg.body.writeOperand(Id, u32_ty_id);6064 try cg.body.emit(gpa, .OpUConvert, .{
5656 cg.body.writeOperand(Id, result_limbs[1]);6065 .id_result_type = u32_ty_id,
5657 cg.body.writeOperand(Id, hi);6066 .id_result = result_limbs[1],
6067 .unsigned_value = hi,
6068 });
5658 }6069 }
5659 // Sign/zero-extend remaining limbs.6070 // Sign/zero-extend remaining limbs.
5660 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;6071 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;
5661 const fill = if (src_info.signedness == .signed) blk: {6072 const fill = if (src_info.signedness == .signed) blk: {
5662 const i32_ty_id = try cg.resolveType(.i32, .direct);6073 const i32_ty_id = try cg.resolveType(.i32, .direct);
5663 const msb = result_limbs[fill_start - 1];6074 const msb = result_limbs[fill_start - 1];
5664 const msb_signed = cg.module.allocId();6075 const msb_signed = cg.allocId();
5665 try cg.body.emit(gpa, .OpBitcast, .{6076 try cg.body.emit(gpa, .OpBitcast, .{
5666 .id_result_type = i32_ty_id,6077 .id_result_type = i32_ty_id,
5667 .id_result = msb_signed,6078 .id_result = msb_signed,
5668 .operand = msb,6079 .operand = msb,
5669 });6080 });
5670 const shift31 = try cg.constInt(.i32, @as(i32, 31));6081 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5671 const sign_ext = cg.module.allocId();6082 const sign_ext = cg.allocId();
5672 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);6083 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5673 cg.body.writeOperand(Id, i32_ty_id);6084 .id_result_type = i32_ty_id,
5674 cg.body.writeOperand(Id, sign_ext);6085 .id_result = sign_ext,
5675 cg.body.writeOperand(Id, msb_signed);6086 .base = msb_signed,
5676 cg.body.writeOperand(Id, shift31);6087 .shift = shift31,
5677 const back = cg.module.allocId();6088 });
6089 const back = cg.allocId();
5678 try cg.body.emit(gpa, .OpBitcast, .{6090 try cg.body.emit(gpa, .OpBitcast, .{
5679 .id_result_type = u32_ty_id,6091 .id_result_type = u32_ty_id,
5680 .id_result = back,6092 .id_result = back,
...@@ -5715,8 +6127,8 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5715,8 +6127,8 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
57156127
5716fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {6128fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
5717 const result_type_id = try cg.resolveType(.usize, .direct);6129 const result_type_id = try cg.resolveType(.usize, .direct);
5718 const result_id = cg.module.allocId();6130 const result_id = cg.allocId();
5719 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{6131 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
5720 .id_result_type = result_type_id,6132 .id_result_type = result_type_id,
5721 .id_result = result_id,6133 .id_result = result_id,
5722 .pointer = operand_id,6134 .pointer = operand_id,
...@@ -5725,17 +6137,13 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {...@@ -5725,17 +6137,13 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
5725}6137}
57266138
5727fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6139fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6140 const gpa = cg.gpa;
5728 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6141 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5729 const operand_ty = cg.typeOf(ty_op.operand);6142 const operand_ty = cg.typeOf(ty_op.operand);
5730 const operand_id = try cg.resolve(ty_op.operand);6143 const operand_id = try cg.resolve(ty_op.operand);
5731 const result_ty = cg.typeOfIndex(inst);6144 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;
5737 const operand_info = cg.arithmeticTypeInfo(operand_ty);6145 const operand_info = cg.arithmeticTypeInfo(operand_ty);
5738 const result_id = cg.module.allocId();6146 const result_id = cg.allocId();
5739 const result_ty_id = try cg.resolveType(result_ty, .direct);6147 const result_ty_id = try cg.resolveType(result_ty, .direct);
5740 switch (operand_info.signedness) {6148 switch (operand_info.signedness) {
5741 .signed => try cg.body.emit(gpa, .OpConvertSToF, .{6149 .signed => try cg.body.emit(gpa, .OpConvertSToF, .{
...@@ -5753,17 +6161,13 @@ fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id)...@@ -5753,17 +6161,13 @@ fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id)
5753}6161}
57546162
5755fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6163fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6164 const gpa = cg.gpa;
5756 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6165 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5757 const operand_id = try cg.resolve(ty_op.operand);6166 const operand_id = try cg.resolve(ty_op.operand);
5758 const result_ty = cg.typeOfIndex(inst);6167 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;
5764 const result_info = cg.arithmeticTypeInfo(result_ty);6168 const result_info = cg.arithmeticTypeInfo(result_ty);
5765 const result_ty_id = try cg.resolveType(result_ty, .direct);6169 const result_ty_id = try cg.resolveType(result_ty, .direct);
5766 const result_id = cg.module.allocId();6170 const result_id = cg.allocId();
5767 switch (result_info.signedness) {6171 switch (result_info.signedness) {
5768 .signed => try cg.body.emit(gpa, .OpConvertFToS, .{6172 .signed => try cg.body.emit(gpa, .OpConvertFToS, .{
5769 .id_result_type = result_ty_id,6173 .id_result_type = result_ty_id,
...@@ -5815,7 +6219,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5815,7 +6219,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5815}6219}
58166220
5817fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6221fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5818 const zcu = cg.module.zcu;6222 const zcu = cg.zcu;
5819 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6223 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5820 const array_ptr_ty = cg.typeOf(ty_op.operand);6224 const array_ptr_ty = cg.typeOf(ty_op.operand);
5821 const array_ty = array_ptr_ty.childType(zcu);6225 const array_ty = array_ptr_ty.childType(zcu);
...@@ -5849,11 +6253,11 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5849,11 +6253,11 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5849}6253}
58506254
5851fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6255fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5852 const gpa = cg.module.gpa;6256 const gpa = cg.gpa;
5853 const pt = cg.pt;6257 const pt = cg.pt;
5854 const zcu = cg.module.zcu;6258 const zcu = cg.zcu;
5855 const ip = &zcu.intern_pool;6259 const ip = &zcu.intern_pool;
5856 const target = cg.module.zcu.getTarget();6260 const target = cg.zcu.getTarget();
5857 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6261 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5858 const result_ty = cg.typeOfIndex(inst);6262 const result_ty = cg.typeOfIndex(inst);
5859 const len: usize = @intCast(result_ty.arrayLen(zcu));6263 const len: usize = @intCast(result_ty.arrayLen(zcu));
...@@ -5978,23 +6382,8 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5978,23 +6382,8 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5978 }6382 }
5979}6383}
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
5996fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id {6385fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
5997 const zcu = cg.module.zcu;6386 const zcu = cg.zcu;
5998 if (ty.isSlice(zcu)) {6387 if (ty.isSlice(zcu)) {
5999 const ptr_ty = ty.slicePtrFieldType(zcu);6388 const ptr_ty = ty.slicePtrFieldType(zcu);
6000 return cg.extractField(ptr_ty, operand_id, 0);6389 return cg.extractField(ptr_ty, operand_id, 0);
...@@ -6010,8 +6399,17 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6010,8 +6399,17 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) !void {
6010 const src_ty = cg.typeOf(bin_op.rhs);6399 const src_ty = cg.typeOf(bin_op.rhs);
6011 const dest_ptr = try cg.sliceOrArrayPtr(dest_slice, dest_ty);6400 const dest_ptr = try cg.sliceOrArrayPtr(dest_slice, dest_ty);
6012 const src_ptr = try cg.sliceOrArrayPtr(src_slice, src_ty);6401 const src_ptr = try cg.sliceOrArrayPtr(src_slice, src_ty);
6013 const len = try cg.sliceOrArrayLen(dest_slice, dest_ty);6402 const len = switch (dest_ty.ptrSize(cg.zcu)) {
6014 try cg.body.emit(cg.module.gpa, .OpCopyMemorySized, .{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, .{
6015 .target = dest_ptr,6413 .target = dest_ptr,
6016 .source = src_ptr,6414 .source = src_ptr,
6017 .size = len,6415 .size = len,
...@@ -6031,12 +6429,12 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {...@@ -6031,12 +6429,12 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {
6031}6429}
60326430
6033fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6431fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6034 const gpa = cg.module.gpa;6432 const gpa = cg.gpa;
6035 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6433 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6036 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;6434 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
6037 const struct_ptr_id = try cg.resolve(extra.struct_operand);6435 const struct_ptr_id = try cg.resolve(extra.struct_operand);
6038 const u32_ty_id = try cg.module.intType(.unsigned, 32);6436 const u32_ty_id = try cg.intType(.unsigned, 32);
6039 const result_id = cg.module.allocId();6437 const result_id = cg.allocId();
6040 try cg.body.emit(gpa, .OpArrayLength, .{6438 try cg.body.emit(gpa, .OpArrayLength, .{
6041 .id_result_type = u32_ty_id,6439 .id_result_type = u32_ty_id,
6042 .id_result = result_id,6440 .id_result = result_id,
...@@ -6047,7 +6445,7 @@ fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6047,7 +6445,7 @@ fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6047}6445}
60486446
6049fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6447fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6050 const zcu = cg.module.zcu;6448 const zcu = cg.zcu;
6051 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6449 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6052 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;6450 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
6053 const slice_ty = cg.typeOf(bin_op.lhs);6451 const slice_ty = cg.typeOf(bin_op.lhs);
...@@ -6064,7 +6462,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6064,7 +6462,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6064}6462}
60656463
6066fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6464fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6067 const zcu = cg.module.zcu;6465 const zcu = cg.zcu;
6068 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6466 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6069 const slice_ty = cg.typeOf(bin_op.lhs);6467 const slice_ty = cg.typeOf(bin_op.lhs);
6070 if (!slice_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;6468 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 {...@@ -6081,11 +6479,11 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6081}6479}
60826480
6083fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {6481fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
6084 const zcu = cg.module.zcu;6482 const zcu = cg.zcu;
6085 // Construct new pointer type for the resulting pointer6483 // Construct new pointer type for the resulting pointer
6086 const elem_ty = ptr_ty.indexableElem(zcu);6484 const elem_ty = ptr_ty.indexableElem(zcu);
6087 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);6485 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)));
6089 if (ptr_ty.isSinglePointer(zcu)) {6487 if (ptr_ty.isSinglePointer(zcu)) {
6090 // Pointer-to-array. In this case, the resulting pointer is not of the same type6488 // Pointer-to-array. In this case, the resulting pointer is not of the same type
6091 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.6489 // 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 {...@@ -6097,7 +6495,7 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
6097}6495}
60986496
6099fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6497fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6100 const zcu = cg.module.zcu;6498 const zcu = cg.zcu;
6101 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6499 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6102 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;6500 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
6103 const src_ptr_ty = cg.typeOf(bin_op.lhs);6501 const src_ptr_ty = cg.typeOf(bin_op.lhs);
...@@ -6111,8 +6509,8 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6111,8 +6509,8 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6111}6509}
61126510
6113fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6511fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6114 const gpa = cg.module.gpa;6512 const gpa = cg.gpa;
6115 const zcu = cg.module.zcu;6513 const zcu = cg.zcu;
6116 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6514 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6117 const array_ty = cg.typeOf(bin_op.lhs);6515 const array_ty = cg.typeOf(bin_op.lhs);
6118 const elem_ty = array_ty.childType(zcu);6516 const elem_ty = array_ty.childType(zcu);
...@@ -6127,10 +6525,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6127,10 +6525,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6127 const elem_repr: Repr = if (is_vector) .direct else .indirect;6525 const elem_repr: Repr = if (is_vector) .direct else .indirect;
6128 const array_ty_id = try cg.resolveType(array_ty, .direct);6526 const array_ty_id = try cg.resolveType(array_ty, .direct);
6129 const elem_ty_id = try cg.resolveType(elem_ty, elem_repr);6527 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);6528 const ptr_array_ty_id = try cg.ptrType(array_ty_id, .function);
6131 const ptr_elem_ty_id = try cg.module.ptrType(elem_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();
6134 try cg.prologue.emit(gpa, .OpVariable, .{6532 try cg.prologue.emit(gpa, .OpVariable, .{
6135 .id_result_type = ptr_array_ty_id,6533 .id_result_type = ptr_array_ty_id,
6136 .id_result = tmp_id,6534 .id_result = tmp_id,
...@@ -6144,7 +6542,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6144,7 +6542,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61446542
6145 const elem_ptr_id = try cg.accessChainId(ptr_elem_ty_id, tmp_id, &.{index_id});6543 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();
6148 try cg.body.emit(gpa, .OpLoad, .{6546 try cg.body.emit(gpa, .OpLoad, .{
6149 .id_result_type = try cg.resolveType(elem_ty, elem_repr),6547 .id_result_type = try cg.resolveType(elem_ty, elem_repr),
6150 .id_result = result_id,6548 .id_result = result_id,
...@@ -6163,7 +6561,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6163,7 +6561,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6163}6561}
61646562
6165fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6563fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6166 const zcu = cg.module.zcu;6564 const zcu = cg.zcu;
6167 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6565 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6168 const ptr_ty = cg.typeOf(bin_op.lhs);6566 const ptr_ty = cg.typeOf(bin_op.lhs);
6169 const elem_ty = cg.typeOfIndex(inst);6567 const elem_ty = cg.typeOfIndex(inst);
...@@ -6174,7 +6572,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6174,7 +6572,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6174}6572}
61756573
6176fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {6574fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
6177 const zcu = cg.module.zcu;6575 const zcu = cg.zcu;
6178 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6576 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6179 const un_ptr_ty = cg.typeOf(bin_op.lhs);6577 const un_ptr_ty = cg.typeOf(bin_op.lhs);
6180 const un_ty = un_ptr_ty.childType(zcu);6578 const un_ty = un_ptr_ty.childType(zcu);
...@@ -6184,7 +6582,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6184,7 +6582,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
61846582
6185 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;6583 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
6186 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);6584 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
6189 const union_ptr_id = try cg.resolve(bin_op.lhs);6587 const union_ptr_id = try cg.resolve(bin_op.lhs);
6190 const new_tag_id = try cg.resolve(bin_op.rhs);6588 const new_tag_id = try cg.resolve(bin_op.rhs);
...@@ -6201,7 +6599,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6201,7 +6599,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6201 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6599 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6202 const un_ty = cg.typeOf(ty_op.operand);6600 const un_ty = cg.typeOf(ty_op.operand);
62036601
6204 const zcu = cg.module.zcu;6602 const zcu = cg.zcu;
6205 const layout = cg.unionLayout(un_ty);6603 const layout = cg.unionLayout(un_ty);
6206 if (layout.tag_size == 0) return null;6604 if (layout.tag_size == 0) return null;
62076605
...@@ -6225,7 +6623,7 @@ fn unionInit(...@@ -6225,7 +6623,7 @@ fn unionInit(
6225 // Note: The result here is not cached, because it generates runtime code.6623 // Note: The result here is not cached, because it generates runtime code.
62266624
6227 const pt = cg.pt;6625 const pt = cg.pt;
6228 const zcu = cg.module.zcu;6626 const zcu = cg.zcu;
6229 const ip = &zcu.intern_pool;6627 const ip = &zcu.intern_pool;
6230 const union_ty = zcu.typeToUnion(ty).?;6628 const union_ty = zcu.typeToUnion(ty).?;
6231 const tag_ty: Type = .fromInterned(union_ty.enum_tag_type);6629 const tag_ty: Type = .fromInterned(union_ty.enum_tag_type);
...@@ -6250,7 +6648,7 @@ fn unionInit(...@@ -6250,7 +6648,7 @@ fn unionInit(
62506648
6251 if (layout.tag_size != 0) {6649 if (layout.tag_size != 0) {
6252 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);6650 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);
6254 const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});6652 const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
6255 const tag_id = try cg.constInt(tag_ty, tag_int);6653 const tag_id = try cg.constInt(tag_ty, tag_int);
6256 try cg.store(tag_ty, ptr_id, tag_id, .{});6654 try cg.store(tag_ty, ptr_id, tag_id, .{});
...@@ -6258,13 +6656,13 @@ fn unionInit(...@@ -6258,13 +6656,13 @@ fn unionInit(
62586656
6259 if (payload_ty.hasRuntimeBits(zcu)) {6657 if (payload_ty.hasRuntimeBits(zcu)) {
6260 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);6658 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);
6262 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});6660 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
6263 const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty)) blk: {6661 const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty)) blk: {
6264 const payload_ty_id = try cg.resolveType(payload_ty, .indirect);6662 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);6663 const active_pl_ptr_ty_id = try cg.ptrType(payload_ty_id, .function);
6266 const active_pl_ptr_id = cg.module.allocId();6664 const active_pl_ptr_id = cg.allocId();
6267 try cg.body.emit(cg.module.gpa, .OpBitcast, .{6665 try cg.body.emit(cg.gpa, .OpBitcast, .{
6268 .id_result_type = active_pl_ptr_ty_id,6666 .id_result_type = active_pl_ptr_ty_id,
6269 .id_result = active_pl_ptr_id,6667 .id_result = active_pl_ptr_id,
6270 .operand = pl_ptr_id,6668 .operand = pl_ptr_id,
...@@ -6284,7 +6682,7 @@ fn unionInit(...@@ -6284,7 +6682,7 @@ fn unionInit(
6284}6682}
62856683
6286fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6684fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6287 const zcu = cg.module.zcu;6685 const zcu = cg.zcu;
6288 const ip = &zcu.intern_pool;6686 const ip = &zcu.intern_pool;
6289 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6687 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6290 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;6688 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
...@@ -6301,7 +6699,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6301,7 +6699,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63016699
6302fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6700fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6303 const pt = cg.pt;6701 const pt = cg.pt;
6304 const zcu = cg.module.zcu;6702 const zcu = cg.zcu;
6305 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6703 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6306 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;6704 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 {...@@ -6316,7 +6714,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6316 .@"struct" => switch (object_ty.containerLayout(zcu)) {6714 .@"struct" => switch (object_ty.containerLayout(zcu)) {
6317 .@"packed" => {6715 .@"packed" => {
6318 const struct_ty = zcu.typeToPackedStruct(object_ty).?;6716 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";
6320 const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index);6718 const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index);
6321 // We use the same int type the packed struct is backed by, because even though it would6719 // We use the same int type the packed struct is backed by, because even though it would
6322 // be valid SPIR-V to use an smaller type like u16, some implementations like PoCL will complain.6720 // 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 {...@@ -6329,7 +6727,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6329 const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1);6727 const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1);
6330 const masked = try cg.buildBinary(.OpBitwiseAnd, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });6728 const masked = try cg.buildBinary(.OpBitwiseAnd, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });
6331 const result_id = blk: {6729 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)
6333 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));6731 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));
6334 const trunc = try cg.buildConvert(field_int_ty, masked);6732 const trunc = try cg.buildConvert(field_int_ty, masked);
6335 break :blk try trunc.materialize(cg);6733 break :blk try trunc.materialize(cg);
...@@ -6353,7 +6751,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6353,7 +6751,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6353 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },6751 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },
6354 );6752 );
6355 const result_id = blk: {6753 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")
6357 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));6755 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));
6358 const trunc = try cg.buildConvert(int_ty, masked);6756 const trunc = try cg.buildConvert(int_ty, masked);
6359 break :blk try trunc.materialize(cg);6757 break :blk try trunc.materialize(cg);
...@@ -6372,13 +6770,13 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6372,13 +6770,13 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6372 try cg.store(object_ty, tmp_id, object_id, .{});6770 try cg.store(object_ty, tmp_id, object_id, .{});
63736771
6374 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);6772 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);
6376 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});6774 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
63776775
6378 const field_ty_id = try cg.resolveType(field_ty, .indirect);6776 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);6777 const active_pl_ptr_ty_id = try cg.ptrType(field_ty_id, .function);
6380 const active_pl_ptr_id = cg.module.allocId();6778 const active_pl_ptr_id = cg.allocId();
6381 try cg.body.emit(cg.module.gpa, .OpBitcast, .{6779 try cg.body.emit(cg.gpa, .OpBitcast, .{
6382 .id_result_type = active_pl_ptr_ty_id,6780 .id_result_type = active_pl_ptr_ty_id,
6383 .id_result = active_pl_ptr_id,6781 .id_result = active_pl_ptr_id,
6384 .operand = pl_ptr_id,6782 .operand = pl_ptr_id,
...@@ -6391,7 +6789,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6391,7 +6789,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6391}6789}
63926790
6393fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6791fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6394 const zcu = cg.module.zcu;6792 const zcu = cg.zcu;
6395 const target = zcu.getTarget();6793 const target = zcu.getTarget();
6396 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6794 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6397 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;6795 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
...@@ -6424,8 +6822,8 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6424,8 +6822,8 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6424 }6822 }
6425 }6823 }
64266824
6427 const base_ptr = cg.module.allocId();6825 const base_ptr = cg.allocId();
6428 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{6826 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
6429 .id_result_type = result_ty_id,6827 .id_result_type = result_ty_id,
6430 .id_result = base_ptr,6828 .id_result = base_ptr,
6431 .integer_value = base_ptr_int,6829 .integer_value = base_ptr_int,
...@@ -6443,7 +6841,7 @@ fn structFieldPtr(...@@ -6443,7 +6841,7 @@ fn structFieldPtr(
6443) !Id {6841) !Id {
6444 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);6842 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);
64456843
6446 const zcu = cg.module.zcu;6844 const zcu = cg.zcu;
6447 const object_ty = object_ptr_ty.childType(zcu);6845 const object_ty = object_ptr_ty.childType(zcu);
6448 switch (object_ty.zigTypeTag(zcu)) {6846 switch (object_ty.zigTypeTag(zcu)) {
6449 .pointer => {6847 .pointer => {
...@@ -6455,8 +6853,8 @@ fn structFieldPtr(...@@ -6455,8 +6853,8 @@ fn structFieldPtr(
6455 const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu);6853 const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu);
6456 if (byte_offset == 0) return object_ptr;6854 if (byte_offset == 0) return object_ptr;
6457 const usize_ty_id = try cg.resolveType(.usize, .direct);6855 const usize_ty_id = try cg.resolveType(.usize, .direct);
6458 const base_int = cg.module.allocId();6856 const base_int = cg.allocId();
6459 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{6857 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
6460 .id_result_type = usize_ty_id,6858 .id_result_type = usize_ty_id,
6461 .id_result = base_int,6859 .id_result = base_int,
6462 .pointer = object_ptr,6860 .pointer = object_ptr,
...@@ -6464,8 +6862,8 @@ fn structFieldPtr(...@@ -6464,8 +6862,8 @@ fn structFieldPtr(
6464 const offset_id = try cg.constInt(.usize, byte_offset);6862 const offset_id = try cg.constInt(.usize, byte_offset);
6465 const adjusted = try cg.buildBinary(.OpIAdd, .{ .ty = .usize, .value = .{ .singleton = base_int } }, .{ .ty = .usize, .value = .{ .singleton = offset_id } });6863 const adjusted = try cg.buildBinary(.OpIAdd, .{ .ty = .usize, .value = .{ .singleton = base_int } }, .{ .ty = .usize, .value = .{ .singleton = offset_id } });
6466 const adjusted_id = try adjusted.materialize(cg);6864 const adjusted_id = try adjusted.materialize(cg);
6467 const result_id = cg.module.allocId();6865 const result_id = cg.allocId();
6468 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{6866 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
6469 .id_result_type = result_ty_id,6867 .id_result_type = result_ty_id,
6470 .id_result = result_id,6868 .id_result = result_id,
6471 .integer_value = adjusted_id,6869 .integer_value = adjusted_id,
...@@ -6483,19 +6881,19 @@ fn structFieldPtr(...@@ -6483,19 +6881,19 @@ fn structFieldPtr(
6483 if (!layout.has_payload) {6881 if (!layout.has_payload) {
6484 // Asked to get a pointer to a zero-sized field. Just lower this6882 // Asked to get a pointer to a zero-sized field. Just lower this
6485 // to undefined, there is no reason to make it be a valid pointer.6883 // 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);
6487 }6885 }
64886886
6489 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));6887 const storage_class = cg.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
6490 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);6888 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);
6492 const pl_ptr_id = blk: {6890 const pl_ptr_id = blk: {
6493 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;6891 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
6494 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});6892 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
6495 };6893 };
64966894
6497 const active_pl_ptr_id = cg.module.allocId();6895 const active_pl_ptr_id = cg.allocId();
6498 try cg.body.emit(cg.module.gpa, .OpBitcast, .{6896 try cg.body.emit(cg.gpa, .OpBitcast, .{
6499 .id_result_type = result_ty_id,6897 .id_result_type = result_ty_id,
6500 .id_result = active_pl_ptr_id,6898 .id_result = active_pl_ptr_id,
6501 .operand = pl_ptr_id,6899 .operand = pl_ptr_id,
...@@ -6525,9 +6923,9 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32)...@@ -6525,9 +6923,9 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32)
6525}6923}
65266924
6527fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {6925fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
6528 const ptr_ty_id = try cg.module.ptrType(ty_id, .function);6926 const ptr_ty_id = try cg.ptrType(ty_id, .function);
6529 const result_id = cg.module.allocId();6927 const result_id = cg.allocId();
6530 try cg.prologue.emit(cg.module.gpa, .OpVariable, .{6928 try cg.prologue.emit(cg.gpa, .OpVariable, .{
6531 .id_result_type = ptr_ty_id,6929 .id_result_type = ptr_ty_id,
6532 .id_result = result_id,6930 .id_result = result_id,
6533 .storage_class = .function,6931 .storage_class = .function,
...@@ -6537,7 +6935,7 @@ fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {...@@ -6537,7 +6935,7 @@ fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
6537}6935}
65386936
6539fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6937fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6540 const zcu = cg.module.zcu;6938 const zcu = cg.zcu;
6541 const target = zcu.getTarget();6939 const target = zcu.getTarget();
6542 const ptr_ty = cg.typeOfIndex(inst);6940 const ptr_ty = cg.typeOfIndex(inst);
6543 const child_ty = ptr_ty.childType(zcu);6941 const child_ty = ptr_ty.childType(zcu);
...@@ -6546,9 +6944,9 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6546,9 +6944,9 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6546 .vulkan, .opengl => {6944 .vulkan, .opengl => {
6547 if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) {6945 if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) {
6548 const as = child_ty.ptrAddressSpace(zcu);6946 const as = child_ty.ptrAddressSpace(zcu);
6549 if (cg.module.storageClass(as) == .function) {6947 if (cg.storageClass(as) == .function) {
6550 const result_id = cg.module.allocId();6948 const result_id = cg.allocId();
6551 try cg.virtual_allocas.put(cg.module.gpa, result_id, null);6949 try cg.tracked_allocas.put(cg.gpa, result_id, null);
6552 return result_id;6950 return result_id;
6553 }6951 }
6554 }6952 }
...@@ -6561,7 +6959,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6561,7 +6959,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6561 const result_id = try cg.alloc(child_ty_id, null);6959 const result_id = try cg.alloc(child_ty_id, null);
6562 if (ptr_align != child_ty.abiAlignment(zcu)) {6960 if (ptr_align != child_ty.abiAlignment(zcu)) {
6563 if (target.os.tag != .opencl) return cg.fail("cannot apply alignment to variables", .{});6961 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, .{
6565 .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) },6963 .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) },
6566 });6964 });
6567 }6965 }
...@@ -6578,9 +6976,9 @@ fn airArg(cg: *CodeGen) Id {...@@ -6578,9 +6976,9 @@ fn airArg(cg: *CodeGen) Id {
6578/// inside the merge block of the block.6976/// inside the merge block of the block.
6579/// This function should only be called with structured control flow generation.6977/// This function should only be called with structured control flow generation.
6580fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {6978fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
6581 const result_id = cg.module.allocId();6979 const result_id = cg.allocId();
6582 const block_id_ty_id = try cg.resolveType(.u32, .direct);6980 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...
6584 cg.body.writeOperand(Id, block_id_ty_id);6982 cg.body.writeOperand(Id, block_id_ty_id);
6585 cg.body.writeOperand(Id, result_id);6983 cg.body.writeOperand(Id, result_id);
65866984
...@@ -6597,11 +6995,11 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {...@@ -6597,11 +6995,11 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
6597fn structuredBreak(cg: *CodeGen, target_block: Id) !void {6995fn structuredBreak(cg: *CodeGen, target_block: Id) !void {
6598 if (cg.block_terminated) return;6996 if (cg.block_terminated) return;
65996997
6600 const gpa = cg.module.gpa;6998 const gpa = cg.gpa;
6601 const sblock = cg.block_stack.getLast().?;6999 const sblock = cg.block_stack.getLast().?;
6602 const merge_block = switch (sblock.*) {7000 const merge_block = switch (sblock.*) {
6603 .selection => |*merge| blk: {7001 .selection => |*merge| blk: {
6604 const merge_label = cg.module.allocId();7002 const merge_label = cg.allocId();
6605 try merge.merge_stack.append(gpa, .{7003 try merge.merge_stack.append(gpa, .{
6606 .incoming = .{7004 .incoming = .{
6607 .src_label = cg.block_label,7005 .src_label = cg.block_label,
...@@ -6641,7 +7039,7 @@ fn genStructuredBody(...@@ -6641,7 +7039,7 @@ fn genStructuredBody(
6641 },7039 },
6642 body: []const Air.Inst.Index,7040 body: []const Air.Inst.Index,
6643) !Id {7041) !Id {
6644 const gpa = cg.module.gpa;7042 const gpa = cg.gpa;
66457043
6646 var sblock: Block = switch (block_merge_type) {7044 var sblock: Block = switch (block_merge_type) {
6647 .loop => |merge| .{ .loop = .{7045 .loop => |merge| .{ .loop = .{
...@@ -6679,9 +7077,9 @@ fn genStructuredBody(...@@ -6679,9 +7077,9 @@ fn genStructuredBody(
66797077
6680 // Make sure that we are still in a block when exiting the function.7078 // Make sure that we are still in a block when exiting the function.
6681 // TODO: Can we get rid of that?7079 // TODO: Can we get rid of that?
6682 try cg.beginSpvBlock(cg.module.allocId());7080 try cg.beginSpvBlock(cg.allocId());
6683 const block_id_ty_id = try cg.resolveType(.u32, .direct);7081 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);
6685 }7083 }
66867084
6687 // The top-most merge actually only has a single source, the7085 // 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)...@@ -6735,8 +7133,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
6735 // of the block, then a label, and then generate the rest of the current7133 // of the block, then a label, and then generate the rest of the current
6736 // ir.Block in a different SPIR-V block.7134 // ir.Block in a different SPIR-V block.
67377135
6738 const gpa = cg.module.gpa;7136 const gpa = cg.gpa;
6739 const zcu = cg.module.zcu;7137 const zcu = cg.zcu;
6740 const ty = cg.typeOfIndex(inst);7138 const ty = cg.typeOfIndex(inst);
6741 const have_block_result = ty.hasRuntimeBits(zcu);7139 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)...@@ -6756,7 +7154,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
67567154
6757 // Check if the target of the branch was this current block.7155 // Check if the target of the branch was this current block.
6758 const this_block = try cg.constInt(.u32, @intFromEnum(inst));7156 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();
6760 const bool_ty_id = try cg.resolveType(.bool, .direct);7158 const bool_ty_id = try cg.resolveType(.bool, .direct);
6761 try cg.body.emit(gpa, .OpIEqual, .{7159 try cg.body.emit(gpa, .OpIEqual, .{
6762 .id_result_type = bool_ty_id,7160 .id_result_type = bool_ty_id,
...@@ -6776,8 +7174,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6776,8 +7174,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
6776 .selection => |*merge| {7174 .selection => |*merge| {
6777 // To jump out of a selection block, push a new entry onto its merge stack and7175 // To jump out of a selection block, push a new entry onto its merge stack and
6778 // generate a conditional branch to there and to the instructions following this block.7176 // generate a conditional branch to there and to the instructions following this block.
6779 const merge_label = cg.module.allocId();7177 const merge_label = cg.allocId();
6780 const then_label = cg.module.allocId();7178 const then_label = cg.allocId();
6781 try cg.body.emit(gpa, .OpSelectionMerge, .{7179 try cg.body.emit(gpa, .OpSelectionMerge, .{
6782 .merge_block = merge_label,7180 .merge_block = merge_label,
6783 .selection_control = .{},7181 .selection_control = .{},
...@@ -6800,7 +7198,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6800,7 +7198,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
6800 .loop => |*merge| {7198 .loop => |*merge| {
6801 // To jump out of a loop block, generate a conditional that exits the block7199 // To jump out of a loop block, generate a conditional that exits the block
6802 // to the loop merge if the target ID is not the one of this block.7200 // 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();
6804 try cg.body.emit(gpa, .OpBranchConditional, .{7202 try cg.body.emit(gpa, .OpBranchConditional, .{
6805 .condition = jump_to_this_block_id,7203 .condition = jump_to_this_block_id,
6806 .true_label = continue_label,7204 .true_label = continue_label,
...@@ -6823,7 +7221,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6823,7 +7221,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
6823}7221}
68247222
6825fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {7223fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6826 const zcu = cg.module.zcu;7224 const zcu = cg.zcu;
6827 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;7225 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
6828 const operand_ty = cg.typeOf(br.operand);7226 const operand_ty = cg.typeOf(br.operand);
68297227
...@@ -6838,16 +7236,16 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6838,16 +7236,16 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6838}7236}
68397237
6840fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {7238fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6841 const gpa = cg.module.gpa;7239 const gpa = cg.gpa;
6842 const cond_br = cg.air.unwrapCondBr(inst);7240 const cond_br = cg.air.unwrapCondBr(inst);
6843 const then_body = cond_br.then_body;7241 const then_body = cond_br.then_body;
6844 const else_body = cond_br.else_body;7242 const else_body = cond_br.else_body;
6845 const condition_id = try cg.resolve(cond_br.condition);7243 const condition_id = try cg.resolve(cond_br.condition);
68467244
6847 const then_label = cg.module.allocId();7245 const then_label = cg.allocId();
6848 const else_label = cg.module.allocId();7246 const else_label = cg.allocId();
68497247
6850 const merge_label = cg.module.allocId();7248 const merge_label = cg.allocId();
68517249
6852 try cg.body.emit(gpa, .OpSelectionMerge, .{7250 try cg.body.emit(gpa, .OpSelectionMerge, .{
6853 .merge_block = merge_label,7251 .merge_block = merge_label,
...@@ -6888,14 +7286,14 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6888,14 +7286,14 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6888}7286}
68897287
6890fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {7288fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
6891 const gpa = cg.module.gpa;7289 const gpa = cg.gpa;
6892 const block = cg.air.unwrapBlock(inst);7290 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();7294 const header_label = cg.allocId();
6897 const merge_label = cg.module.allocId();7295 const merge_label = cg.allocId();
6898 const continue_label = cg.module.allocId();7296 const continue_label = cg.allocId();
68997297
6900 // The back-edge must point to the loop header, so generate a separate block for the7298 // The back-edge must point to the loop header, so generate a separate block for the
6901 // loop header so that we don't accidentally include some instructions from there7299 // 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 {...@@ -6927,18 +7325,19 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
6927}7325}
69287326
6929fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7327fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6930 const zcu = cg.module.zcu;7328 const zcu = cg.zcu;
6931 const pt = cg.pt;7329 const pt = cg.pt;
6932 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7330 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
69337331 const ptr_ty = cg.typeOf(ty_op.operand);
6934 const ptr_info = cg.typeOf(ty_op.operand).ptrInfo(zcu);7332 const ptr_info = ptr_ty.ptrInfo(zcu);
6935
6936 const elem_ty = cg.typeOfIndex(inst);7333 const elem_ty = cg.typeOfIndex(inst);
6937 const operand_ptr_id = try cg.resolve(ty_op.operand);7334 const ptr = try cg.resolvePtr(ty_op.operand);
6938
6939 assert(ptr_info.child == elem_ty.toIntern());7335 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
6943 if (ptr_info.packed_offset.host_size != 0 and7342 if (ptr_info.packed_offset.host_size != 0 and
6944 ptr_info.flags.vector_index == .none)7343 ptr_info.flags.vector_index == .none)
...@@ -6955,7 +7354,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6955,7 +7354,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6955 break :blk try shifted.materialize(cg);7354 break :blk try shifted.materialize(cg);
6956 } else host_val;7355 } else host_val;
6957 const result_id = blk: {7356 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")
6959 break :blk try cg.bitCast(field_int_ty, host_int_ty, narrowed);7358 break :blk try cg.bitCast(field_int_ty, host_int_ty, narrowed);
6960 const trunc = try cg.buildConvert(field_int_ty, .{ .ty = host_int_ty, .value = .{ .singleton = narrowed } });7359 const trunc = try cg.buildConvert(field_int_ty, .{ .ty = host_int_ty, .value = .{ .singleton = narrowed } });
6961 break :blk try trunc.materialize(cg);7360 break :blk try trunc.materialize(cg);
...@@ -6968,9 +7367,9 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6968,9 +7367,9 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6968 const ptr_id = switch (ptr_info.flags.vector_index) {7367 const ptr_id = switch (ptr_info.flags.vector_index) {
6969 .none => operand_ptr_id,7368 .none => operand_ptr_id,
6970 else => |index| ptr_id: {7369 else => |index| ptr_id: {
6971 const elem_ptr_ty_id = try cg.module.ptrType(7370 const elem_ptr_ty_id = try cg.ptrType(
6972 try cg.resolveType(elem_ty, .indirect),7371 try cg.resolveType(elem_ty, .indirect),
6973 cg.module.storageClass(ptr_info.flags.address_space),7372 cg.storageClass(ptr_info.flags.address_space),
6974 );7373 );
6975 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});7374 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
6976 },7375 },
...@@ -6979,18 +7378,20 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6979,18 +7378,20 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6979}7378}
69807379
6981fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {7380fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
6982 const zcu = cg.module.zcu;7381 const zcu = cg.zcu;
6983 const pt = cg.pt;7382 const pt = cg.pt;
6984 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;7383 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);
6986 const elem_ty: Type = .fromInterned(ptr_info.child);7386 const elem_ty: Type = .fromInterned(ptr_info.child);
6987 const operand_ptr_id = try cg.resolve(bin_op.lhs);
6988 const value_id = try cg.resolve(bin_op.rhs);7387 const value_id = try cg.resolve(bin_op.rhs);
69897388 const operand_ptr_id = switch (try cg.resolvePtr(bin_op.lhs)) {
6990 if (cg.virtual_allocas.getPtr(operand_ptr_id)) |slot| {7389 .tracked => |t| {
6991 slot.* = value_id;7390 t.slot.* = value_id;
6992 return;7391 return;
6993 }7392 },
7393 .id => |id| id,
7394 };
69947395
6995 if (ptr_info.packed_offset.host_size != 0 and7396 if (ptr_info.packed_offset.host_size != 0 and
6996 ptr_info.flags.vector_index == .none)7397 ptr_info.flags.vector_index == .none)
...@@ -7013,7 +7414,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7013,7 +7414,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
7013 }7414 }
70147415
7015 const extended = blk: {7416 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")
7017 break :blk try cg.bitCast(host_int_ty, field_int_ty, value_as_int);7418 break :blk try cg.bitCast(host_int_ty, field_int_ty, value_as_int);
7018 const conv = try cg.buildConvert(host_int_ty, .{ .ty = field_int_ty, .value = .{ .singleton = value_as_int } });7419 const conv = try cg.buildConvert(host_int_ty, .{ .ty = field_int_ty, .value = .{ .singleton = value_as_int } });
7019 break :blk try conv.materialize(cg);7420 break :blk try conv.materialize(cg);
...@@ -7037,9 +7438,9 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7037,9 +7438,9 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
7037 const ptr_id = switch (ptr_info.flags.vector_index) {7438 const ptr_id = switch (ptr_info.flags.vector_index) {
7038 .none => operand_ptr_id,7439 .none => operand_ptr_id,
7039 else => |index| ptr_id: {7440 else => |index| ptr_id: {
7040 const elem_ptr_ty_id = try cg.module.ptrType(7441 const elem_ptr_ty_id = try cg.ptrType(
7041 try cg.resolveType(elem_ty, .indirect),7442 try cg.resolveType(elem_ty, .indirect),
7042 cg.module.storageClass(ptr_info.flags.address_space),7443 cg.storageClass(ptr_info.flags.address_space),
7043 );7444 );
7044 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});7445 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
7045 },7446 },
...@@ -7049,8 +7450,8 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7049,8 +7450,8 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
7049}7450}
70507451
7051fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {7452fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
7052 const gpa = cg.module.gpa;7453 const gpa = cg.gpa;
7053 const zcu = cg.module.zcu;7454 const zcu = cg.zcu;
7054 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7455 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7055 const ret_ty = cg.typeOf(operand);7456 const ret_ty = cg.typeOf(operand);
7056 if (!ret_ty.hasRuntimeBits(zcu)) {7457 if (!ret_ty.hasRuntimeBits(zcu)) {
...@@ -7071,8 +7472,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7071,8 +7472,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
7071}7472}
70727473
7073fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {7474fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
7074 const gpa = cg.module.gpa;7475 const gpa = cg.gpa;
7075 const zcu = cg.module.zcu;7476 const zcu = cg.zcu;
7076 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7477 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7077 const ptr_ty = cg.typeOf(un_op);7478 const ptr_ty = cg.typeOf(un_op);
7078 const ret_ty = ptr_ty.childType(zcu);7479 const ret_ty = ptr_ty.childType(zcu);
...@@ -7090,16 +7491,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7090,16 +7491,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
7090 }7491 }
7091 }7492 }
70927493
7093 const ptr = try cg.resolve(un_op);7494 const value = switch (try cg.resolvePtr(un_op)) {
7094 const value = try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });7495 .tracked => |t| t.slot.*.?,
7496 .id => |ptr| try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }),
7497 };
7095 try cg.body.emit(gpa, .OpReturnValue, .{7498 try cg.body.emit(gpa, .OpReturnValue, .{
7096 .value = value,7499 .value = value,
7097 });7500 });
7098}7501}
70997502
7100fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7503fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7101 const gpa = cg.module.gpa;7504 const gpa = cg.gpa;
7102 const zcu = cg.module.zcu;7505 const zcu = cg.zcu;
7103 const unwrapped_try = cg.air.unwrapTry(inst);7506 const unwrapped_try = cg.air.unwrapTry(inst);
7104 const body = unwrapped_try.else_body;7507 const body = unwrapped_try.else_body;
71057508
...@@ -7118,7 +7521,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7118,7 +7521,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7118 err_union_id;7521 err_union_id;
71197522
7120 const zero_id = try cg.constInt(.anyerror, 0);7523 const zero_id = try cg.constInt(.anyerror, 0);
7121 const is_err_id = cg.module.allocId();7524 const is_err_id = cg.allocId();
7122 try cg.body.emit(gpa, .OpINotEqual, .{7525 try cg.body.emit(gpa, .OpINotEqual, .{
7123 .id_result_type = bool_ty_id,7526 .id_result_type = bool_ty_id,
7124 .id_result = is_err_id,7527 .id_result = is_err_id,
...@@ -7130,8 +7533,8 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7130,8 +7533,8 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7130 // with the current body.7533 // with the current body.
7131 // Just generate a new block here, then generate a new block inline for the remainder of the body.7534 // 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();7536 const err_block = cg.allocId();
7134 const ok_block = cg.module.allocId();7537 const ok_block = cg.allocId();
71357538
7136 // According to AIR documentation, this block is guaranteed7539 // According to AIR documentation, this block is guaranteed
7137 // to not break and end in a return instruction. Thus,7540 // to not break and end in a return instruction. Thus,
...@@ -7162,7 +7565,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7162,7 +7565,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7162}7565}
71637566
7164fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7567fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7165 const zcu = cg.module.zcu;7568 const zcu = cg.zcu;
7166 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7569 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7167 const operand_id = try cg.resolve(ty_op.operand);7570 const operand_id = try cg.resolve(ty_op.operand);
7168 const err_union_ty = cg.typeOf(ty_op.operand);7571 const err_union_ty = cg.typeOf(ty_op.operand);
...@@ -7170,7 +7573,7 @@ fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7170,7 +7573,7 @@ fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71707573
7171 if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {7574 if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
7172 // No error possible, so just return undefined.7575 // No error possible, so just return undefined.
7173 return try cg.module.constUndef(err_ty_id);7576 return try cg.constUndef(err_ty_id);
7174 }7577 }
71757578
7176 const payload_ty = err_union_ty.errorUnionPayload(zcu);7579 const payload_ty = err_union_ty.errorUnionPayload(zcu);
...@@ -7198,7 +7601,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7198,7 +7601,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7198}7601}
71997602
7200fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7603fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7201 const zcu = cg.module.zcu;7604 const zcu = cg.zcu;
7202 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7605 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7203 const err_union_ty = cg.typeOfIndex(inst);7606 const err_union_ty = cg.typeOfIndex(inst);
7204 const payload_ty = err_union_ty.errorUnionPayload(zcu);7607 const payload_ty = err_union_ty.errorUnionPayload(zcu);
...@@ -7213,7 +7616,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7213,7 +7616,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
72137616
7214 var members: [2]Id = undefined;7617 var members: [2]Id = undefined;
7215 members[eu_layout.errorFieldIndex()] = operand_id;7618 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
7218 var types: [2]Type = undefined;7621 var types: [2]Type = undefined;
7219 types[eu_layout.errorFieldIndex()] = .anyerror;7622 types[eu_layout.errorFieldIndex()] = .anyerror;
...@@ -7247,7 +7650,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7247,7 +7650,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7247}7650}
72487651
7249fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?Id {7652fn 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;
7251 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7654 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7252 const operand_id = try cg.resolve(un_op);7655 const operand_id = try cg.resolve(un_op);
7253 const operand_ty = cg.typeOf(un_op);7656 const operand_ty = cg.typeOf(un_op);
...@@ -7274,7 +7677,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -7274,7 +7677,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7274 loaded_id;7677 loaded_id;
72757678
7276 const ptr_ty_id = try cg.resolveType(ptr_ty, .direct);7679 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);
7278 const null_tmp: Temporary = .init(ptr_ty, null_id);7681 const null_tmp: Temporary = .init(ptr_ty, null_id);
7279 const ptr: Temporary = .init(ptr_ty, ptr_id);7682 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 {...@@ -7289,9 +7692,9 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7289 const is_non_null_id = blk: {7692 const is_non_null_id = blk: {
7290 if (is_pointer) {7693 if (is_pointer) {
7291 if (payload_ty.hasRuntimeBits(zcu)) {7694 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));
7293 const bool_indirect_ty_id = try cg.resolveType(.bool, .indirect);7696 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);
7295 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});7698 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});
7296 break :blk try cg.load(.bool, tag_ptr_id, .{});7699 break :blk try cg.load(.bool, tag_ptr_id, .{});
7297 }7700 }
...@@ -7311,8 +7714,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -7311,8 +7714,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7311 return switch (pred) {7714 return switch (pred) {
7312 .is_null => blk: {7715 .is_null => blk: {
7313 // Invert condition7716 // Invert condition
7314 const result_id = cg.module.allocId();7717 const result_id = cg.allocId();
7315 try cg.body.emit(cg.module.gpa, .OpLogicalNot, .{7718 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
7316 .id_result_type = bool_ty_id,7719 .id_result_type = bool_ty_id,
7317 .id_result = result_id,7720 .id_result = result_id,
7318 .operand = is_non_null_id,7721 .operand = is_non_null_id,
...@@ -7324,7 +7727,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -7324,7 +7727,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7324}7727}
73257728
7326fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?Id {7729fn 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;
7328 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7731 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7329 const operand_id = try cg.resolve(un_op);7732 const operand_id = try cg.resolve(un_op);
7330 const err_union_ty = cg.typeOf(un_op);7733 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...@@ -7342,10 +7745,10 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
7342 else7745 else
7343 try cg.extractField(.anyerror, operand_id, eu_layout.errorFieldIndex());7746 try cg.extractField(.anyerror, operand_id, eu_layout.errorFieldIndex());
73447747
7345 const result_id = cg.module.allocId();7748 const result_id = cg.allocId();
7346 switch (pred) {7749 switch (pred) {
7347 inline else => |pred_ct| try cg.body.emit(7750 inline else => |pred_ct| try cg.body.emit(
7348 cg.module.gpa,7751 cg.gpa,
7349 switch (pred_ct) {7752 switch (pred_ct) {
7350 .is_err => .OpINotEqual,7753 .is_err => .OpINotEqual,
7351 .is_non_err => .OpIEqual,7754 .is_non_err => .OpIEqual,
...@@ -7362,7 +7765,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err...@@ -7362,7 +7765,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
7362}7765}
73637766
7364fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7767fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7365 const zcu = cg.module.zcu;7768 const zcu = cg.zcu;
7366 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7769 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7367 const operand_id = try cg.resolve(ty_op.operand);7770 const operand_id = try cg.resolve(ty_op.operand);
7368 const optional_ty = cg.typeOf(ty_op.operand);7771 const optional_ty = cg.typeOf(ty_op.operand);
...@@ -7378,7 +7781,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7378,7 +7781,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7378}7781}
73797782
7380fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7783fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7381 const zcu = cg.module.zcu;7784 const zcu = cg.zcu;
7382 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7785 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7383 const operand_id = try cg.resolve(ty_op.operand);7786 const operand_id = try cg.resolve(ty_op.operand);
7384 const operand_ty = cg.typeOf(ty_op.operand);7787 const operand_ty = cg.typeOf(ty_op.operand);
...@@ -7402,7 +7805,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7402,7 +7805,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7402}7805}
74037806
7404fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7807fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7405 const zcu = cg.module.zcu;7808 const zcu = cg.zcu;
7406 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7809 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7407 const payload_ty = cg.typeOf(ty_op.operand);7810 const payload_ty = cg.typeOf(ty_op.operand);
74087811
...@@ -7422,9 +7825,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7422,9 +7825,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7422}7825}
74237826
7424fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {7827fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7425 const gpa = cg.module.gpa;7828 const gpa = cg.gpa;
7426 const zcu = cg.module.zcu;7829 const zcu = cg.zcu;
7427 const target = cg.module.zcu.getTarget();7830 const target = cg.zcu.getTarget();
7428 const switch_br = cg.air.unwrapSwitch(inst);7831 const switch_br = cg.air.unwrapSwitch(inst);
7429 const cond_ty = cg.typeOf(switch_br.operand);7832 const cond_ty = cg.typeOf(switch_br.operand);
7430 const cond = try cg.resolve(switch_br.operand);7833 const cond = try cg.resolve(switch_br.operand);
...@@ -7434,14 +7837,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7434,14 +7837,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7434 .bool, .error_set => 1,7837 .bool, .error_set => 1,
7435 .int => blk: {7838 .int => blk: {
7436 const bits = cond_ty.intInfo(zcu).bits;7839 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);
7438 if (big_int) return cg.todo("implement composite int switch", .{});7841 if (big_int) return cg.todo("implement composite int switch", .{});
7439 break :blk if (backing_bits <= 32) 1 else 2;7842 break :blk if (backing_bits <= 32) 1 else 2;
7440 },7843 },
7441 .@"enum" => blk: {7844 .@"enum" => blk: {
7442 const int_ty = cond_ty.intTagType(zcu);7845 const int_ty = cond_ty.intTagType(zcu);
7443 const int_info = int_ty.intInfo(zcu);7846 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);
7445 if (big_int) return cg.todo("implement composite int switch", .{});7848 if (big_int) return cg.todo("implement composite int switch", .{});
7446 break :blk if (backing_bits <= 32) 1 else 2;7849 break :blk if (backing_bits <= 32) 1 else 2;
7447 },7850 },
...@@ -7470,12 +7873,12 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7470,12 +7873,12 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7470 }7873 }
74717874
7472 // First, pre-allocate the labels for the cases.7875 // 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);
7474 // We always need the default case - if zig has none, we will generate unreachable there.7877 // We always need the default case - if zig has none, we will generate unreachable there.
7475 const default_label = cg.module.allocId();7878 const default_label = cg.allocId();
7476 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;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
7480 try cg.body.emit(gpa, .OpSelectionMerge, .{7883 try cg.body.emit(gpa, .OpSelectionMerge, .{
7481 .merge_block = merge_label,7884 .merge_block = merge_label,
...@@ -7540,12 +7943,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7540,12 +7943,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7540 const item_tmp: Temporary = try cg.temporary(item);7943 const item_tmp: Temporary = try cg.temporary(item);
7541 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);7944 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
7542 case_cond = if (case_cond) |prev| blk: {7945 case_cond = if (case_cond) |prev| blk: {
7543 const combined = cg.module.allocId();7946 const combined = cg.allocId();
7544 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);7947 try cg.body.emit(gpa, .OpLogicalOr, .{
7545 cg.body.writeOperand(Id, bool_ty_id);7948 .id_result_type = bool_ty_id,
7546 cg.body.writeOperand(Id, combined);7949 .id_result = combined,
7547 cg.body.writeOperand(Id, prev);7950 .operand_1 = prev,
7548 cg.body.writeOperand(Id, eq);7951 .operand_2 = eq,
7952 });
7549 break :blk combined;7953 break :blk combined;
7550 } else eq;7954 } else eq;
7551 }7955 }
...@@ -7555,26 +7959,28 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7555,26 +7959,28 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7555 const hi_tmp: Temporary = try cg.temporary(range[1]);7959 const hi_tmp: Temporary = try cg.temporary(range[1]);
7556 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);7960 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
7557 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);7961 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7558 const in_range = cg.module.allocId();7962 const in_range = cg.allocId();
7559 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);7963 try cg.body.emit(gpa, .OpLogicalAnd, .{
7560 cg.body.writeOperand(Id, bool_ty_id);7964 .id_result_type = bool_ty_id,
7561 cg.body.writeOperand(Id, in_range);7965 .id_result = in_range,
7562 cg.body.writeOperand(Id, ge);7966 .operand_1 = ge,
7563 cg.body.writeOperand(Id, le);7967 .operand_2 = le,
7968 });
7564 case_cond = if (case_cond) |prev| blk: {7969 case_cond = if (case_cond) |prev| blk: {
7565 const combined = cg.module.allocId();7970 const combined = cg.allocId();
7566 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);7971 try cg.body.emit(gpa, .OpLogicalOr, .{
7567 cg.body.writeOperand(Id, bool_ty_id);7972 .id_result_type = bool_ty_id,
7568 cg.body.writeOperand(Id, combined);7973 .id_result = combined,
7569 cg.body.writeOperand(Id, prev);7974 .operand_1 = prev,
7570 cg.body.writeOperand(Id, in_range);7975 .operand_2 = in_range,
7976 });
7571 break :blk combined;7977 break :blk combined;
7572 } else in_range;7978 } else in_range;
7573 }7979 }
75747980
7575 const case_label = case_labels.at(case.idx);7981 const case_label = case_labels.at(case.idx);
7576 const is_last = case.idx == last_range_case.?;7982 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
7579 try cg.body.emit(gpa, .OpSelectionMerge, .{7985 try cg.body.emit(gpa, .OpSelectionMerge, .{
7580 .merge_block = next_check,7986 .merge_block = next_check,
...@@ -7633,9 +8039,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7633,9 +8039,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7633}8039}
76348040
7635fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {8041fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7636 const gpa = cg.module.gpa;8042 const gpa = cg.gpa;
7637 const zcu = cg.module.zcu;8043 const zcu = cg.zcu;
7638 const target = cg.module.zcu.getTarget();8044 const target = cg.zcu.getTarget();
7639 const switch_br = cg.air.unwrapSwitch(inst);8045 const switch_br = cg.air.unwrapSwitch(inst);
7640 const cond_ty = cg.typeOf(switch_br.operand);8046 const cond_ty = cg.typeOf(switch_br.operand);
7641 const initial_cond = try cg.resolve(switch_br.operand);8047 const initial_cond = try cg.resolve(switch_br.operand);
...@@ -7645,14 +8051,14 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7645,14 +8051,14 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7645 .bool, .error_set => 1,8051 .bool, .error_set => 1,
7646 .int => blk: {8052 .int => blk: {
7647 const bits = cond_ty.intInfo(zcu).bits;8053 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);
7649 if (big_int) return cg.todo("implement composite int loop switch", .{});8055 if (big_int) return cg.todo("implement composite int loop switch", .{});
7650 break :blk if (backing_bits <= 32) 1 else 2;8056 break :blk if (backing_bits <= 32) 1 else 2;
7651 },8057 },
7652 .@"enum" => blk: {8058 .@"enum" => blk: {
7653 const int_ty = cond_ty.intTagType(zcu);8059 const int_ty = cond_ty.intTagType(zcu);
7654 const int_info = int_ty.intInfo(zcu);8060 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);
7656 if (big_int) return cg.todo("implement composite int loop switch", .{});8062 if (big_int) return cg.todo("implement composite int loop switch", .{});
7657 break :blk if (backing_bits <= 32) 1 else 2;8063 break :blk if (backing_bits <= 32) 1 else 2;
7658 },8064 },
...@@ -7682,15 +8088,15 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7682,15 +8088,15 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7682 }8088 }
7683 }8089 }
76848090
7685 const case_labels = cg.module.allocIds(num_cases);8091 const case_labels = cg.allocIds(num_cases);
7686 const default_label = cg.module.allocId();8092 const default_label = cg.allocId();
7687 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;8093 const switch_default = if (last_range_case != null) cg.allocId() else default_label;
76888094
7689 const header_label = cg.module.allocId();8095 const header_label = cg.allocId();
7690 const loop_merge = cg.module.allocId();8096 const loop_merge = cg.allocId();
7691 const continue_label = cg.module.allocId();8097 const continue_label = cg.allocId();
7692 const switch_merge = cg.module.allocId();8098 const switch_merge = cg.allocId();
7693 const body_label = cg.module.allocId();8099 const body_label = cg.allocId();
76948100
7695 // switch_dispatch signals "continue the loop" by using this sentinel as the8101 // switch_dispatch signals "continue the loop" by using this sentinel as the
7696 // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes8102 // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes
...@@ -7772,12 +8178,13 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7772,12 +8178,13 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7772 const item_tmp: Temporary = try cg.temporary(item);8178 const item_tmp: Temporary = try cg.temporary(item);
7773 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);8179 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
7774 case_cond = if (case_cond) |prev| blk: {8180 case_cond = if (case_cond) |prev| blk: {
7775 const combined = cg.module.allocId();8181 const combined = cg.allocId();
7776 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);8182 try cg.body.emit(gpa, .OpLogicalOr, .{
7777 cg.body.writeOperand(Id, bool_ty_id);8183 .id_result_type = bool_ty_id,
7778 cg.body.writeOperand(Id, combined);8184 .id_result = combined,
7779 cg.body.writeOperand(Id, prev);8185 .operand_1 = prev,
7780 cg.body.writeOperand(Id, eq);8186 .operand_2 = eq,
8187 });
7781 break :blk combined;8188 break :blk combined;
7782 } else eq;8189 } else eq;
7783 }8190 }
...@@ -7787,26 +8194,28 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7787,26 +8194,28 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7787 const hi_tmp: Temporary = try cg.temporary(range[1]);8194 const hi_tmp: Temporary = try cg.temporary(range[1]);
7788 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);8195 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
7789 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);8196 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7790 const in_range = cg.module.allocId();8197 const in_range = cg.allocId();
7791 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);8198 try cg.body.emit(gpa, .OpLogicalAnd, .{
7792 cg.body.writeOperand(Id, bool_ty_id);8199 .id_result_type = bool_ty_id,
7793 cg.body.writeOperand(Id, in_range);8200 .id_result = in_range,
7794 cg.body.writeOperand(Id, ge);8201 .operand_1 = ge,
7795 cg.body.writeOperand(Id, le);8202 .operand_2 = le,
8203 });
7796 case_cond = if (case_cond) |prev| blk: {8204 case_cond = if (case_cond) |prev| blk: {
7797 const combined = cg.module.allocId();8205 const combined = cg.allocId();
7798 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);8206 try cg.body.emit(gpa, .OpLogicalOr, .{
7799 cg.body.writeOperand(Id, bool_ty_id);8207 .id_result_type = bool_ty_id,
7800 cg.body.writeOperand(Id, combined);8208 .id_result = combined,
7801 cg.body.writeOperand(Id, prev);8209 .operand_1 = prev,
7802 cg.body.writeOperand(Id, in_range);8210 .operand_2 = in_range,
8211 });
7803 break :blk combined;8212 break :blk combined;
7804 } else in_range;8213 } else in_range;
7805 }8214 }
78068215
7807 const case_label = case_labels.at(case.idx);8216 const case_label = case_labels.at(case.idx);
7808 const is_last = case.idx == last_range_case.?;8217 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
7811 try cg.body.emit(gpa, .OpSelectionMerge, .{8220 try cg.body.emit(gpa, .OpSelectionMerge, .{
7812 .merge_block = next_check,8221 .merge_block = next_check,
...@@ -7860,7 +8269,7 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7860,7 +8269,7 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7860 try cg.beginSpvBlock(switch_merge);8269 try cg.beginSpvBlock(switch_merge);
7861 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);8270 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);
78628271
7863 const is_dispatch = cg.module.allocId();8272 const is_dispatch = cg.allocId();
7864 const bool_ty_id = try cg.resolveType(.bool, .direct);8273 const bool_ty_id = try cg.resolveType(.bool, .direct);
7865 try cg.body.emit(gpa, .OpIEqual, .{8274 try cg.body.emit(gpa, .OpIEqual, .{
7866 .id_result_type = bool_ty_id,8275 .id_result_type = bool_ty_id,
...@@ -7869,12 +8278,12 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7869,12 +8278,12 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7869 .operand_2 = dispatch_sentinel,8278 .operand_2 = dispatch_sentinel,
7870 });8279 });
78718280
7872 const dispatch_check_merge = cg.module.allocId();8281 const dispatch_check_merge = cg.allocId();
7873 try cg.body.emit(gpa, .OpSelectionMerge, .{8282 try cg.body.emit(gpa, .OpSelectionMerge, .{
7874 .merge_block = dispatch_check_merge,8283 .merge_block = dispatch_check_merge,
7875 .selection_control = .{},8284 .selection_control = .{},
7876 });8285 });
7877 const exit_block = cg.module.allocId();8286 const exit_block = cg.allocId();
7878 try cg.body.emit(gpa, .OpBranchConditional, .{8287 try cg.body.emit(gpa, .OpBranchConditional, .{
7879 .condition = is_dispatch,8288 .condition = is_dispatch,
7880 .true_label = dispatch_check_merge,8289 .true_label = dispatch_check_merge,
...@@ -7906,25 +8315,30 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7906,25 +8315,30 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void {
7906}8315}
79078316
7908fn airUnreach(cg: *CodeGen) !void {8317fn airUnreach(cg: *CodeGen) !void {
7909 try cg.body.emit(cg.module.gpa, .OpUnreachable, {});8318 try cg.body.emit(cg.gpa, .OpUnreachable, {});
7910}8319}
79118320
7912fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {8321fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {
7913 const zcu = cg.module.zcu;8322 const zcu = cg.zcu;
7914 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;8323 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
7915 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;8324 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;
79168325
7917 if (zcu.comp.config.root_strip) return;8326 if (zcu.comp.config.root_strip) return;
79188327
7919 try cg.body.emit(cg.module.gpa, .OpLine, .{8328 const path_id = cg.allocId();
7920 .file = try cg.module.debugString(path),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,
7921 .line = cg.base_line + dbg_stmt.line + 1,8335 .line = cg.base_line + dbg_stmt.line + 1,
7922 .column = dbg_stmt.column + 1,8336 .column = dbg_stmt.column + 1,
7923 });8337 });
7924}8338}
79258339
7926fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {8340fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7927 const zcu = cg.module.zcu;8341 const zcu = cg.zcu;
7928 const block = cg.air.unwrapDbgBlock(inst);8342 const block = cg.air.unwrapDbgBlock(inst);
7929 const old_base_line = cg.base_line;8343 const old_base_line = cg.base_line;
7930 defer cg.base_line = old_base_line;8344 defer cg.base_line = old_base_line;
...@@ -7934,15 +8348,17 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7934,15 +8348,17 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
79348348
7935fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {8349fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
7936 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;8350 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
7937 const target_id = try cg.resolve(pl_op.operand);8351 const target_id = switch (try cg.resolvePtr(pl_op.operand)) {
7938 if (cg.virtual_allocas.contains(target_id)) return;8352 .tracked => return,
8353 .id => |id| id,
8354 };
7939 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);8355 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));
7941}8357}
79428358
7943fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {8359fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7944 const gpa = cg.module.gpa;8360 const gpa = cg.gpa;
7945 const zcu = cg.module.zcu;8361 const zcu = cg.zcu;
7946 const unwrapped_asm = cg.air.unwrapAsm(inst);8362 const unwrapped_asm = cg.air.unwrapAsm(inst);
79478363
7948 const is_volatile = unwrapped_asm.is_volatile;8364 const is_volatile = unwrapped_asm.is_volatile;
...@@ -7974,7 +8390,6 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7974,7 +8390,6 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7974 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});8390 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});
7975 });8391 });
79768392
7977 // TODO: This entire function should be handled a bit better...
7978 const ip = &zcu.intern_pool;8393 const ip = &zcu.intern_pool;
7979 switch (ip.indexToKey(val.toIntern())) {8394 switch (ip.indexToKey(val.toIntern())) {
7980 .int_type,8395 .int_type,
...@@ -8080,8 +8495,8 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -8080,8 +8495,8 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
8080fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) !?Id {8495fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) !?Id {
8081 _ = modifier;8496 _ = modifier;
80828497
8083 const gpa = cg.module.gpa;8498 const gpa = cg.gpa;
8084 const zcu = cg.module.zcu;8499 const zcu = cg.zcu;
8085 const air_call = cg.air.unwrapCall(inst);8500 const air_call = cg.air.unwrapCall(inst);
8086 const args = air_call.args;8501 const args = air_call.args;
8087 const callee_ty = cg.typeOf(air_call.callee);8502 const callee_ty = cg.typeOf(air_call.callee);
...@@ -8094,11 +8509,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -8094,11 +8509,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
8094 const return_type = fn_info.return_type;8509 const return_type = fn_info.return_type;
80958510
8096 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));8511 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));
8097 const result_id = cg.module.allocId();8512 const result_id = cg.allocId();
8098 const callee_id = try cg.resolve(air_call.callee);8513 const callee_id = try cg.resolve(air_call.callee);
80998514
8100 comptime assert(zig_call_abi_ver == 3);
8101
8102 const scratch_top = cg.id_scratch.items.len;8515 const scratch_top = cg.id_scratch.items.len;
8103 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);8516 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
8104 const params = try cg.id_scratch.addManyAsSlice(gpa, args.len);8517 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)...@@ -8113,7 +8526,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
81138526
8114 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and8527 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and
8115 !arg_ty.childType(zcu).hasRuntimeBits(zcu) and8528 !arg_ty.childType(zcu).hasRuntimeBits(zcu) and
8116 cg.module.storageClass(arg_ty.ptrAddressSpace(zcu)) == .function)8529 cg.storageClass(arg_ty.ptrAddressSpace(zcu)) == .function)
8117 {8530 {
8118 // in logical addressing, pointer arguments to function calls8531 // in logical addressing, pointer arguments to function calls
8119 // must be memory object declarations (OpVariable). for pointers to8532 // must be memory object declarations (OpVariable). for pointers to
...@@ -8148,15 +8561,26 @@ fn builtin3D(...@@ -8148,15 +8561,26 @@ fn builtin3D(
8148 dimension: u32,8561 dimension: u32,
8149 out_of_range_value: anytype,8562 out_of_range_value: anytype,
8150) !Id {8563) !Id {
8151 const gpa = cg.module.gpa;8564 const gpa = cg.gpa;
8152 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);8565 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);
8153 const u32_ty_id = try cg.module.intType(.unsigned, 32);8566 const u32_ty_id = try cg.intType(.unsigned, 32);
8154 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);8567 const vec_ty_id = try cg.vectorType(3, u32_ty_id);
8155 const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input);8568 const ptr_ty_id = try cg.ptrType(vec_ty_id, .input);
8156 const spv_decl_index = try cg.module.builtin(ptr_ty_id, built_in, .input);8569 const builtins_gop = try cg.builtins.getOrPut(gpa, .{ built_in, .input });
8157 try cg.module.decl_deps.append(gpa, spv_decl_index);8570 if (!builtins_gop.found_existing) {
8158 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;8571 builtins_gop.value_ptr.* = try cg.allocDecl(.global);
8159 const vec_id = cg.module.allocId();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();
8160 try cg.body.emit(gpa, .OpLoad, .{8584 try cg.body.emit(gpa, .OpLoad, .{
8161 .id_result_type = vec_ty_id,8585 .id_result_type = vec_ty_id,
8162 .id_result = vec_id,8586 .id_result = vec_id,
...@@ -8187,12 +8611,30 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -8187,12 +8611,30 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
8187 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);8611 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
8188}8612}
81898613
8190fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {8614const std = @import("std");
8191 const zcu = cg.module.zcu;8615const Allocator = std.mem.Allocator;
8192 return cg.air.typeOf(inst, &zcu.intern_pool);8616const Target = std.Target;
8193}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 {8621const builtin = @import("builtin");
8196 const zcu = cg.module.zcu;8622const link = @import("../../link.zig");
8197 return cg.air.typeOfIndex(inst, &zcu.intern_pool);8623const codegen = @import("../../codegen.zig");
8198}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;...@@ -6,13 +6,13 @@ const Word = spec.Word;
6const Id = spec.Id;6const Id = spec.Id;
77
8const InternPool = @import("../../InternPool.zig");8const InternPool = @import("../../InternPool.zig");
9const Module = @import("Module.zig");9const CodeGen = @import("CodeGen.zig");
1010
11const Mir = @This();11const Mir = @This();
1212
13id_bound: Word,13id_bound: Word,
14owner_nav: InternPool.Nav.Index,14owner_nav: InternPool.Nav.Index,
15kind: Module.Decl.Kind,15kind: CodeGen.Decl.Kind,
16decl_result_id: Id,16decl_result_id: Id,
17extended_instruction_set: []const Word,17extended_instruction_set: []const Word,
18globals: []const Word,18globals: []const Word,
...@@ -30,18 +30,18 @@ entry_points: []const EntryPoint,...@@ -30,18 +30,18 @@ entry_points: []const EntryPoint,
30pub const NavRef = struct {30pub const NavRef = struct {
31 local_id: Id,31 local_id: Id,
32 nav: InternPool.Nav.Index,32 nav: InternPool.Nav.Index,
33 kind: Module.Decl.Kind,33 kind: CodeGen.Decl.Kind,
34};34};
3535
36pub const UavRef = struct {36pub const UavRef = struct {
37 local_id: Id,37 local_id: Id,
38 val: InternPool.Index,38 val: InternPool.Index,
39 storage_class: spec.StorageClass,39 storage_class: spec.StorageClass,
40 kind: Module.Decl.Kind,40 kind: CodeGen.Decl.Kind,
41};41};
4242
43pub const DeclDep = struct {43pub const DeclDep = struct {
44 kind: Module.Decl.Kind,44 kind: CodeGen.Decl.Kind,
45 nav: InternPool.Nav.Index,45 nav: InternPool.Nav.Index,
46};46};
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}