authorgravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-25 15:47:10+02:00
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-25 15:47:10+02:00
log914b8f26b03944ac58900aefb3ab21fc988e6c7e
treef94d3156f4f2abf5770dc4c684d40247d9b4c793
parent64c5cc80471ccd167af2403741dc2037824e0c8c
parente8ccd4fbcd8375d579042b5c38d8370ca271a00f

Merge pull request 'spirv: bug fixes' (#35874) from alichraghi/zig:ali/refactor into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35874 Reviewed-by: Alex Rønne Petersen <alex@alexrp.com>

26 files changed, 2097 insertions(+), 2277 deletions(-)

lib/std/lang.zig+1-1
...@@ -838,7 +838,7 @@ pub const Type = union(enum) {...@@ -838,7 +838,7 @@ pub const Type = union(enum) {
838 pub const Usage = union(enum(u2)) {838 pub const Usage = union(enum(u2)) {
839 unknown: type,839 unknown: type,
840 sampled: type,840 sampled: type,
841 storage,841 storage: type,
842 };842 };
843843
844 pub const Format = enum(u4) {844 pub const Format = enum(u4) {
src/Sema.zig+92-48
...@@ -8694,15 +8694,26 @@ fn checkReturnTypeAndCallConv(...@@ -8694,15 +8694,26 @@ fn checkReturnTypeAndCallConv(
8694 return sema.fail(block, callconv_src, "'pixel_centered_integer' is not supported on this target", .{});8694 return sema.fail(block, callconv_src, "'pixel_centered_integer' is not supported on this target", .{});
8695 }8695 }
8696 },8696 },
8697 .spirv_kernel, .spirv_task => |kernel| {8697 .spirv_kernel => |kernel| {
8698 if (kernel.x == 0 or kernel.y == 0 or kernel.z == 0) {8698 if (kernel.x == 0 or kernel.y == 0 or kernel.z == 0) {
8699 return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{});8699 return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{});
8700 }8700 }
8701 },8701 },
8702 .spirv_task => |task| {
8703 if (task.x == 0 or task.y == 0 or task.z == 0) {
8704 return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{});
8705 }
8706 if (!target.cpu.has(.spirv, .mesh_shading_ext)) {
8707 return sema.fail(block, callconv_src, "calling convention '{t}' requires the 'mesh_shading_ext' feature", .{@"callconv"});
8708 }
8709 },
8702 .spirv_mesh => |mesh| {8710 .spirv_mesh => |mesh| {
8703 if (mesh.max_vertices == 0 or mesh.max_primitives == 0) {8711 if (mesh.max_vertices == 0 or mesh.max_primitives == 0) {
8704 return sema.fail(block, callconv_src, "mesh shader 'max_vertices' and 'max_primitives' must be at least 1", .{});8712 return sema.fail(block, callconv_src, "mesh shader 'max_vertices' and 'max_primitives' must be at least 1", .{});
8705 }8713 }
8714 if (!target.cpu.has(.spirv, .mesh_shading_ext)) {
8715 return sema.fail(block, callconv_src, "calling convention '{t}' requires the 'mesh_shading_ext' feature", .{@"callconv"});
8716 }
8706 },8717 },
8707 else => {},8718 else => {},
8708 }8719 }
...@@ -8844,7 +8855,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type)...@@ -8844,7 +8855,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type)
8844 try sema.errNote(runtime_src, msg, "runtime control flow here", .{});8855 try sema.errNote(runtime_src, msg, "runtime control flow here", .{});
88458856
8846 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm);8857 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm);
8847 try sema.errNote(src, msg, "pointers with address space '{s}' cannot be returned from a branch on target {s}-{s} by compiler backend {s}", .{8858 try sema.errNote(src, msg, "pointers with address space '{s}' cannot be returned from a branch on target '{s}-{s}' by compiler backend '{s}'", .{
8848 @tagName(as),8859 @tagName(as),
8849 @tagName(target.cpu.arch.family()),8860 @tagName(target.cpu.arch.family()),
8850 @tagName(target.os.tag),8861 @tagName(target.os.tag),
...@@ -16793,7 +16804,43 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16793,7 +16804,43 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16793 .val = (try pt.aggregateValue(type_opaque_ty, &field_values)).toIntern(),16804 .val = (try pt.aggregateValue(type_opaque_ty, &field_values)).toIntern(),
16794 })));16805 })));
16795 },16806 },
16796 .spirv => unreachable, // TODO: ALI16807 .spirv => {
16808 const spirv_info = ip.loadSpirvType(ty.toIntern());
16809 const spirv_union_ty = try sema.getStdLangType(src, .@"Type.Spirv");
16810 const spirv_tag_ty = spirv_union_ty.unionTagType(zcu).?;
16811 const spirv_tag_val = try pt.enumValueFieldIndex(spirv_tag_ty, @intFromEnum(spirv_info.flags.tag));
16812 const spirv_payload_val: Value = switch (spirv_info.flags.tag) {
16813 .sampler => .void,
16814 .sampled_image, .runtime_array => .fromInterned(spirv_info.ty),
16815 .image => image: {
16816 const image_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image");
16817 const usage_union_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Usage");
16818 const format_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Format");
16819 const dim_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Dimensionality");
16820 const depth_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Depth");
16821 const access_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Access");
16822 const usage_tag_ty = usage_union_ty.unionTagType(zcu).?;
16823 const usage_tag_val = try pt.enumValueFieldIndex(usage_tag_ty, @intFromEnum(spirv_info.flags.usage));
16824 const usage_val = try pt.unionValue(usage_union_ty, usage_tag_val, .fromInterned(spirv_info.ty));
16825 const image_field_vals = [_]InternPool.Index{
16826 usage_val.toIntern(),
16827 (try pt.enumValueFieldIndex(format_ty, @intFromEnum(spirv_info.flags.format))).toIntern(),
16828 (try pt.enumValueFieldIndex(dim_ty, @intFromEnum(spirv_info.flags.dim))).toIntern(),
16829 (try pt.enumValueFieldIndex(depth_ty, @intFromEnum(spirv_info.flags.depth))).toIntern(),
16830 (try pt.enumValueFieldIndex(access_ty, @intFromEnum(spirv_info.flags.access))).toIntern(),
16831 Value.makeBool(spirv_info.flags.is_arrayed).toIntern(),
16832 Value.makeBool(spirv_info.flags.is_multisampled).toIntern(),
16833 };
16834 break :image try pt.aggregateValue(image_ty, &image_field_vals);
16835 },
16836 };
16837 const spirv_val = try pt.unionValue(spirv_union_ty, spirv_tag_val, spirv_payload_val);
16838 return Air.internedToRef((try pt.internUnion(.{
16839 .ty = type_info_ty.toIntern(),
16840 .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.lang.TypeId.spirv))).toIntern(),
16841 .val = spirv_val.toIntern(),
16842 })));
16843 },
16797 .frame => return sema.failWithUseOfAsync(block, src),16844 .frame => return sema.failWithUseOfAsync(block, src),
16798 .@"anyframe" => return sema.failWithUseOfAsync(block, src),16845 .@"anyframe" => return sema.failWithUseOfAsync(block, src),
16799 }16846 }
...@@ -20594,62 +20641,59 @@ fn zirReifySpirvType(...@@ -20594,62 +20641,59 @@ fn zirReifySpirvType(
20594 break :ip_data .{20641 break :ip_data .{
20595 .name = name,20642 .name = name,
20596 .zir_index = tracked_inst,20643 .zir_index = tracked_inst,
20597 .ty = switch (usage_tag) {20644 .ty = blk: {
20598 .sampled, .unknown => blk: {20645 const sampled_type = usage_val.unionPayload(zcu).toType();
20599 const sampled_type = usage_val.unionPayload(zcu).toType();20646 std.hash.autoHash(&hasher, sampled_type.toIntern());
20600 std.hash.autoHash(&hasher, sampled_type.toIntern());
2060120647
20602 if (target.os.tag != .opencl and sampled_type.toIntern() == .void_type) {20648 if (target.os.tag != .opencl and sampled_type.toIntern() == .void_type) {
20603 return sema.fail(block, operand_src, "'void' type for '{t}' field is only valid under the 'opencl' os", .{usage_tag});20649 return sema.fail(block, operand_src, "'void' type for '{t}' field is only valid under the 'opencl' os", .{usage_tag});
20604 }20650 }
20605 if (target.os.tag == .opencl and sampled_type.toIntern() != .void_type) {20651 if (target.os.tag == .opencl and sampled_type.toIntern() != .void_type) {
20606 return sema.fail(block, operand_src, "'{t}' field type must be 'void' under the 'opencl' os", .{usage_tag});20652 return sema.fail(block, operand_src, "'{t}' field type must be 'void' under the 'opencl' os", .{usage_tag});
20607 }20653 }
2060820654
20609 if (sampled_type.toIntern() != .void_type and20655 if (sampled_type.toIntern() != .void_type and
20610 (!sampled_type.hasRuntimeBits(zcu) or (!sampled_type.isRuntimeFloat() and !sampled_type.isInt(zcu))))20656 (!sampled_type.hasRuntimeBits(zcu) or (!sampled_type.isRuntimeFloat() and !sampled_type.isInt(zcu))))
20611 {20657 {
20612 return sema.fail(block, operand_src, "invalid '{t}' field value '{f}'", .{ usage_tag, sampled_type.fmt(pt) });20658 return sema.fail(block, operand_src, "invalid '{t}' field value '{f}'", .{ usage_tag, sampled_type.fmt(pt) });
20659 }
20660
20661 if (target.os.tag == .vulkan) {
20662 const ok = (sampled_type.isRuntimeFloat() and sampled_type.bitSize(zcu) == 32) or
20663 (sampled_type.isInt(zcu) and (sampled_type.bitSize(zcu) == 32 or sampled_type.bitSize(zcu) == 64));
20664 if (!ok) {
20665 return sema.fail(
20666 block,
20667 operand_src,
20668 "'{t}' field value must be a 32-bit int, 64-bit int or 32-bit float under the 'vulkan' os",
20669 .{usage_tag},
20670 );
20613 }20671 }
2061420672
20615 if (target.os.tag == .vulkan) {20673 if (format != .unknown) {
20616 const ok = (sampled_type.isRuntimeFloat() and sampled_type.bitSize(zcu) == 32) or20674 const format_kind: enum { float, sint, uint } = switch (format) {
20617 (sampled_type.isInt(zcu) and (sampled_type.bitSize(zcu) == 32 or sampled_type.bitSize(zcu) == 64));20675 .rgba32f, .rgba16f, .rgba8unorm, .rgba8snorm, .r32f => .float,
20618 if (!ok) {20676 .rgba32i, .rgba16i, .rgba8i, .r32i => .sint,
20677 .rgba32u, .rgba16u, .rgba8u, .r32u => .uint,
20678 .unknown => unreachable,
20679 };
20680 const matches = switch (format_kind) {
20681 .float => sampled_type.isRuntimeFloat(),
20682 .sint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .signed,
20683 .uint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .unsigned,
20684 };
20685 if (!matches) {
20619 return sema.fail(20686 return sema.fail(
20620 block,20687 block,
20621 operand_src,20688 operand_src,
20622 "'{t}' field value must be a 32-bit int, 64-bit int or 32-bit float under the 'vulkan' os",20689 "image 'format' '.{t}' does not match '{t}' type '{f}' under the 'vulkan' os",
20623 .{usage_tag},20690 .{ format, usage_tag, sampled_type.fmt(pt) },
20624 );20691 );
20625 }20692 }
20626
20627 if (format != .unknown) {
20628 const format_kind: enum { float, sint, uint } = switch (format) {
20629 .rgba32f, .rgba16f, .rgba8unorm, .rgba8snorm, .r32f => .float,
20630 .rgba32i, .rgba16i, .rgba8i, .r32i => .sint,
20631 .rgba32u, .rgba16u, .rgba8u, .r32u => .uint,
20632 .unknown => unreachable,
20633 };
20634 const matches = switch (format_kind) {
20635 .float => sampled_type.isRuntimeFloat(),
20636 .sint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .signed,
20637 .uint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .unsigned,
20638 };
20639 if (!matches) {
20640 return sema.fail(
20641 block,
20642 operand_src,
20643 "image 'format' '.{t}' does not match '{t}' type '{f}' under the 'vulkan' os",
20644 .{ format, usage_tag, sampled_type.fmt(pt) },
20645 );
20646 }
20647 }
20648 }20693 }
20694 }
2064920695
20650 break :blk sampled_type.toIntern();20696 break :blk sampled_type.toIntern();
20651 },
20652 .storage => .none,
20653 },20697 },
20654 .flags = .{20698 .flags = .{
20655 .tag = .image,20699 .tag = .image,
src/Zcu.zig+13-1
...@@ -469,6 +469,12 @@ pub const StdLangDecl = enum {...@@ -469,6 +469,12 @@ pub const StdLangDecl = enum {
469 @"Type.ContainerLayout",469 @"Type.ContainerLayout",
470 @"Type.Opaque",470 @"Type.Opaque",
471 @"Type.Spirv",471 @"Type.Spirv",
472 @"Type.Spirv.Image",
473 @"Type.Spirv.Image.Usage",
474 @"Type.Spirv.Image.Format",
475 @"Type.Spirv.Image.Dimensionality",
476 @"Type.Spirv.Image.Depth",
477 @"Type.Spirv.Image.Access",
472478
473 panic,479 panic,
474 @"panic.call",480 @"panic.call",
...@@ -550,6 +556,12 @@ pub const StdLangDecl = enum {...@@ -550,6 +556,12 @@ pub const StdLangDecl = enum {
550 .@"Type.ContainerLayout",556 .@"Type.ContainerLayout",
551 .@"Type.Opaque",557 .@"Type.Opaque",
552 .@"Type.Spirv",558 .@"Type.Spirv",
559 .@"Type.Spirv.Image",
560 .@"Type.Spirv.Image.Usage",
561 .@"Type.Spirv.Image.Format",
562 .@"Type.Spirv.Image.Dimensionality",
563 .@"Type.Spirv.Image.Depth",
564 .@"Type.Spirv.Image.Access",
553 => .type,565 => .type,
554566
555 .panic => .type,567 .panic => .type,
...@@ -603,7 +615,7 @@ pub const StdLangDecl = enum {...@@ -603,7 +615,7 @@ pub const StdLangDecl = enum {
603 .VaList => .va_list,615 .VaList => .va_list,
604 .assembly, .@"assembly.Clobbers" => .assembly,616 .assembly, .@"assembly.Clobbers" => .assembly,
605 else => {617 else => {
606 if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Spirv")) {618 if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Spirv.Image.Access")) {
607 return .main;619 return .main;
608 } else {620 } else {
609 return .panic;621 return .panic;
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+1720-1273
...@@ -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
...@@ -337,19 +725,22 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -337,19 +725,22 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
337 const val = zcu.navValue(cg.owner_nav);725 const val = zcu.navValue(cg.owner_nav);
338 const ty = val.typeOf(zcu);726 const ty = val.typeOf(zcu);
339727
340 if (!do_codegen and !ty.hasRuntimeBits(zcu)) return;728 if (!do_codegen and !ty.hasRuntimeBits(zcu)) {
729 const child_ty = if (ty.zigTypeTag(zcu) == .pointer) ty.childType(zcu) else ty;
730 if (child_ty.zigTypeTag(zcu) != .spirv) return;
731 }
341732
342 const spv_decl_index = try cg.module.resolveNav(ip, cg.owner_nav);733 const spv_decl_index = try cg.resolveNav(ip, cg.owner_nav);
343 const decl = cg.module.declPtr(spv_decl_index);734 const decl = cg.declPtr(spv_decl_index);
344 const result_id = decl.result_id;735 const result_id = decl.result_id;
345 decl.begin_dep = cg.module.decl_deps.items.len;736 decl.begin_dep = cg.decl_deps.items.len;
346737
347 switch (decl.kind) {738 switch (decl.kind) {
348 .func => {739 .func => {
349 if (nav.resolved.?.is_extern_decl) {740 if (nav.resolved.?.is_extern_decl) {
350 _ = try cg.resolveType(ty, .direct);741 _ = try cg.resolveType(ty, .direct);
351 try emitExternFnStub(cg, nav, decl, ty);742 try emitExternFnStub(cg, nav, decl, ty);
352 decl.end_dep = cg.module.decl_deps.items.len;743 decl.end_dep = cg.decl_deps.items.len;
353 return;744 return;
354 }745 }
355746
...@@ -357,7 +748,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -357,7 +748,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
357 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));748 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
358 const is_test = zcu.test_functions.contains(cg.owner_nav);749 const is_test = zcu.test_functions.contains(cg.owner_nav);
359750
360 const func_result_id = if (is_test) cg.module.allocId() else result_id;751 const func_result_id = if (is_test) cg.allocId() else result_id;
361 const prototype_ty_id = try cg.resolveType(ty, .direct);752 const prototype_ty_id = try cg.resolveType(ty, .direct);
362 try cg.prologue.emit(gpa, .OpFunction, .{753 try cg.prologue.emit(gpa, .OpFunction, .{
363 .id_result_type = return_ty_id,754 .id_result_type = return_ty_id,
...@@ -368,14 +759,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -368,14 +759,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
368 .function_control = .{},759 .function_control = .{},
369 });760 });
370761
371 comptime assert(zig_call_abi_ver == 3);
372 try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len);762 try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len);
373 for (fn_info.param_types.get(ip)) |param_ty_index| {763 for (fn_info.param_types.get(ip)) |param_ty_index| {
374 const param_ty: Type = .fromInterned(param_ty_index);764 const param_ty: Type = .fromInterned(param_ty_index);
375 if (!param_ty.hasRuntimeBits(zcu)) continue;765 if (!param_ty.hasRuntimeBits(zcu)) continue;
376766
377 const param_type_id = try cg.resolveType(param_ty, .direct);767 const param_type_id = try cg.resolveType(param_ty, .direct);
378 const arg_result_id = cg.module.allocId();768 const arg_result_id = cg.allocId();
379 try cg.prologue.emit(gpa, .OpFunctionParameter, .{769 try cg.prologue.emit(gpa, .OpFunctionParameter, .{
380 .id_result_type = param_type_id,770 .id_result_type = param_type_id,
381 .id_result = arg_result_id,771 .id_result = arg_result_id,
...@@ -384,7 +774,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -384,7 +774,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
384 }774 }
385775
386 // TODO: This could probably be done in a better way...776 // TODO: This could probably be done in a better way...
387 const root_block_id = cg.module.allocId();777 const root_block_id = cg.allocId();
388778
389 // The root block of a function declaration should appear before OpVariable instructions,779 // The root block of a function declaration should appear before OpVariable instructions,
390 // so it is generated into the function's prologue.780 // so it is generated into the function's prologue.
...@@ -400,26 +790,26 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -400,26 +790,26 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
400 try cg.body.emit(gpa, .OpUnreachable, {});790 try cg.body.emit(gpa, .OpUnreachable, {});
401 try cg.body.emit(gpa, .OpFunctionEnd, {});791 try cg.body.emit(gpa, .OpFunctionEnd, {});
402 // Append the actual code into the functions section.792 // Append the actual code into the functions section.
403 try cg.module.sections.functions.append(gpa, cg.prologue);793 try cg.sections.functions.append(gpa, cg.prologue);
404 try cg.module.sections.functions.append(gpa, cg.body);794 try cg.sections.functions.append(gpa, cg.body);
405795
406 // Temporarily generate a test kernel declaration if this is a test function.796 // Temporarily generate a test kernel declaration if this is a test function.
407 if (is_test) {797 if (is_test) {
408 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);798 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);
409 }799 }
410800
411 try cg.module.debugName(func_result_id, nav.fqn.toSlice(ip));801 try cg.debugName(func_result_id, nav.fqn.toSlice(ip));
412 },802 },
413 .global => {803 .global => {
414 const key = ip.indexToKey(val.toIntern()).@"extern";804 const key = ip.indexToKey(val.toIntern()).@"extern";
415805
416 const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace");806 const storage_class = cg.storageClass(nav.resolved.?.@"addrspace");
417 assert(storage_class != .generic); // These should be instance globals807 assert(storage_class != .generic); // These should be instance globals
418808
419 const ty_id = try cg.resolveType(ty, .indirect);809 const ty_id = try cg.resolveType(ty, .indirect);
420 const ptr_ty_id = try cg.module.ptrType(ty_id, storage_class);810 const ptr_ty_id = try cg.ptrType(ty_id, storage_class);
421811
422 try cg.module.sections.globals.emit(gpa, .OpVariable, .{812 try cg.sections.globals.emit(gpa, .OpVariable, .{
423 .id_result_type = ptr_ty_id,813 .id_result_type = ptr_ty_id,
424 .id_result = result_id,814 .id_result = result_id,
425 .storage_class = storage_class,815 .storage_class = storage_class,
...@@ -430,11 +820,11 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -430,11 +820,11 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
430 switch (storage_class) {820 switch (storage_class) {
431 .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => {821 .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => {
432 if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) {822 if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) {
433 try cg.module.decorate(ty_id, .block);823 try cg.decorate(ty_id, .block);
434 }824 }
435825
436 if (ty.hasRuntimeBits(zcu)) {826 if (ty.hasRuntimeBits(zcu)) {
437 try cg.module.decorate(ptr_ty_id, .{827 try cg.decorate(ptr_ty_id, .{
438 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },828 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },
439 });829 });
440 try cg.decorateLayout(ty, ty_id);830 try cg.decorateLayout(ty, ty_id);
...@@ -448,23 +838,23 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -448,23 +838,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) {838 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)});839 return cg.fail("storage class must be one of (output, input, uniform_constant) but is {s}", .{@tagName(storage_class)});
450 }840 }
451 try cg.module.decorate(result_id, .{841 try cg.decorate(result_id, .{
452 .location = .{ .location = location },842 .location = .{ .location = location },
453 });843 });
454 },844 },
455 .flat => |location| {845 .flat => |location| {
456 try cg.module.decorate(result_id, .{ .location = .{ .location = location } });846 try cg.decorate(result_id, .{ .location = .{ .location = location } });
457 try cg.module.decorate(result_id, .flat);847 try cg.decorate(result_id, .flat);
458 },848 },
459 .descriptor => |descriptor| {849 .descriptor => |descriptor| {
460 if (storage_class != .storage_buffer and storage_class != .uniform and storage_class != .uniform_constant) {850 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)});851 return cg.fail("storage class must be one of (storage_buffer, uniform, uniform_constant) but is {s}", .{@tagName(storage_class)});
462 }852 }
463 try cg.module.decorate(result_id, .{853 try cg.decorate(result_id, .{
464 .binding = .{ .binding_point = descriptor.binding },854 .binding = .{ .binding_point = descriptor.binding },
465 });855 });
466856
467 try cg.module.decorate(result_id, .{857 try cg.decorate(result_id, .{
468 .descriptor_set = .{ .descriptor_set = descriptor.set },858 .descriptor_set = .{ .descriptor_set = descriptor.set },
469 });859 });
470 },860 },
...@@ -474,10 +864,10 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -474,10 +864,10 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
474 }864 }
475865
476 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |built_in| {866 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 } });867 try cg.decorate(result_id, .{ .built_in = .{ .built_in = built_in } });
478 }868 }
479869
480 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));870 try cg.debugName(result_id, nav.fqn.toSlice(ip));
481 },871 },
482 .invocation_global => {872 .invocation_global => {
483 // `@extern()` produces an invocation_global whose value is a873 // `@extern()` produces an invocation_global whose value is a
...@@ -488,18 +878,18 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -488,18 +878,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;878 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);879 const underlying_nav = ip.getNav(ptr_key.base_addr.nav);
490 if (!underlying_nav.resolved.?.is_extern_decl) break :alias;880 if (!underlying_nav.resolved.?.is_extern_decl) break :alias;
491 cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len;881 cg.declPtr(spv_decl_index).end_dep = cg.decl_deps.items.len;
492 return;882 return;
493 }883 }
494884
495 const ty_id = try cg.resolveType(ty, .indirect);885 const ty_id = try cg.resolveType(ty, .indirect);
496 const ptr_ty_id = try cg.module.ptrType(ty_id, .function);886 const ptr_ty_id = try cg.ptrType(ty_id, .function);
497887
498 // TODO: Combine with resolveAnonDecl?888 // TODO: Combine with resolveAnonDecl?
499 const void_ty_id = try cg.resolveType(.void, .direct);889 const void_ty_id = try cg.resolveType(.void, .direct);
500 const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});890 const initializer_proto_ty_id = try cg.functionType(void_ty_id, &.{});
501891
502 const initializer_id = cg.module.allocId();892 const initializer_id = cg.allocId();
503 try cg.prologue.emit(gpa, .OpFunction, .{893 try cg.prologue.emit(gpa, .OpFunction, .{
504 .id_result_type = try cg.resolveType(.void, .direct),894 .id_result_type = try cg.resolveType(.void, .direct),
505 .id_result = initializer_id,895 .id_result = initializer_id,
...@@ -507,7 +897,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -507,7 +897,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
507 .function_type = initializer_proto_ty_id,897 .function_type = initializer_proto_ty_id,
508 });898 });
509899
510 const root_block_id = cg.module.allocId();900 const root_block_id = cg.allocId();
511 try cg.prologue.emit(gpa, .OpLabel, .{901 try cg.prologue.emit(gpa, .OpLabel, .{
512 .id_result = root_block_id,902 .id_result = root_block_id,
513 });903 });
...@@ -521,33 +911,33 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -521,33 +911,33 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
521911
522 try cg.body.emit(gpa, .OpReturn, {});912 try cg.body.emit(gpa, .OpReturn, {});
523 try cg.body.emit(gpa, .OpFunctionEnd, {});913 try cg.body.emit(gpa, .OpFunctionEnd, {});
524 try cg.module.sections.functions.append(gpa, cg.prologue);914 try cg.sections.functions.append(gpa, cg.prologue);
525 try cg.module.sections.functions.append(gpa, cg.body);915 try cg.sections.functions.append(gpa, cg.body);
526916
527 try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});917 try cg.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
528 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));918 try cg.debugName(result_id, nav.fqn.toSlice(ip));
529919
530 try cg.module.sections.globals.emit(gpa, .OpExtInst, .{920 try cg.sections.globals.emit(gpa, .OpExtInst, .{
531 .id_result_type = ptr_ty_id,921 .id_result_type = ptr_ty_id,
532 .id_result = result_id,922 .id_result = result_id,
533 .set = try cg.module.importInstructionSet(.zig),923 .set = try cg.importInstructionSet(.zig),
534 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },924 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
535 .id_ref_4 = &.{initializer_id},925 .id_ref_4 = &.{initializer_id},
536 });926 });
537 },927 },
538 }928 }
539929
540 cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len;930 cg.declPtr(spv_decl_index).end_dep = cg.decl_deps.items.len;
541}931}
542932
543fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {933fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
544 const zcu = cg.module.zcu;934 const zcu = cg.zcu;
545 const ip = &zcu.intern_pool;935 const ip = &zcu.intern_pool;
546 switch (ty.zigTypeTag(zcu)) {936 switch (ty.zigTypeTag(zcu)) {
547 .array => {937 .array => {
548 const elem_ty = ty.childType(zcu);938 const elem_ty = ty.childType(zcu);
549 if (!elem_ty.hasRuntimeBits(zcu)) return;939 if (!elem_ty.hasRuntimeBits(zcu)) return;
550 try cg.module.decorate(ty_id, .{940 try cg.decorate(ty_id, .{
551 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },941 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
552 });942 });
553 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));943 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
...@@ -556,7 +946,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {...@@ -556,7 +946,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
556 const elem_ty = ty.childType(zcu);946 const elem_ty = ty.childType(zcu);
557 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));947 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
558 if (cg.isSpvVector(ty)) return;948 if (cg.isSpvVector(ty)) return;
559 try cg.module.decorate(ty_id, .{949 try cg.decorate(ty_id, .{
560 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },950 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
561 });951 });
562 },952 },
...@@ -570,7 +960,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {...@@ -570,7 +960,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]);960 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
571 if (!field_ty.hasRuntimeBits(zcu)) continue;961 if (!field_ty.hasRuntimeBits(zcu)) continue;
572 const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu));962 const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu));
573 try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } });963 try cg.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } });
574 try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect));964 try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect));
575 member += 1;965 member += 1;
576 }966 }
...@@ -598,13 +988,13 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {...@@ -598,13 +988,13 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
598 const u8_id = try cg.resolveType(.u8, .direct);988 const u8_id = try cg.resolveType(.u8, .direct);
599 if (layout.payload_padding_size != 0) {989 if (layout.payload_padding_size != 0) {
600 const len_id = try cg.constInt(.u32, layout.payload_padding_size);990 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
601 const arr_id = try cg.module.arrayType(len_id, u8_id);991 const arr_id = try cg.arrayType(len_id, u8_id);
602 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });992 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
603 }993 }
604 if (layout.padding_size != 0) {994 if (layout.padding_size != 0) {
605 const len_id = try cg.constInt(.u32, layout.padding_size);995 const len_id = try cg.constInt(.u32, layout.padding_size);
606 const arr_id = try cg.module.arrayType(len_id, u8_id);996 const arr_id = try cg.arrayType(len_id, u8_id);
607 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });997 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
608 }998 }
609 },999 },
610 .optional => {1000 .optional => {
...@@ -621,7 +1011,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {...@@ -621,7 +1011,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
6211011
622pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {1012pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
623 @branchHint(.cold);1013 @branchHint(.cold);
624 return cg.module.zcu.codegenFail(cg.owner_nav, format, args);1014 return cg.zcu.codegenFail(cg.owner_nav, format, args);
625}1015}
6261016
627pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {1017pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
...@@ -631,17 +1021,17 @@ pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {...@@ -631,17 +1021,17 @@ pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
631/// This imports the "default" extended instruction set for the target1021/// This imports the "default" extended instruction set for the target
632/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.1022/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.
633fn importExtendedSet(cg: *CodeGen) !Id {1023fn importExtendedSet(cg: *CodeGen) !Id {
634 const target = cg.module.zcu.getTarget();1024 const target = cg.zcu.getTarget();
635 return switch (target.os.tag) {1025 return switch (target.os.tag) {
636 .opencl, .amdhsa => try cg.module.importInstructionSet(.@"OpenCL.std"),1026 .opencl, .amdhsa => try cg.importInstructionSet(.@"OpenCL.std"),
637 .vulkan, .opengl => try cg.module.importInstructionSet(.@"GLSL.std.450"),1027 .vulkan, .opengl => try cg.importInstructionSet(.@"GLSL.std.450"),
638 else => unreachable,1028 else => unreachable,
639 };1029 };
640}1030}
6411031
642/// Fetch the result-id for a previously generated instruction or constant.1032/// Fetch the result-id for a previously generated instruction or constant.
643fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {1033fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
644 const zcu = cg.module.zcu;1034 const zcu = cg.zcu;
645 const ip = &zcu.intern_pool;1035 const ip = &zcu.intern_pool;
646 if (inst.toInterned()) |val_ip_index| {1036 if (inst.toInterned()) |val_ip_index| {
647 const ty = cg.typeOf(inst);1037 const ty = cg.typeOf(inst);
...@@ -652,9 +1042,9 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {...@@ -652,9 +1042,9 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
652 .func => |func| func.owner_nav,1042 .func => |func| func.owner_nav,
653 else => unreachable,1043 else => unreachable,
654 };1044 };
655 const spv_decl_index = try cg.module.resolveNav(ip, fn_nav);1045 const spv_decl_index = try cg.resolveNav(ip, fn_nav);
656 try cg.module.decl_deps.append(cg.module.gpa, spv_decl_index);1046 try cg.decl_deps.append(cg.gpa, spv_decl_index);
657 const decl = cg.module.declPtr(spv_decl_index);1047 const decl = cg.declPtr(spv_decl_index);
658 if (val_key == .@"extern") {1048 if (val_key == .@"extern") {
659 const nav = ip.getNav(fn_nav);1049 const nav = ip.getNav(fn_nav);
660 const nav_ty: Type = .fromInterned(nav.resolved.?.type);1050 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
...@@ -670,22 +1060,22 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {...@@ -670,22 +1060,22 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
670}1060}
6711061
672fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {1062fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
673 const gpa = cg.module.gpa;1063 const gpa = cg.gpa;
6741064
675 // TODO: This cannot be a function at this point, but it should probably be handled anyway.1065 // TODO: This cannot be a function at this point, but it should probably be handled anyway.
6761066
677 const zcu = cg.module.zcu;1067 const zcu = cg.zcu;
678 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));1068 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
679 const ty_id = try cg.resolveType(ty, .indirect);1069 const ty_id = try cg.resolveType(ty, .indirect);
6801070
681 const spv_decl_index = blk: {1071 const spv_decl_index = blk: {
682 const entry = try cg.module.uav_link.getOrPut(gpa, .{ val, .function });1072 const entry = try cg.uav_link.getOrPut(gpa, .{ val, .function });
683 if (entry.found_existing) {1073 if (entry.found_existing) {
684 try cg.addFunctionDep(entry.value_ptr.*, .function);1074 try cg.addFunctionDep(entry.value_ptr.*, .function);
685 return cg.module.declPtr(entry.value_ptr.*).result_id;1075 return cg.declPtr(entry.value_ptr.*).result_id;
686 }1076 }
6871077
688 const spv_decl_index = try cg.module.allocDecl(.invocation_global);1078 const spv_decl_index = try cg.allocDecl(.invocation_global);
689 try cg.addFunctionDep(spv_decl_index, .function);1079 try cg.addFunctionDep(spv_decl_index, .function);
690 entry.value_ptr.* = spv_decl_index;1080 entry.value_ptr.* = spv_decl_index;
691 break :blk spv_decl_index;1081 break :blk spv_decl_index;
...@@ -697,7 +1087,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -697,7 +1087,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
697 // constant lowering of this value will need to be deferred to an initializer similar to1087 // constant lowering of this value will need to be deferred to an initializer similar to
698 // other globals.1088 // other globals.
6991089
700 const result_id = cg.module.declPtr(spv_decl_index).result_id;1090 const result_id = cg.declPtr(spv_decl_index).result_id;
7011091
702 {1092 {
703 // Save the current state so that we can temporarily generate into a different function.1093 // Save the current state so that we can temporarily generate into a different function.
...@@ -719,16 +1109,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -719,16 +1109,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
719 }1109 }
7201110
721 const void_ty_id = try cg.resolveType(.void, .direct);1111 const void_ty_id = try cg.resolveType(.void, .direct);
722 const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});1112 const initializer_proto_ty_id = try cg.functionType(void_ty_id, &.{});
7231113
724 const initializer_id = cg.module.allocId();1114 const initializer_id = cg.allocId();
725 try cg.prologue.emit(gpa, .OpFunction, .{1115 try cg.prologue.emit(gpa, .OpFunction, .{
726 .id_result_type = try cg.resolveType(.void, .direct),1116 .id_result_type = try cg.resolveType(.void, .direct),
727 .id_result = initializer_id,1117 .id_result = initializer_id,
728 .function_control = .{},1118 .function_control = .{},
729 .function_type = initializer_proto_ty_id,1119 .function_type = initializer_proto_ty_id,
730 });1120 });
731 const root_block_id = cg.module.allocId();1121 const root_block_id = cg.allocId();
732 try cg.prologue.emit(gpa, .OpLabel, .{1122 try cg.prologue.emit(gpa, .OpLabel, .{
733 .id_result = root_block_id,1123 .id_result = root_block_id,
734 });1124 });
...@@ -743,16 +1133,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -743,16 +1133,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
743 try cg.body.emit(gpa, .OpReturn, {});1133 try cg.body.emit(gpa, .OpReturn, {});
744 try cg.body.emit(gpa, .OpFunctionEnd, {});1134 try cg.body.emit(gpa, .OpFunctionEnd, {});
7451135
746 try cg.module.sections.functions.append(gpa, cg.prologue);1136 try cg.sections.functions.append(gpa, cg.prologue);
747 try cg.module.sections.functions.append(gpa, cg.body);1137 try cg.sections.functions.append(gpa, cg.body);
7481138
749 try cg.module.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});1139 try cg.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
7501140
751 const fn_decl_ptr_ty_id = try cg.module.ptrType(ty_id, .function);1141 const fn_decl_ptr_ty_id = try cg.ptrType(ty_id, .function);
752 try cg.module.sections.globals.emit(gpa, .OpExtInst, .{1142 try cg.sections.globals.emit(gpa, .OpExtInst, .{
753 .id_result_type = fn_decl_ptr_ty_id,1143 .id_result_type = fn_decl_ptr_ty_id,
754 .id_result = result_id,1144 .id_result = result_id,
755 .set = try cg.module.importInstructionSet(.zig),1145 .set = try cg.importInstructionSet(.zig),
756 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },1146 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
757 .id_ref_4 = &.{initializer_id},1147 .id_ref_4 = &.{initializer_id},
758 });1148 });
...@@ -761,15 +1151,21 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -761,15 +1151,21 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
761 return result_id;1151 return result_id;
762}1152}
7631153
764fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void {1154fn resolvePtr(cg: *CodeGen, ref: Air.Inst.Ref) !Ptr {
765 const gpa = cg.module.gpa;1155 const id = try cg.resolve(ref);
766 const target = cg.module.zcu.getTarget();1156 if (cg.tracked_allocas.getPtr(id)) |slot| return .{ .tracked = .{ .id = id, .slot = slot } };
1157 return .{ .id = id };
1158}
1159
1160fn addFunctionDep(cg: *CodeGen, decl_index: Decl.Index, storage_class: StorageClass) !void {
1161 const gpa = cg.gpa;
1162 const target = cg.zcu.getTarget();
767 if (target.cpu.has(.spirv, .v1_4)) {1163 if (target.cpu.has(.spirv, .v1_4)) {
768 try cg.module.decl_deps.append(gpa, decl_index);1164 try cg.decl_deps.append(gpa, decl_index);
769 } else {1165 } else {
770 // Before version 1.4, the interface’s storage classes are limited to the Input and Output1166 // 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) {1167 if (storage_class == .input or storage_class == .output) {
772 try cg.module.decl_deps.append(gpa, decl_index);1168 try cg.decl_deps.append(gpa, decl_index);
773 }1169 }
774 }1170 }
775}1171}
...@@ -779,25 +1175,11 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St...@@ -779,25 +1175,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 to1175/// 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.1176/// keep track of the previous block.
781fn beginSpvBlock(cg: *CodeGen, label: Id) !void {1177fn beginSpvBlock(cg: *CodeGen, label: Id) !void {
782 try cg.body.emit(cg.module.gpa, .OpLabel, .{ .id_result = label });1178 try cg.body.emit(cg.gpa, .OpLabel, .{ .id_result = label });
783 cg.block_label = label;1179 cg.block_label = label;
784 cg.block_terminated = false;1180 cg.block_terminated = false;
785}1181}
7861182
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 {1183const ArithmeticTypeInfo = struct {
802 const Class = enum {1184 const Class = enum {
803 bool,1185 bool,
...@@ -835,8 +1217,8 @@ const ArithmeticTypeInfo = struct {...@@ -835,8 +1217,8 @@ const ArithmeticTypeInfo = struct {
835};1217};
8361218
837fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {1219fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
838 const zcu = cg.module.zcu;1220 const zcu = cg.zcu;
839 const target = cg.module.zcu.getTarget();1221 const target = cg.zcu.getTarget();
840 var scalar_ty = ty.scalarType(zcu);1222 var scalar_ty = ty.scalarType(zcu);
841 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {1223 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {
842 scalar_ty = scalar_ty.intTagType(zcu);1224 scalar_ty = scalar_ty.intTagType(zcu);
...@@ -845,7 +1227,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -845,7 +1227,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
845 return switch (scalar_ty.zigTypeTag(zcu)) {1227 return switch (scalar_ty.zigTypeTag(zcu)) {
846 .bool => .{1228 .bool => .{
847 .bits = 1, // Doesn't matter for this class.1229 .bits = 1, // Doesn't matter for this class.
848 .backing_bits = cg.module.backingIntBits(1).@"0",1230 .backing_bits = cg.backingIntBits(1).@"0",
849 .vector_len = vector_len,1231 .vector_len = vector_len,
850 .signedness = .unsigned, // Technically, but doesn't matter for this class.1232 .signedness = .unsigned, // Technically, but doesn't matter for this class.
851 .class = .bool,1233 .class = .bool,
...@@ -860,7 +1242,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -860,7 +1242,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
860 .int => blk: {1242 .int => blk: {
861 const int_info = scalar_ty.intInfo(zcu);1243 const int_info = scalar_ty.intInfo(zcu);
862 // TODO: Maybe it's useful to also return this value.1244 // TODO: Maybe it's useful to also return this value.
863 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);1245 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
864 break :blk .{1246 break :blk .{
865 .bits = int_info.bits,1247 .bits = int_info.bits,
866 .backing_bits = backing_bits,1248 .backing_bits = backing_bits,
...@@ -880,8 +1262,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -880,8 +1262,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8801262
881/// Checks whether the type can be directly translated to SPIR-V vectors1263/// Checks whether the type can be directly translated to SPIR-V vectors
882fn isSpvVector(cg: *CodeGen, ty: Type) bool {1264fn isSpvVector(cg: *CodeGen, ty: Type) bool {
883 const zcu = cg.module.zcu;1265 const zcu = cg.zcu;
884 const target = cg.module.zcu.getTarget();1266 const target = cg.zcu.getTarget();
885 if (ty.zigTypeTag(zcu) != .vector) return false;1267 if (ty.zigTypeTag(zcu) != .vector) return false;
8861268
887 // TODO: This check must be expanded for types that can be represented1269 // TODO: This check must be expanded for types that can be represented
...@@ -909,23 +1291,34 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {...@@ -909,23 +1291,34 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {
9091291
910/// Emits a bool constant in a particular representation.1292/// Emits a bool constant in a particular representation.
911fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {1293fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {
912 return switch (repr) {1294 switch (repr) {
913 .indirect => cg.constInt(.u1, @intFromBool(value)),1295 .indirect => return cg.constInt(.u1, @intFromBool(value)),
914 .direct => cg.module.constBool(value),1296 .direct => {
915 };1297 const result_ty_id = try cg.boolType();
1298 const result_id = cg.allocId();
1299 switch (value) {
1300 inline else => |value_ct| try cg.sections.globals.emit(
1301 cg.gpa,
1302 if (value_ct) .OpConstantTrue else .OpConstantFalse,
1303 .{ .id_result_type = result_ty_id, .id_result = result_id },
1304 ),
1305 }
1306 return result_id;
1307 },
1308 }
916}1309}
9171310
918/// Emits an integer constant.1311/// Emits an integer constant.
919/// This function, unlike Module.constInt, takes care to bitcast1312/// This function, unlike cg.constInt, takes care to bitcast
920/// the value to an unsigned int first for Kernels.1313/// the value to an unsigned int first for Kernels.
921fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {1314fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
922 const gpa = cg.module.gpa;1315 const gpa = cg.gpa;
923 const zcu = cg.module.zcu;1316 const zcu = cg.zcu;
924 const target = cg.module.zcu.getTarget();1317 const target = cg.zcu.getTarget();
925 const scalar_ty = ty.scalarType(zcu);1318 const scalar_ty = ty.scalarType(zcu);
926 const int_info = scalar_ty.intInfo(zcu);1319 const int_info = scalar_ty.intInfo(zcu);
927 // Use backing bits so that negatives are sign extended1320 // Use backing bits so that negatives are sign extended
928 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);1321 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
929 assert(backing_bits != 0); // u0 is comptime1322 assert(backing_bits != 0); // u0 is comptime
9301323
931 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);1324 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);
...@@ -939,7 +1332,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -939,7 +1332,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
939 .signed => @bitCast(@as(i64, @intCast(value))),1332 .signed => @bitCast(@as(i64, @intCast(value))),
940 .unsigned => @as(u64, @intCast(value)),1333 .unsigned => @as(u64, @intCast(value)),
941 };1334 };
942 const n_limbs = backing_bits / Module.big_int_bits;1335 const n_limbs = backing_bits / big_int_bits;
943 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;1336 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;
944 const scratch_top = cg.id_scratch.items.len;1337 const scratch_top = cg.id_scratch.items.len;
945 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);1338 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
...@@ -979,61 +1372,45 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -979,61 +1372,45 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
979 },1372 },
980 };1373 };
9811374
982 const result_id = try cg.module.constant(result_ty_id, final_value);1375 const result_id = cg.allocId();
1376 try cg.sections.globals.emit(cg.gpa, .OpConstant, .{
1377 .id_result_type = result_ty_id,
1378 .id_result = result_id,
1379 .value = final_value,
1380 });
9831381
984 if (!ty.isVector(zcu)) return result_id;1382 if (!ty.isVector(zcu)) return result_id;
985 return cg.constructCompositeSplat(ty, result_id);1383 return cg.constructCompositeSplat(ty, result_id);
986}1384}
9871385
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.1386/// Construct a composite value from its constituents.
1018/// In logical addressing mode (Vulkan/OpenGL), OpCompositeConstruct cannot accept1387/// 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.1388/// 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 {1389pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id {
1021 const gpa = cg.module.gpa;1390 const gpa = cg.gpa;
10221391
1023 if (cg.module.structFields(result_ty_id)) |fields| {1392 const maybe_fields: ?[]const Id = for (cg.struct_types.keys(), cg.struct_types.values()) |key, val| {
1393 if (val == result_ty_id) break key.fields;
1394 } else null;
1395 if (maybe_fields) |fields| {
1024 assert(fields.len == constituents.len);1396 assert(fields.len == constituents.len);
1025 const u32_ty_id = try cg.module.intType(.unsigned, 32);1397 const u32_ty_id = try cg.intType(.unsigned, 32);
1026 const var_id = try cg.alloc(result_ty_id, null);1398 const var_id = try cg.alloc(result_ty_id, null);
1027 for (fields, constituents, 0..) |field_ty_id, constituent, i| {1399 for (fields, constituents, 0..) |field_ty_id, constituent, i| {
1028 const field_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);1400 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) });1401 const index_id = cg.allocId();
1402 try cg.sections.globals.emit(gpa, .OpConstant, .{
1403 .id_result_type = u32_ty_id,
1404 .id_result = index_id,
1405 .value = .{ .uint32 = @intCast(i) },
1406 });
1030 const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id});1407 const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id});
1031 try cg.body.emit(gpa, .OpStore, .{1408 try cg.body.emit(gpa, .OpStore, .{
1032 .pointer = field_ptr,1409 .pointer = field_ptr,
1033 .object = constituent,1410 .object = constituent,
1034 });1411 });
1035 }1412 }
1036 const result_id = cg.module.allocId();1413 const result_id = cg.allocId();
1037 try cg.body.emit(gpa, .OpLoad, .{1414 try cg.body.emit(gpa, .OpLoad, .{
1038 .id_result_type = result_ty_id,1415 .id_result_type = result_ty_id,
1039 .id_result = result_id,1416 .id_result = result_id,
...@@ -1042,7 +1419,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const...@@ -1042,7 +1419,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
1042 return result_id;1419 return result_id;
1043 }1420 }
10441421
1045 const result_id = cg.module.allocId();1422 const result_id = cg.allocId();
1046 try cg.body.emit(gpa, .OpCompositeConstruct, .{1423 try cg.body.emit(gpa, .OpCompositeConstruct, .{
1047 .id_result_type = result_ty_id,1424 .id_result_type = result_ty_id,
1048 .id_result = result_id,1425 .id_result = result_id,
...@@ -1054,8 +1431,8 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const...@@ -1054,8 +1431,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.1431/// Construct a composite at runtime with all lanes set to the same value.
1055/// ty must be an aggregate type.1432/// ty must be an aggregate type.
1056fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {1433fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
1057 const gpa = cg.module.gpa;1434 const gpa = cg.gpa;
1058 const zcu = cg.module.zcu;1435 const zcu = cg.zcu;
1059 const n: usize = @intCast(ty.arrayLen(zcu));1436 const n: usize = @intCast(ty.arrayLen(zcu));
10601437
1061 const scratch_top = cg.id_scratch.items.len;1438 const scratch_top = cg.id_scratch.items.len;
...@@ -1075,24 +1452,17 @@ fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {...@@ -1075,24 +1452,17 @@ fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
1075//1452//
1076/// This function should only be called during function code generation.1453/// This function should only be called during function code generation.
1077fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {1454fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1078 const gpa = cg.module.gpa;1455 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 }
10861456
1087 const pt = cg.pt;1457 const pt = cg.pt;
1088 const zcu = cg.module.zcu;1458 const zcu = cg.zcu;
1089 const target = cg.module.zcu.getTarget();1459 const target = cg.zcu.getTarget();
1090 const result_ty_id = try cg.resolveType(ty, repr);1460 const result_ty_id = try cg.resolveType(ty, repr);
1091 const ip = &zcu.intern_pool;1461 const ip = &zcu.intern_pool;
10921462
1093 log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });1463 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)) {1464 if (val.isUndef(zcu)) {
1095 return cg.module.constUndef(result_ty_id);1465 return cg.constUndef(result_ty_id);
1096 }1466 }
10971467
1098 const cacheable_id = cache: {1468 const cacheable_id = cache: {
...@@ -1133,9 +1503,25 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1133,9 +1503,25 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1133 },1503 },
1134 .int => {1504 .int => {
1135 const int_info = ty.intInfo(zcu);1505 const int_info = ty.intInfo(zcu);
1136 _, const is_big_int = cg.module.backingIntBits(int_info.bits);1506 const backing_bits, const is_big_int = cg.backingIntBits(int_info.bits);
1137 if (is_big_int) {1507 if (is_big_int) {
1138 break :cache try cg.constIntBig(ty, val);1508 const n_limbs = backing_bits / big_int_bits;
1509 const big_result_ty_id = try cg.resolveType(ty, .indirect);
1510 var bigint_space: Value.BigIntSpace = undefined;
1511 const bigint = val.toBigInt(&bigint_space, zcu);
1512 const limb_values = try gpa.alloc(u32, n_limbs);
1513 defer gpa.free(limb_values);
1514 bigint.writeTwosComplement(std.mem.sliceAsBytes(limb_values), .little);
1515 if (builtin.cpu.arch.endian() == .big) {
1516 for (limb_values) |*limb| limb.* = @byteSwap(limb.*);
1517 }
1518 const scratch_top = cg.id_scratch.items.len;
1519 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
1520 const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
1521 for (constituents, 0..) |*c, i| {
1522 c.* = try cg.constInt(.u32, limb_values[i]);
1523 }
1524 break :cache try cg.constructComposite(big_result_ty_id, constituents);
1139 }1525 }
1140 if (ty.isSignedInt(zcu)) {1526 if (ty.isSignedInt(zcu)) {
1141 break :cache try cg.constInt(ty, val.toSignedInt(zcu));1527 break :cache try cg.constInt(ty, val.toSignedInt(zcu));
...@@ -1151,7 +1537,13 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1151,7 +1537,13 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1151 80, 128 => unreachable, // TODO1537 80, 128 => unreachable, // TODO
1152 else => unreachable,1538 else => unreachable,
1153 };1539 };
1154 break :cache try cg.module.constant(result_ty_id, lit);1540 const lit_id = cg.allocId();
1541 try cg.sections.globals.emit(gpa, .OpConstant, .{
1542 .id_result_type = result_ty_id,
1543 .id_result = lit_id,
1544 .value = lit,
1545 });
1546 break :cache lit_id;
1155 },1547 },
1156 .err => |err| {1548 .err => |err| {
1157 const value = try pt.getErrorValue(err.name);1549 const value = try pt.getErrorValue(err.name);
...@@ -1218,7 +1610,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1218,7 +1610,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1218 if (maybe_payload_val) |payload_val| {1610 if (maybe_payload_val) |payload_val| {
1219 return try cg.constant(payload_ty, payload_val, .indirect);1611 return try cg.constant(payload_ty, payload_val, .indirect);
1220 } else {1612 } else {
1221 break :cache try cg.module.constNull(result_ty_id);1613 break :cache try cg.constNull(result_ty_id);
1222 }1614 }
1223 }1615 }
12241616
...@@ -1229,7 +1621,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1229,7 +1621,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1229 const payload_id = if (maybe_payload_val) |payload_val|1621 const payload_id = if (maybe_payload_val) |payload_val|
1230 try cg.constant(payload_ty, payload_val, .indirect)1622 try cg.constant(payload_ty, payload_val, .indirect)
1231 else1623 else
1232 try cg.module.constUndef(try cg.resolveType(payload_ty, .indirect));1624 try cg.constUndef(try cg.resolveType(payload_ty, .indirect));
12331625
1234 const comp_ty_id = try cg.resolveType(ty, .direct);1626 const comp_ty_id = try cg.resolveType(ty, .direct);
1235 return try cg.constructComposite(comp_ty_id, &.{ payload_id, has_pl_id });1627 return try cg.constructComposite(comp_ty_id, &.{ payload_id, has_pl_id });
...@@ -1339,21 +1731,18 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1339,21 +1731,18 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1339 .memoized_call => unreachable,1731 .memoized_call => unreachable,
1340 }1732 }
1341 };1733 };
1342
1343 try cg.module.intern_map.putNoClobber(gpa, .{ val.toIntern(), repr }, cacheable_id);
1344
1345 return cacheable_id;1734 return cacheable_id;
1346}1735}
13471736
1348fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {1737fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
1349 const pt = cg.pt;1738 const pt = cg.pt;
1350 const zcu = cg.module.zcu;1739 const zcu = cg.zcu;
1351 const gpa = cg.module.gpa;1740 const gpa = cg.gpa;
13521741
1353 if (ptr_val.isUndef(zcu)) {1742 if (ptr_val.isUndef(zcu)) {
1354 const result_ty = ptr_val.typeOf(zcu);1743 const result_ty = ptr_val.typeOf(zcu);
1355 const result_ty_id = try cg.resolveType(result_ty, .direct);1744 const result_ty_id = try cg.resolveType(result_ty, .direct);
1356 return cg.module.constUndef(result_ty_id);1745 return cg.constUndef(result_ty_id);
1357 }1746 }
13581747
1359 var arena = std.heap.ArenaAllocator.init(gpa);1748 var arena = std.heap.ArenaAllocator.init(gpa);
...@@ -1364,9 +1753,9 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {...@@ -1364,9 +1753,9 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
1364}1753}
13651754
1366fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {1755fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1367 const gpa = cg.module.gpa;1756 const gpa = cg.gpa;
1368 const pt = cg.pt;1757 const pt = cg.pt;
1369 const zcu = cg.module.zcu;1758 const zcu = cg.zcu;
1370 const target = zcu.getTarget();1759 const target = zcu.getTarget();
1371 switch (derivation) {1760 switch (derivation) {
1372 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,1761 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
...@@ -1383,7 +1772,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1383,7 +1772,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1383 // TODO: This can probably be an OpSpecConstantOp Bitcast, but1772 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
1384 // that is not implemented by Mesa yet. Therefore, just generate it1773 // that is not implemented by Mesa yet. Therefore, just generate it
1385 // as a runtime operation.1774 // as a runtime operation.
1386 const result_ptr_id = cg.module.allocId();1775 const result_ptr_id = cg.allocId();
1387 const value_id = try cg.constInt(.usize, int.addr);1776 const value_id = try cg.constInt(.usize, int.addr);
1388 try cg.body.emit(gpa, .OpConvertUToPtr, .{1777 try cg.body.emit(gpa, .OpConvertUToPtr, .{
1389 .id_result_type = result_ty_id,1778 .id_result_type = result_ty_id,
...@@ -1392,13 +1781,87 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1392,13 +1781,87 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1392 });1781 });
1393 return result_ptr_id;1782 return result_ptr_id;
1394 },1783 },
1395 .nav_ptr => |nav| {1784 .nav_ptr => |nav_index| {
1396 const result_ptr_ty = try pt.navPtrType(nav);1785 const ip = &zcu.intern_pool;
1397 return cg.constantNavRef(result_ptr_ty, nav);1786 const result_ptr_ty = try pt.navPtrType(nav_index);
1787 const ty_id = try cg.resolveType(result_ptr_ty, .direct);
1788 const nav = ip.getNav(nav_index);
1789 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
1790
1791 switch (nav.resolved.?.value) {
1792 .none => {},
1793 else => |value| switch (ip.indexToKey(value)) {
1794 // TODO: Properly lower function pointers; for now substitute undef.
1795 .func => return try cg.constUndef(ty_id),
1796 .@"extern" => if (ip.isFunctionType(nav_ty.toIntern())) {
1797 const spv_decl_index = try cg.resolveNav(ip, nav_index);
1798 const decl = cg.declPtr(spv_decl_index);
1799 try emitExternFnStub(cg, nav, decl, nav_ty);
1800 return decl.result_id;
1801 },
1802 else => {},
1803 },
1804 }
1805
1806 if (!nav_ty.hasRuntimeBits(zcu) and nav_ty.zigTypeTag(zcu) != .spirv) {
1807 return cg.constUndef(ty_id);
1808 }
1809
1810 const spv_decl_index = try cg.resolveNav(ip, nav_index);
1811 const spv_decl = cg.declPtr(spv_decl_index);
1812 assert(spv_decl.kind != .func);
1813 const storage_class = cg.storageClass(nav.resolved.?.@"addrspace");
1814 try cg.addFunctionDep(spv_decl_index, storage_class);
1815
1816 const nav_ty_id = try cg.resolveType(nav_ty, .indirect);
1817 const decl_ptr_ty_id = try cg.ptrType(nav_ty_id, storage_class);
1818 if (decl_ptr_ty_id == ty_id) return spv_decl.result_id;
1819 switch (target.os.tag) {
1820 .vulkan, .opengl => return spv_decl.result_id,
1821 else => {},
1822 }
1823 const casted_ptr_id = cg.allocId();
1824 try cg.body.emit(gpa, .OpBitcast, .{
1825 .id_result_type = ty_id,
1826 .id_result = casted_ptr_id,
1827 .operand = spv_decl.result_id,
1828 });
1829 return casted_ptr_id;
1398 },1830 },
1399 .uav_ptr => |uav| {1831 .uav_ptr => |uav| {
1832 const ip = &zcu.intern_pool;
1400 const result_ptr_ty: Type = .fromInterned(uav.orig_ty);1833 const result_ptr_ty: Type = .fromInterned(uav.orig_ty);
1401 return cg.constantUavRef(result_ptr_ty, uav);1834 const ty_id = try cg.resolveType(result_ptr_ty, .direct);
1835 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
1836
1837 switch (ip.indexToKey(uav.val)) {
1838 .func => unreachable, // TODO
1839 .@"extern" => assert(!ip.isFunctionType(uav_ty.toIntern())),
1840 else => {},
1841 }
1842
1843 if (!uav_ty.hasRuntimeBits(zcu) and uav_ty.zigTypeTag(zcu) != .spirv) {
1844 return cg.constUndef(ty_id);
1845 }
1846
1847 // Uav refs are always generic.
1848 assert(result_ptr_ty.ptrAddressSpace(zcu) == .generic);
1849 const uav_ty_id = try cg.resolveType(uav_ty, .indirect);
1850 const decl_ptr_ty_id = try cg.ptrType(uav_ty_id, .function);
1851 const ptr_id = try cg.resolveUav(uav.val);
1852
1853 if (decl_ptr_ty_id == ty_id) return ptr_id;
1854 switch (target.os.tag) {
1855 .vulkan, .opengl => return ptr_id,
1856 else => {},
1857 }
1858 const casted_ptr_id = cg.allocId();
1859 try cg.body.emit(gpa, .OpBitcast, .{
1860 .id_result_type = ty_id,
1861 .id_result = casted_ptr_id,
1862 .operand = ptr_id,
1863 });
1864 return casted_ptr_id;
1402 },1865 },
1403 .eu_payload_ptr => @panic("TODO"),1866 .eu_payload_ptr => @panic("TODO"),
1404 .opt_payload_ptr => @panic("TODO"),1867 .opt_payload_ptr => @panic("TODO"),
...@@ -1450,7 +1913,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1450,7 +1913,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1450 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);1913 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);
1451 }1914 }
1452 if (target.os.tag == .opencl) {1915 if (target.os.tag == .opencl) {
1453 const result_ptr_id = cg.module.allocId();1916 const result_ptr_id = cg.allocId();
1454 try cg.body.emit(gpa, .OpBitcast, .{1917 try cg.body.emit(gpa, .OpBitcast, .{
1455 .id_result_type = result_ty_id,1918 .id_result_type = result_ty_id,
1456 .id_result = result_ptr_id,1919 .id_result = result_ptr_id,
...@@ -1468,59 +1931,15 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1468,59 +1931,15 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1468 }1931 }
1469}1932}
14701933
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 an1934/// Emit a stub OpFunction/OpFunctionEnd + Import linkage decoration for an
1516/// extern function so the module is structurally valid. The stub will be1935/// extern function so the module is structurally valid. The stub will be
1517/// replaced by the real definition at link time.1936/// replaced by the real definition at link time.
1518fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Module.Decl, fn_ty: Type) !void {1937fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Decl, fn_ty: Type) !void {
1519 if (decl.has_extern_stub) return;1938 if (decl.has_extern_stub) return;
1520 decl.has_extern_stub = true;1939 decl.has_extern_stub = true;
15211940
1522 const gpa = cg.module.gpa;1941 const gpa = cg.gpa;
1523 const zcu = cg.module.zcu;1942 const zcu = cg.zcu;
1524 const ip = &zcu.intern_pool;1943 const ip = &zcu.intern_pool;
1525 const fn_info = zcu.typeToFunc(fn_ty).?;1944 const fn_info = zcu.typeToFunc(fn_ty).?;
1526 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));1945 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
...@@ -1540,81 +1959,25 @@ fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Module.Decl, fn_ty...@@ -1540,81 +1959,25 @@ fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Module.Decl, fn_ty
1540 const param_type_id = try cg.resolveType(param_ty, .direct);1959 const param_type_id = try cg.resolveType(param_ty, .direct);
1541 try stub.emit(gpa, .OpFunctionParameter, .{1960 try stub.emit(gpa, .OpFunctionParameter, .{
1542 .id_result_type = param_type_id,1961 .id_result_type = param_type_id,
1543 .id_result = cg.module.allocId(),1962 .id_result = cg.allocId(),
1544 });1963 });
1545 }1964 }
1546 try stub.emit(gpa, .OpFunctionEnd, {});1965 try stub.emit(gpa, .OpFunctionEnd, {});
1547 try cg.module.sections.functions.append(gpa, stub);1966 try cg.sections.functions.append(gpa, stub);
15481967
1549 const extern_name = nav.getExtern(ip).?.name.toSlice(ip);1968 const extern_name = nav.getExtern(ip).?.name.toSlice(ip);
1550 try cg.module.sections.annotations.emit(gpa, .OpDecorate, .{1969 try cg.sections.annotations.emit(gpa, .OpDecorate, .{
1551 .target = decl.result_id,1970 .target = decl.result_id,
1552 .decoration = .{ .linkage_attributes = .{1971 .decoration = .{ .linkage_attributes = .{
1553 .name = extern_name,1972 .name = extern_name,
1554 .linkage_type = .import,1973 .linkage_type = .import,
1555 } },1974 } },
1556 });1975 });
1557 try cg.module.debugName(decl.result_id, extern_name);1976 try cg.debugName(decl.result_id, extern_name);
1558}1977}
15591978
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}
1614
1615// Turn a Zig type's name into a cache reference.
1616fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {1979fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1617 const gpa = cg.module.gpa;1980 const gpa = cg.gpa;
1618 var aw: std.Io.Writer.Allocating = .init(gpa);1981 var aw: std.Io.Writer.Allocating = .init(gpa);
1619 defer aw.deinit();1982 defer aw.deinit();
1620 ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) {1983 ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) {
...@@ -1641,67 +2004,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {...@@ -1641,67 +2004,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1641/// padding: [padding_size]u8,2004/// padding: [padding_size]u8,
1642/// }2005/// }
1643/// If any of the fields' size is 0, it will be omitted.2006/// 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 {2007fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1704 const zcu = cg.module.zcu;2008 const zcu = cg.zcu;
1705 if (!ret_ty.hasRuntimeBits(zcu)) {2009 if (!ret_ty.hasRuntimeBits(zcu)) {
1706 // If the return type is an error set or an error union, then we make this2010 // 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 function2011 // anyerror return type instead, so that it can be coerced into a function
...@@ -1717,38 +2021,38 @@ fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {...@@ -1717,38 +2021,38 @@ fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1717}2021}
17182022
1719fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {2023fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1720 const gpa = cg.module.gpa;2024 const gpa = cg.gpa;
1721 const pt = cg.pt;2025 const pt = cg.pt;
1722 const zcu = cg.module.zcu;2026 const zcu = cg.zcu;
1723 const ip = &zcu.intern_pool;2027 const ip = &zcu.intern_pool;
1724 const target = cg.module.zcu.getTarget();2028 const target = cg.zcu.getTarget();
17252029
1726 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});2030 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});
17272031
1728 switch (ty.zigTypeTag(zcu)) {2032 switch (ty.zigTypeTag(zcu)) {
1729 .noreturn => {2033 .noreturn => {
1730 assert(repr == .direct);2034 assert(repr == .direct);
1731 return try cg.module.voidType();2035 return try cg.voidType();
1732 },2036 },
1733 .void => switch (repr) {2037 .void => switch (repr) {
1734 .direct => return try cg.module.voidType(),2038 .direct => return try cg.voidType(),
1735 .indirect => {2039 .indirect => {
1736 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2040 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1737 return try cg.module.opaqueType("void");2041 return try cg.opaqueType("void");
1738 },2042 },
1739 },2043 },
1740 .bool => switch (repr) {2044 .bool => switch (repr) {
1741 .direct => return try cg.module.boolType(),2045 .direct => return try cg.boolType(),
1742 .indirect => return try cg.resolveType(.u1, .indirect),2046 .indirect => return try cg.resolveType(.u1, .indirect),
1743 },2047 },
1744 .int => {2048 .int => {
1745 if (ty.toIntern() == .u0_type) {2049 if (ty.toIntern() == .u0_type) {
1746 assert(repr == .indirect);2050 assert(repr == .indirect);
1747 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2051 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1748 return try cg.module.opaqueType("u0");2052 return try cg.opaqueType("u0");
1749 }2053 }
1750 const int_info = ty.intInfo(zcu);2054 const int_info = ty.intInfo(zcu);
1751 return try cg.module.intType(int_info.signedness, int_info.bits);2055 return try cg.intType(int_info.signedness, int_info.bits);
1752 },2056 },
1753 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),2057 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
1754 .float => {2058 .float => {
...@@ -1767,7 +2071,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1767,7 +2071,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1767 );2071 );
1768 }2072 }
17692073
1770 return try cg.module.floatType(bits);2074 return try cg.floatType(bits);
1771 },2075 },
1772 .array => {2076 .array => {
1773 const elem_ty = ty.childType(zcu);2077 const elem_ty = ty.childType(zcu);
...@@ -1779,7 +2083,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1779,7 +2083,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1779 if (!elem_ty.hasRuntimeBits(zcu)) {2083 if (!elem_ty.hasRuntimeBits(zcu)) {
1780 assert(repr == .indirect);2084 assert(repr == .indirect);
1781 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2085 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1782 return try cg.module.opaqueType("zero-sized-array");2086 return try cg.opaqueType("zero-sized-array");
1783 } else if (total_len == 0) {2087 } else if (total_len == 0) {
1784 // The size of the array would be 0, but that is not allowed in SPIR-V.2088 // 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 pointer2089 // This path can be reached for example when there is a slicing of a pointer
...@@ -1790,25 +2094,24 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1790,25 +2094,24 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1790 // generate an array of 1 element instead, so that ptr_elem_ptr instructions2094 // 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.2095 // can be lowered to ptrAccessChain instead of manually performing the math.
1792 const len_id = try cg.constInt(.u32, 1);2096 const len_id = try cg.constInt(.u32, 1);
1793 return try cg.module.arrayType(len_id, elem_ty_id);2097 return try cg.arrayType(len_id, elem_ty_id);
1794 } else {2098 } else {
1795 const total_len_id = try cg.constInt(.u32, total_len);2099 const total_len_id = try cg.constInt(.u32, total_len);
1796 return try cg.module.arrayType(total_len_id, elem_ty_id);2100 return try cg.arrayType(total_len_id, elem_ty_id);
1797 }2101 }
1798 },2102 },
1799 .vector => {2103 .vector => {
1800 const elem_ty = ty.childType(zcu);2104 const elem_ty = ty.childType(zcu);
1801 const elem_ty_id = try cg.resolveType(elem_ty, repr);2105 const elem_ty_id = try cg.resolveType(elem_ty, repr);
1802 const len = ty.vectorLen(zcu);2106 const len = ty.vectorLen(zcu);
1803 if (cg.isSpvVector(ty)) return try cg.module.vectorType(len, elem_ty_id);2107 if (cg.isSpvVector(ty)) return try cg.vectorType(len, elem_ty_id);
1804 const len_id = try cg.constInt(.u32, len);2108 const len_id = try cg.constInt(.u32, len);
1805 return try cg.module.arrayType(len_id, elem_ty_id);2109 return try cg.arrayType(len_id, elem_ty_id);
1806 },2110 },
1807 .@"fn" => switch (repr) {2111 .@"fn" => switch (repr) {
1808 .direct => {2112 .direct => {
1809 const fn_info = zcu.typeToFunc(ty).?;2113 const fn_info = zcu.typeToFunc(ty).?;
18102114
1811 comptime assert(zig_call_abi_ver == 3);
1812 assert(!fn_info.is_var_args);2115 assert(!fn_info.is_var_args);
1813 switch (fn_info.cc) {2116 switch (fn_info.cc) {
1814 .auto,2117 .auto,
...@@ -1837,7 +2140,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1837,7 +2140,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1837 param_index += 1;2140 param_index += 1;
1838 }2141 }
18392142
1840 return try cg.module.functionType(return_ty_id, param_ty_ids[0..param_index]);2143 return try cg.functionType(return_ty_id, param_ty_ids[0..param_index]);
1841 },2144 },
1842 .indirect => {2145 .indirect => {
1843 // TODO: Represent function pointers properly.2146 // TODO: Represent function pointers properly.
...@@ -1860,15 +2163,15 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1860,15 +2163,15 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1860 },2163 },
1861 };2164 };
1862 const child_ty_id = try cg.resolveType(child_ty, .indirect);2165 const child_ty_id = try cg.resolveType(child_ty, .indirect);
1863 const storage_class = cg.module.storageClass(ptr_info.flags.address_space);2166 const storage_class = cg.storageClass(ptr_info.flags.address_space);
1864 const ptr_ty_id = try cg.module.ptrType(child_ty_id, storage_class);2167 const ptr_ty_id = try cg.ptrType(child_ty_id, storage_class);
18652168
1866 if (ptr_info.flags.size != .slice) {2169 if (ptr_info.flags.size != .slice) {
1867 return ptr_ty_id;2170 return ptr_ty_id;
1868 }2171 }
18692172
1870 const size_ty_id = try cg.resolveType(.usize, .direct);2173 const size_ty_id = try cg.resolveType(.usize, .direct);
1871 return try cg.module.structType(2174 return try cg.structType(
1872 &.{ ptr_ty_id, size_ty_id },2175 &.{ ptr_ty_id, size_ty_id },
1873 &.{ "ptr", "len" },2176 &.{ "ptr", "len" },
1874 .none,2177 .none,
...@@ -1889,14 +2192,14 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1889,14 +2192,14 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1889 member_index += 1;2192 member_index += 1;
1890 }2193 }
18912194
1892 const result_id = try cg.module.structType(2195 const result_id = try cg.structType(
1893 member_types[0..member_index],2196 member_types[0..member_index],
1894 null,2197 null,
1895 .none,2198 .none,
1896 );2199 );
1897 const type_name = try cg.resolveTypeName(ty);2200 const type_name = try cg.resolveTypeName(ty);
1898 defer gpa.free(type_name);2201 defer gpa.free(type_name);
1899 try cg.module.debugName(result_id, type_name);2202 try cg.debugName(result_id, type_name);
1900 return result_id;2203 return result_id;
1901 },2204 },
1902 .struct_type => ip.loadStructType(ty.toIntern()),2205 .struct_type => ip.loadStructType(ty.toIntern()),
...@@ -1923,7 +2226,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1923,7 +2226,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1923 try member_names.append(field_name.toSlice(ip));2226 try member_names.append(field_name.toSlice(ip));
1924 }2227 }
19252228
1926 const result_id = try cg.module.structType(2229 const result_id = try cg.structType(
1927 member_types.items,2230 member_types.items,
1928 member_names.items,2231 member_names.items,
1929 ty.toIntern(),2232 ty.toIntern(),
...@@ -1931,7 +2234,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1931,7 +2234,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19312234
1932 const type_name = try cg.resolveTypeName(ty);2235 const type_name = try cg.resolveTypeName(ty);
1933 defer gpa.free(type_name);2236 defer gpa.free(type_name);
1934 try cg.module.debugName(result_id, type_name);2237 try cg.debugName(result_id, type_name);
19352238
1936 return result_id;2239 return result_id;
1937 },2240 },
...@@ -1952,13 +2255,52 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1952,13 +2255,52 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19522255
1953 const bool_ty_id = try cg.resolveType(.bool, .indirect);2256 const bool_ty_id = try cg.resolveType(.bool, .indirect);
19542257
1955 return try cg.module.structType(2258 return try cg.structType(
1956 &.{ payload_ty_id, bool_ty_id },2259 &.{ payload_ty_id, bool_ty_id },
1957 &.{ "payload", "valid" },2260 &.{ "payload", "valid" },
1958 .none,2261 .none,
1959 );2262 );
1960 },2263 },
1961 .@"union" => return try cg.resolveUnionType(ty),2264 .@"union" => {
2265 const union_obj = zcu.typeToUnion(ty).?;
2266 if (union_obj.layout == .@"packed") {
2267 return try cg.intType(.unsigned, @intCast(ty.bitSize(zcu)));
2268 }
2269 const layout = cg.unionLayout(ty);
2270 if (!layout.has_payload) {
2271 return try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
2272 }
2273 var member_types: [4]Id = undefined;
2274 var member_names: [4][]const u8 = undefined;
2275 const u8_ty_id = try cg.resolveType(.u8, .direct);
2276 if (layout.tag_size != 0) {
2277 member_types[layout.tag_index] = try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
2278 member_names[layout.tag_index] = "(tag)";
2279 }
2280 if (layout.payload_size != 0) {
2281 member_types[layout.payload_index] = try cg.resolveType(layout.payload_ty, .indirect);
2282 member_names[layout.payload_index] = "(payload)";
2283 }
2284 if (layout.payload_padding_size != 0) {
2285 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
2286 member_types[layout.payload_padding_index] = try cg.arrayType(len_id, u8_ty_id);
2287 member_names[layout.payload_padding_index] = "(payload padding)";
2288 }
2289 if (layout.padding_size != 0) {
2290 const len_id = try cg.constInt(.u32, layout.padding_size);
2291 member_types[layout.padding_index] = try cg.arrayType(len_id, u8_ty_id);
2292 member_names[layout.padding_index] = "(padding)";
2293 }
2294 const result_id = try cg.structType(
2295 member_types[0..layout.total_fields],
2296 member_names[0..layout.total_fields],
2297 .none,
2298 );
2299 const type_name = try cg.resolveTypeName(ty);
2300 defer gpa.free(type_name);
2301 try cg.debugName(result_id, type_name);
2302 return result_id;
2303 },
1962 .error_set => {2304 .error_set => {
1963 const err_int_ty = try pt.errorIntType();2305 const err_int_ty = try pt.errorIntType();
1964 return try cg.resolveType(err_int_ty, repr);2306 return try cg.resolveType(err_int_ty, repr);
...@@ -1989,46 +2331,43 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1989,46 +2331,43 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1989 // TODO: ABI padding?2331 // TODO: ABI padding?
1990 }2332 }
19912333
1992 return try cg.module.structType(&member_types, &member_names, .none);2334 return try cg.structType(&member_types, &member_names, .none);
1993 },2335 },
1994 .@"opaque" => {2336 .@"opaque" => {
1995 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});2337 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
1996 const type_name = try cg.resolveTypeName(ty);2338 const type_name = try cg.resolveTypeName(ty);
1997 defer gpa.free(type_name);2339 defer gpa.free(type_name);
1998 return try cg.module.opaqueType(type_name);2340 return try cg.opaqueType(type_name);
1999 },2341 },
2000 .spirv => {2342 .spirv => {
2001 const ip_index = ty.toIntern();2343 const spirv_type = ip.loadSpirvType(ty.toIntern());
2002 const spirv_type = ip.loadSpirvType(ip_index);2344 const result_id = cg.allocId();
2003 switch (spirv_type.flags.tag) {2345 switch (spirv_type.flags.tag) {
2004 .sampler => return try cg.module.samplerType(ip_index),2346 .sampler => try cg.sections.globals.emit(gpa, .OpTypeSampler, .{ .id_result = result_id }),
2005 .image => {2347 .image => {
2006 const sampled_type_id = blk: {2348 const sampled_type_id = try cg.resolveType(.fromInterned(spirv_type.ty), .direct);
2007 if (spirv_type.ty == .none) break :blk try cg.module.intType(.unsigned, 32);2349 try cg.sections.globals.emit(gpa, .OpTypeImage, .{
2008 break :blk try cg.resolveType(Type.fromInterned(spirv_type.ty), .direct);2350 .id_result = result_id,
2009 };2351 .sampled_type = sampled_type_id,
2010 return try cg.module.imageType(2352 .dim = switch (spirv_type.flags.dim) {
2011 ip_index,
2012 sampled_type_id,
2013 switch (spirv_type.flags.dim) {
2014 .@"1d" => .@"1d",2353 .@"1d" => .@"1d",
2015 .@"2d" => .@"2d",2354 .@"2d" => .@"2d",
2016 .@"3d" => .@"3d",2355 .@"3d" => .@"3d",
2017 .cube => .cube,2356 .cube => .cube,
2018 },2357 },
2019 switch (spirv_type.flags.depth) {2358 .depth = switch (spirv_type.flags.depth) {
2020 .not_depth => 0,2359 .not_depth => 0,
2021 .depth => 1,2360 .depth => 1,
2022 .unknown => 2,2361 .unknown => 2,
2023 },2362 },
2024 @intFromBool(spirv_type.flags.is_arrayed),2363 .arrayed = @intFromBool(spirv_type.flags.is_arrayed),
2025 @intFromBool(spirv_type.flags.is_multisampled),2364 .ms = @intFromBool(spirv_type.flags.is_multisampled),
2026 switch (spirv_type.flags.usage) {2365 .sampled = switch (spirv_type.flags.usage) {
2027 .unknown => 1,2366 .unknown => 0,
2028 .sampled => 1,2367 .sampled => 1,
2029 .storage => 2,2368 .storage => 2,
2030 },2369 },
2031 switch (spirv_type.flags.format) {2370 .image_format = switch (spirv_type.flags.format) {
2032 .unknown => .unknown,2371 .unknown => .unknown,
2033 .rgba32f => .rgba32f,2372 .rgba32f => .rgba32f,
2034 .rgba32i => .rgba32i,2373 .rgba32i => .rgba32i,
...@@ -2044,31 +2383,36 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -2044,31 +2383,36 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
2044 .r32i => .r32i,2383 .r32i => .r32i,
2045 .r32u => .r32ui,2384 .r32u => .r32ui,
2046 },2385 },
2047 switch (spirv_type.flags.access) {2386 .access_qualifier = switch (spirv_type.flags.access) {
2048 .unknown => null,2387 .unknown => null,
2049 .read_only => .read_only,2388 .read_only => .read_only,
2050 .write_only => .write_only,2389 .write_only => .write_only,
2051 .read_write => .read_write,2390 .read_write => .read_write,
2052 },2391 },
2053 );2392 });
2054 },2393 },
2055 .sampled_image => {2394 .sampled_image => {
2056 const image_ty_id = try cg.resolveType(.fromInterned(spirv_type.ty), .indirect);2395 const image_ty_id = try cg.resolveType(.fromInterned(spirv_type.ty), .indirect);
2057 return try cg.module.sampledImageType(ip_index, image_ty_id);2396 try cg.sections.globals.emit(gpa, .OpTypeSampledImage, .{
2397 .id_result = result_id,
2398 .image_type = image_ty_id,
2399 });
2058 },2400 },
2059 .runtime_array => {2401 .runtime_array => {
2060 const elem_ty: Type = .fromInterned(spirv_type.ty);2402 const elem_ty: Type = .fromInterned(spirv_type.ty);
2061 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);2403 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
2062 const result_id = try cg.module.runtimeArrayType(ip_index, elem_ty_id);2404 try cg.sections.globals.emit(gpa, .OpTypeRuntimeArray, .{
20632405 .id_result = result_id,
2406 .element_type = elem_ty_id,
2407 });
2064 if (elem_ty.hasRuntimeBits(zcu)) {2408 if (elem_ty.hasRuntimeBits(zcu)) {
2065 try cg.module.decorate(result_id, .{ .array_stride = .{2409 try cg.decorate(result_id, .{ .array_stride = .{
2066 .array_stride = @intCast(elem_ty.abiSize(zcu)),2410 .array_stride = @intCast(elem_ty.abiSize(zcu)),
2067 } });2411 } });
2068 }2412 }
2069 return result_id;
2070 },2413 },
2071 }2414 }
2415 return result_id;
2072 },2416 },
20732417
2074 .null,2418 .null,
...@@ -2099,7 +2443,7 @@ const ErrorUnionLayout = struct {...@@ -2099,7 +2443,7 @@ const ErrorUnionLayout = struct {
2099};2443};
21002444
2101fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {2445fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {
2102 const zcu = cg.module.zcu;2446 const zcu = cg.zcu;
21032447
2104 const error_align = Type.abiAlignment(.anyerror, zcu);2448 const error_align = Type.abiAlignment(.anyerror, zcu);
2105 const payload_align = payload_ty.abiAlignment(zcu);2449 const payload_align = payload_ty.abiAlignment(zcu);
...@@ -2130,7 +2474,7 @@ const UnionLayout = struct {...@@ -2130,7 +2474,7 @@ const UnionLayout = struct {
2130};2474};
21312475
2132fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {2476fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {
2133 const zcu = cg.module.zcu;2477 const zcu = cg.zcu;
2134 const ip = &zcu.intern_pool;2478 const ip = &zcu.intern_pool;
2135 const layout = ty.unionGetLayout(zcu);2479 const layout = ty.unionGetLayout(zcu);
2136 const union_obj = zcu.typeToUnion(ty).?;2480 const union_obj = zcu.typeToUnion(ty).?;
...@@ -2220,8 +2564,8 @@ const Temporary = struct {...@@ -2220,8 +2564,8 @@ const Temporary = struct {
2220 }2564 }
22212565
2222 fn materialize(temp: Temporary, cg: *CodeGen) !Id {2566 fn materialize(temp: Temporary, cg: *CodeGen) !Id {
2223 const gpa = cg.module.gpa;2567 const gpa = cg.gpa;
2224 const zcu = cg.module.zcu;2568 const zcu = cg.zcu;
2225 switch (temp.value) {2569 switch (temp.value) {
2226 .singleton => |id| return id,2570 .singleton => |id| return id,
2227 .exploded_vector => |range| {2571 .exploded_vector => |range| {
...@@ -2255,7 +2599,7 @@ const Temporary = struct {...@@ -2255,7 +2599,7 @@ const Temporary = struct {
2255 /// 'Explode' a temporary into separate elements. This turns a vector2599 /// 'Explode' a temporary into separate elements. This turns a vector
2256 /// into a bag of elements.2600 /// into a bag of elements.
2257 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {2601 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {
2258 const zcu = cg.module.zcu;2602 const zcu = cg.zcu;
22592603
2260 // If the value is a scalar, then this is a no-op.2604 // If the value is a scalar, then this is a no-op.
2261 if (!temp.ty.isVector(zcu)) {2605 if (!temp.ty.isVector(zcu)) {
...@@ -2267,7 +2611,7 @@ const Temporary = struct {...@@ -2267,7 +2611,7 @@ const Temporary = struct {
22672611
2268 const ty_id = try cg.resolveType(temp.ty.scalarType(zcu), .direct);2612 const ty_id = try cg.resolveType(temp.ty.scalarType(zcu), .direct);
2269 const n = temp.ty.vectorLen(zcu);2613 const n = temp.ty.vectorLen(zcu);
2270 const results = cg.module.allocIds(n);2614 const results = cg.allocIds(n);
22712615
2272 const id = switch (temp.value) {2616 const id = switch (temp.value) {
2273 .singleton => |id| id,2617 .singleton => |id| id,
...@@ -2276,7 +2620,7 @@ const Temporary = struct {...@@ -2276,7 +2620,7 @@ const Temporary = struct {
22762620
2277 for (0..n) |i| {2621 for (0..n) |i| {
2278 const indexes = [_]u32{@intCast(i)};2622 const indexes = [_]u32{@intCast(i)};
2279 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{2623 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
2280 .id_result_type = ty_id,2624 .id_result_type = ty_id,
2281 .id_result = results.at(i),2625 .id_result = results.at(i),
2282 .composite = id,2626 .composite = id,
...@@ -2296,12 +2640,12 @@ const CompositeInt = struct {...@@ -2296,12 +2640,12 @@ const CompositeInt = struct {
2296 info: ArithmeticTypeInfo,2640 info: ArithmeticTypeInfo,
22972641
2298 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {2642 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {
2299 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;2643 const n_limbs: u16 = info.backing_bits / big_int_bits;
2300 const gpa = cg.module.gpa;2644 const gpa = cg.gpa;
2301 const u32_ty_id = try cg.resolveType(.u32, .direct);2645 const u32_ty_id = try cg.resolveType(.u32, .direct);
2302 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);2646 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
2303 for (limbs, 0..) |*limb, i| {2647 for (limbs, 0..) |*limb, i| {
2304 const result_id = cg.module.allocId();2648 const result_id = cg.allocId();
2305 try cg.body.emit(gpa, .OpCompositeExtract, .{2649 try cg.body.emit(gpa, .OpCompositeExtract, .{
2306 .id_result_type = u32_ty_id,2650 .id_result_type = u32_ty_id,
2307 .id_result = result_id,2651 .id_result = result_id,
...@@ -2323,8 +2667,8 @@ const CompositeInt = struct {...@@ -2323,8 +2667,8 @@ const CompositeInt = struct {
2323 }2667 }
23242668
2325 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {2669 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {
2326 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;2670 const n_limbs: u16 = info.backing_bits / big_int_bits;
2327 const limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, n_limbs);2671 const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs);
2328 const zero_id = try cg.constInt(.u32, @as(u32, 0));2672 const zero_id = try cg.constInt(.u32, @as(u32, 0));
2329 for (limbs) |*limb| limb.* = zero_id;2673 for (limbs) |*limb| limb.* = zero_id;
2330 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };2674 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
...@@ -2337,9 +2681,9 @@ const CompositeInt = struct {...@@ -2337,9 +2681,9 @@ const CompositeInt = struct {
23372681
2338 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {2682 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {
2339 const cg = ci.cg;2683 const cg = ci.cg;
2340 const gpa = cg.module.gpa;2684 const gpa = cg.gpa;
2341 const u32_ty_id = try cg.resolveType(.u32, .direct);2685 const u32_ty_id = try cg.resolveType(.u32, .direct);
2342 const result_id = cg.module.allocId();2686 const result_id = cg.allocId();
2343 try cg.body.emitRaw(gpa, opcode, 4);2687 try cg.body.emitRaw(gpa, opcode, 4);
2344 cg.body.writeOperand(Id, u32_ty_id);2688 cg.body.writeOperand(Id, u32_ty_id);
2345 cg.body.writeOperand(Id, result_id);2689 cg.body.writeOperand(Id, result_id);
...@@ -2350,9 +2694,9 @@ const CompositeInt = struct {...@@ -2350,9 +2694,9 @@ const CompositeInt = struct {
23502694
2351 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {2695 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {
2352 const cg = ci.cg;2696 const cg = ci.cg;
2353 const gpa = cg.module.gpa;2697 const gpa = cg.gpa;
2354 const u32_ty_id = try cg.resolveType(.u32, .direct);2698 const u32_ty_id = try cg.resolveType(.u32, .direct);
2355 const result_id = cg.module.allocId();2699 const result_id = cg.allocId();
2356 try cg.body.emitRaw(gpa, opcode, 3);2700 try cg.body.emitRaw(gpa, opcode, 3);
2357 cg.body.writeOperand(Id, u32_ty_id);2701 cg.body.writeOperand(Id, u32_ty_id);
2358 cg.body.writeOperand(Id, result_id);2702 cg.body.writeOperand(Id, result_id);
...@@ -2362,7 +2706,7 @@ const CompositeInt = struct {...@@ -2362,7 +2706,7 @@ const CompositeInt = struct {
23622706
2363 fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt {2707 fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt {
2364 const cg = ci.cg;2708 const cg = ci.cg;
2365 const gpa = cg.module.gpa;2709 const gpa = cg.gpa;
2366 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);2710 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2367 for (result_limbs, 0..) |*r, i| {2711 for (result_limbs, 0..) |*r, i| {
2368 r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]);2712 r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]);
...@@ -2372,7 +2716,7 @@ const CompositeInt = struct {...@@ -2372,7 +2716,7 @@ const CompositeInt = struct {
23722716
2373 fn bitwiseNot(ci: CompositeInt) !CompositeInt {2717 fn bitwiseNot(ci: CompositeInt) !CompositeInt {
2374 const cg = ci.cg;2718 const cg = ci.cg;
2375 const gpa = cg.module.gpa;2719 const gpa = cg.gpa;
2376 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);2720 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2377 for (result_limbs, 0..) |*r, i| {2721 for (result_limbs, 0..) |*r, i| {
2378 r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]);2722 r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]);
...@@ -2382,41 +2726,45 @@ const CompositeInt = struct {...@@ -2382,41 +2726,45 @@ const CompositeInt = struct {
23822726
2383 fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id {2727 fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id {
2384 const cg = ci.cg;2728 const cg = ci.cg;
2385 const gpa = cg.module.gpa;2729 const gpa = cg.gpa;
2386 const bool_ty_id = try cg.resolveType(.bool, .direct);2730 const bool_ty_id = try cg.resolveType(.bool, .direct);
23872731
2388 switch (op) {2732 switch (op) {
2389 .eq, .neq => {2733 .eq, .neq => {
2390 var result = blk: {2734 var result = blk: {
2391 const r = cg.module.allocId();2735 const r = cg.allocId();
2392 try cg.body.emitRaw(gpa, .OpIEqual, 4);2736 try cg.body.emit(gpa, .OpIEqual, .{
2393 cg.body.writeOperand(Id, bool_ty_id);2737 .id_result_type = bool_ty_id,
2394 cg.body.writeOperand(Id, r);2738 .id_result = r,
2395 cg.body.writeOperand(Id, ci.limbs[0]);2739 .operand_1 = ci.limbs[0],
2396 cg.body.writeOperand(Id, other.limbs[0]);2740 .operand_2 = other.limbs[0],
2741 });
2397 break :blk r;2742 break :blk r;
2398 };2743 };
2399 for (1..ci.n_limbs) |i| {2744 for (1..ci.n_limbs) |i| {
2400 const limb_eq = cg.module.allocId();2745 const limb_eq = cg.allocId();
2401 try cg.body.emitRaw(gpa, .OpIEqual, 4);2746 try cg.body.emit(gpa, .OpIEqual, .{
2402 cg.body.writeOperand(Id, bool_ty_id);2747 .id_result_type = bool_ty_id,
2403 cg.body.writeOperand(Id, limb_eq);2748 .id_result = limb_eq,
2404 cg.body.writeOperand(Id, ci.limbs[i]);2749 .operand_1 = ci.limbs[i],
2405 cg.body.writeOperand(Id, other.limbs[i]);2750 .operand_2 = other.limbs[i],
2406 const combined = cg.module.allocId();2751 });
2407 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);2752 const combined = cg.allocId();
2408 cg.body.writeOperand(Id, bool_ty_id);2753 try cg.body.emit(gpa, .OpLogicalAnd, .{
2409 cg.body.writeOperand(Id, combined);2754 .id_result_type = bool_ty_id,
2410 cg.body.writeOperand(Id, result);2755 .id_result = combined,
2411 cg.body.writeOperand(Id, limb_eq);2756 .operand_1 = result,
2757 .operand_2 = limb_eq,
2758 });
2412 result = combined;2759 result = combined;
2413 }2760 }
2414 if (op == .neq) {2761 if (op == .neq) {
2415 const negated = cg.module.allocId();2762 const negated = cg.allocId();
2416 try cg.body.emitRaw(gpa, .OpLogicalNot, 3);2763 try cg.body.emit(gpa, .OpLogicalNot, .{
2417 cg.body.writeOperand(Id, bool_ty_id);2764 .id_result_type = bool_ty_id,
2418 cg.body.writeOperand(Id, negated);2765 .id_result = negated,
2419 cg.body.writeOperand(Id, result);2766 .operand = result,
2767 });
2420 result = negated;2768 result = negated;
2421 }2769 }
2422 return result;2770 return result;
...@@ -2429,12 +2777,13 @@ const CompositeInt = struct {...@@ -2429,12 +2777,13 @@ const CompositeInt = struct {
2429 for (0..ci.n_limbs) |i| {2777 for (0..ci.n_limbs) |i| {
2430 const l = ci.limbs[i];2778 const l = ci.limbs[i];
2431 const r = other.limbs[i];2779 const r = other.limbs[i];
2432 const limb_ne = cg.module.allocId();2780 const limb_ne = cg.allocId();
2433 try cg.body.emitRaw(gpa, .OpINotEqual, 4);2781 try cg.body.emit(gpa, .OpINotEqual, .{
2434 cg.body.writeOperand(Id, bool_ty_id);2782 .id_result_type = bool_ty_id,
2435 cg.body.writeOperand(Id, limb_ne);2783 .id_result = limb_ne,
2436 cg.body.writeOperand(Id, l);2784 .operand_1 = l,
2437 cg.body.writeOperand(Id, r);2785 .operand_2 = r,
2786 });
24382787
2439 const is_top = (i == ci.n_limbs - 1);2788 const is_top = (i == ci.n_limbs - 1);
2440 const use_signed = is_top and ci.info.signedness == .signed;2789 const use_signed = is_top and ci.info.signedness == .signed;
...@@ -2442,13 +2791,13 @@ const CompositeInt = struct {...@@ -2442,13 +2791,13 @@ const CompositeInt = struct {
2442 var cmp_r = r;2791 var cmp_r = r;
2443 if (use_signed) {2792 if (use_signed) {
2444 const i32_ty_id = try cg.resolveType(.i32, .direct);2793 const i32_ty_id = try cg.resolveType(.i32, .direct);
2445 const sl = cg.module.allocId();2794 const sl = cg.allocId();
2446 try cg.body.emit(gpa, .OpBitcast, .{2795 try cg.body.emit(gpa, .OpBitcast, .{
2447 .id_result_type = i32_ty_id,2796 .id_result_type = i32_ty_id,
2448 .id_result = sl,2797 .id_result = sl,
2449 .operand = l,2798 .operand = l,
2450 });2799 });
2451 const sr = cg.module.allocId();2800 const sr = cg.allocId();
2452 try cg.body.emit(gpa, .OpBitcast, .{2801 try cg.body.emit(gpa, .OpBitcast, .{
2453 .id_result_type = i32_ty_id,2802 .id_result_type = i32_ty_id,
2454 .id_result = sr,2803 .id_result = sr,
...@@ -2463,14 +2812,14 @@ const CompositeInt = struct {...@@ -2463,14 +2812,14 @@ const CompositeInt = struct {
2463 else2812 else
2464 (if (use_signed) .OpSGreaterThan else .OpUGreaterThan);2813 (if (use_signed) .OpSGreaterThan else .OpUGreaterThan);
24652814
2466 const limb_cmp = cg.module.allocId();2815 const limb_cmp = cg.allocId();
2467 try cg.body.emitRaw(gpa, cmp_opcode, 4);2816 try cg.body.emitRaw(gpa, cmp_opcode, 4);
2468 cg.body.writeOperand(Id, bool_ty_id);2817 cg.body.writeOperand(Id, bool_ty_id);
2469 cg.body.writeOperand(Id, limb_cmp);2818 cg.body.writeOperand(Id, limb_cmp);
2470 cg.body.writeOperand(Id, cmp_l);2819 cg.body.writeOperand(Id, cmp_l);
2471 cg.body.writeOperand(Id, cmp_r);2820 cg.body.writeOperand(Id, cmp_r);
24722821
2473 const selected = cg.module.allocId();2822 const selected = cg.allocId();
2474 try cg.body.emit(gpa, .OpSelect, .{2823 try cg.body.emit(gpa, .OpSelect, .{
2475 .id_result_type = bool_ty_id,2824 .id_result_type = bool_ty_id,
2476 .id_result = selected,2825 .id_result = selected,
...@@ -2487,9 +2836,9 @@ const CompositeInt = struct {...@@ -2487,9 +2836,9 @@ const CompositeInt = struct {
24872836
2488 fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt {2837 fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt {
2489 const cg = ci.cg;2838 const cg = ci.cg;
2490 const gpa = cg.module.gpa;2839 const gpa = cg.gpa;
2491 const pt = cg.pt;2840 const pt = cg.pt;
2492 const zcu = cg.module.zcu;2841 const zcu = cg.zcu;
2493 const ip = &zcu.intern_pool;2842 const ip = &zcu.intern_pool;
2494 const comp = zcu.comp;2843 const comp = zcu.comp;
2495 const io = comp.io;2844 const io = comp.io;
...@@ -2508,21 +2857,21 @@ const CompositeInt = struct {...@@ -2508,21 +2857,21 @@ const CompositeInt = struct {
2508 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;2857 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;
25092858
2510 for (0..ci.n_limbs) |i| {2859 for (0..ci.n_limbs) |i| {
2511 const op1 = cg.module.allocId();2860 const op1 = cg.allocId();
2512 try cg.body.emitRaw(gpa, opcode, 4);2861 try cg.body.emitRaw(gpa, opcode, 4);
2513 cg.body.writeOperand(Id, carry_struct_ty_id);2862 cg.body.writeOperand(Id, carry_struct_ty_id);
2514 cg.body.writeOperand(Id, op1);2863 cg.body.writeOperand(Id, op1);
2515 cg.body.writeOperand(Id, ci.limbs[i]);2864 cg.body.writeOperand(Id, ci.limbs[i]);
2516 cg.body.writeOperand(Id, other.limbs[i]);2865 cg.body.writeOperand(Id, other.limbs[i]);
25172866
2518 const sum1 = cg.module.allocId();2867 const sum1 = cg.allocId();
2519 try cg.body.emit(gpa, .OpCompositeExtract, .{2868 try cg.body.emit(gpa, .OpCompositeExtract, .{
2520 .id_result_type = u32_ty_id,2869 .id_result_type = u32_ty_id,
2521 .id_result = sum1,2870 .id_result = sum1,
2522 .composite = op1,2871 .composite = op1,
2523 .indexes = &.{0},2872 .indexes = &.{0},
2524 });2873 });
2525 const carry1 = cg.module.allocId();2874 const carry1 = cg.allocId();
2526 try cg.body.emit(gpa, .OpCompositeExtract, .{2875 try cg.body.emit(gpa, .OpCompositeExtract, .{
2527 .id_result_type = u32_ty_id,2876 .id_result_type = u32_ty_id,
2528 .id_result = carry1,2877 .id_result = carry1,
...@@ -2530,21 +2879,21 @@ const CompositeInt = struct {...@@ -2530,21 +2879,21 @@ const CompositeInt = struct {
2530 .indexes = &.{1},2879 .indexes = &.{1},
2531 });2880 });
25322881
2533 const op2 = cg.module.allocId();2882 const op2 = cg.allocId();
2534 try cg.body.emitRaw(gpa, opcode, 4);2883 try cg.body.emitRaw(gpa, opcode, 4);
2535 cg.body.writeOperand(Id, carry_struct_ty_id);2884 cg.body.writeOperand(Id, carry_struct_ty_id);
2536 cg.body.writeOperand(Id, op2);2885 cg.body.writeOperand(Id, op2);
2537 cg.body.writeOperand(Id, sum1);2886 cg.body.writeOperand(Id, sum1);
2538 cg.body.writeOperand(Id, carry_id);2887 cg.body.writeOperand(Id, carry_id);
25392888
2540 result_limbs[i] = cg.module.allocId();2889 result_limbs[i] = cg.allocId();
2541 try cg.body.emit(gpa, .OpCompositeExtract, .{2890 try cg.body.emit(gpa, .OpCompositeExtract, .{
2542 .id_result_type = u32_ty_id,2891 .id_result_type = u32_ty_id,
2543 .id_result = result_limbs[i],2892 .id_result = result_limbs[i],
2544 .composite = op2,2893 .composite = op2,
2545 .indexes = &.{0},2894 .indexes = &.{0},
2546 });2895 });
2547 const carry2 = cg.module.allocId();2896 const carry2 = cg.allocId();
2548 try cg.body.emit(gpa, .OpCompositeExtract, .{2897 try cg.body.emit(gpa, .OpCompositeExtract, .{
2549 .id_result_type = u32_ty_id,2898 .id_result_type = u32_ty_id,
2550 .id_result = carry2,2899 .id_result = carry2,
...@@ -2560,7 +2909,7 @@ const CompositeInt = struct {...@@ -2560,7 +2909,7 @@ const CompositeInt = struct {
25602909
2561 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {2910 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {
2562 const cg = ci.cg;2911 const cg = ci.cg;
2563 const gpa = cg.module.gpa;2912 const gpa = cg.gpa;
2564 const u32_ty_id = try cg.resolveType(.u32, .direct);2913 const u32_ty_id = try cg.resolveType(.u32, .direct);
2565 const bool_ty_id = try cg.resolveType(.bool, .direct);2914 const bool_ty_id = try cg.resolveType(.bool, .direct);
2566 const zero_id = try cg.constInt(.u32, @as(u32, 0));2915 const zero_id = try cg.constInt(.u32, @as(u32, 0));
...@@ -2572,12 +2921,13 @@ const CompositeInt = struct {...@@ -2572,12 +2921,13 @@ const CompositeInt = struct {
2572 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);2921 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
2573 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);2922 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
2574 const frac_is_zero = blk: {2923 const frac_is_zero = blk: {
2575 const r = cg.module.allocId();2924 const r = cg.allocId();
2576 try cg.body.emitRaw(gpa, .OpIEqual, 4);2925 try cg.body.emit(gpa, .OpIEqual, .{
2577 cg.body.writeOperand(Id, bool_ty_id);2926 .id_result_type = bool_ty_id,
2578 cg.body.writeOperand(Id, r);2927 .id_result = r,
2579 cg.body.writeOperand(Id, frac);2928 .operand_1 = frac,
2580 cg.body.writeOperand(Id, zero_id);2929 .operand_2 = zero_id,
2930 });
2581 break :blk r;2931 break :blk r;
2582 };2932 };
25832933
...@@ -2593,17 +2943,18 @@ const CompositeInt = struct {...@@ -2593,17 +2943,18 @@ const CompositeInt = struct {
2593 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);2943 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);
25942944
2595 const is_main = blk: {2945 const is_main = blk: {
2596 const r = cg.module.allocId();2946 const r = cg.allocId();
2597 try cg.body.emitRaw(gpa, .OpIEqual, 4);2947 try cg.body.emit(gpa, .OpIEqual, .{
2598 cg.body.writeOperand(Id, bool_ty_id);2948 .id_result_type = bool_ty_id,
2599 cg.body.writeOperand(Id, r);2949 .id_result = r,
2600 cg.body.writeOperand(Id, j_plus_whole);2950 .operand_1 = j_plus_whole,
2601 cg.body.writeOperand(Id, i_id);2951 .operand_2 = i_id,
2952 });
2602 break :blk r;2953 break :blk r;
2603 };2954 };
2604 const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac);2955 const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac);
2605 main_val = blk: {2956 main_val = blk: {
2606 const r = cg.module.allocId();2957 const r = cg.allocId();
2607 try cg.body.emit(gpa, .OpSelect, .{2958 try cg.body.emit(gpa, .OpSelect, .{
2608 .id_result_type = u32_ty_id,2959 .id_result_type = u32_ty_id,
2609 .id_result = r,2960 .id_result = r,
...@@ -2617,17 +2968,18 @@ const CompositeInt = struct {...@@ -2617,17 +2968,18 @@ const CompositeInt = struct {
2617 const one_id = try cg.constInt(.u32, @as(u32, 1));2968 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);2969 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);
2619 const is_carry = blk: {2970 const is_carry = blk: {
2620 const r = cg.module.allocId();2971 const r = cg.allocId();
2621 try cg.body.emitRaw(gpa, .OpIEqual, 4);2972 try cg.body.emit(gpa, .OpIEqual, .{
2622 cg.body.writeOperand(Id, bool_ty_id);2973 .id_result_type = bool_ty_id,
2623 cg.body.writeOperand(Id, r);2974 .id_result = r,
2624 cg.body.writeOperand(Id, j_plus_whole_plus_1);2975 .operand_1 = j_plus_whole_plus_1,
2625 cg.body.writeOperand(Id, i_id);2976 .operand_2 = i_id,
2977 });
2626 break :blk r;2978 break :blk r;
2627 };2979 };
2628 const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac);2980 const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac);
2629 const guarded_carry = blk: {2981 const guarded_carry = blk: {
2630 const r = cg.module.allocId();2982 const r = cg.allocId();
2631 try cg.body.emit(gpa, .OpSelect, .{2983 try cg.body.emit(gpa, .OpSelect, .{
2632 .id_result_type = u32_ty_id,2984 .id_result_type = u32_ty_id,
2633 .id_result = r,2985 .id_result = r,
...@@ -2638,7 +2990,7 @@ const CompositeInt = struct {...@@ -2638,7 +2990,7 @@ const CompositeInt = struct {
2638 break :blk r;2990 break :blk r;
2639 };2991 };
2640 carry_val = blk: {2992 carry_val = blk: {
2641 const r = cg.module.allocId();2993 const r = cg.allocId();
2642 try cg.body.emit(gpa, .OpSelect, .{2994 try cg.body.emit(gpa, .OpSelect, .{
2643 .id_result_type = u32_ty_id,2995 .id_result_type = u32_ty_id,
2644 .id_result = r,2996 .id_result = r,
...@@ -2658,7 +3010,7 @@ const CompositeInt = struct {...@@ -2658,7 +3010,7 @@ const CompositeInt = struct {
26583010
2659 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {3011 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {
2660 const cg = ci.cg;3012 const cg = ci.cg;
2661 const gpa = cg.module.gpa;3013 const gpa = cg.gpa;
2662 const u32_ty_id = try cg.resolveType(.u32, .direct);3014 const u32_ty_id = try cg.resolveType(.u32, .direct);
2663 const bool_ty_id = try cg.resolveType(.bool, .direct);3015 const bool_ty_id = try cg.resolveType(.bool, .direct);
2664 const zero_id = try cg.constInt(.u32, @as(u32, 0));3016 const zero_id = try cg.constInt(.u32, @as(u32, 0));
...@@ -2670,31 +3022,33 @@ const CompositeInt = struct {...@@ -2670,31 +3022,33 @@ const CompositeInt = struct {
2670 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);3022 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
2671 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);3023 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
2672 const frac_is_zero = blk: {3024 const frac_is_zero = blk: {
2673 const r = cg.module.allocId();3025 const r = cg.allocId();
2674 try cg.body.emitRaw(gpa, .OpIEqual, 4);3026 try cg.body.emit(gpa, .OpIEqual, .{
2675 cg.body.writeOperand(Id, bool_ty_id);3027 .id_result_type = bool_ty_id,
2676 cg.body.writeOperand(Id, r);3028 .id_result = r,
2677 cg.body.writeOperand(Id, frac);3029 .operand_1 = frac,
2678 cg.body.writeOperand(Id, zero_id);3030 .operand_2 = zero_id,
3031 });
2679 break :blk r;3032 break :blk r;
2680 };3033 };
26813034
2682 const fill_id = if (is_arithmetic) blk: {3035 const fill_id = if (is_arithmetic) blk: {
2683 const i32_ty_id = try cg.resolveType(.i32, .direct);3036 const i32_ty_id = try cg.resolveType(.i32, .direct);
2684 const msb_signed = cg.module.allocId();3037 const msb_signed = cg.allocId();
2685 try cg.body.emit(gpa, .OpBitcast, .{3038 try cg.body.emit(gpa, .OpBitcast, .{
2686 .id_result_type = i32_ty_id,3039 .id_result_type = i32_ty_id,
2687 .id_result = msb_signed,3040 .id_result = msb_signed,
2688 .operand = ci.limbs[ci.n_limbs - 1],3041 .operand = ci.limbs[ci.n_limbs - 1],
2689 });3042 });
2690 const shift31 = try cg.constInt(.i32, @as(i32, 31));3043 const shift31 = try cg.constInt(.i32, @as(i32, 31));
2691 const sign_ext = cg.module.allocId();3044 const sign_ext = cg.allocId();
2692 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);3045 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
2693 cg.body.writeOperand(Id, i32_ty_id);3046 .id_result_type = i32_ty_id,
2694 cg.body.writeOperand(Id, sign_ext);3047 .id_result = sign_ext,
2695 cg.body.writeOperand(Id, msb_signed);3048 .base = msb_signed,
2696 cg.body.writeOperand(Id, shift31);3049 .shift = shift31,
2697 const back = cg.module.allocId();3050 });
3051 const back = cg.allocId();
2698 try cg.body.emit(gpa, .OpBitcast, .{3052 try cg.body.emit(gpa, .OpBitcast, .{
2699 .id_result_type = u32_ty_id,3053 .id_result_type = u32_ty_id,
2700 .id_result = back,3054 .id_result = back,
...@@ -2707,7 +3061,7 @@ const CompositeInt = struct {...@@ -2707,7 +3061,7 @@ const CompositeInt = struct {
27073061
2708 const arith_carry_init = if (is_arithmetic) blk: {3062 const arith_carry_init = if (is_arithmetic) blk: {
2709 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);3063 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);
2710 const guarded = cg.module.allocId();3064 const guarded = cg.allocId();
2711 try cg.body.emit(gpa, .OpSelect, .{3065 try cg.body.emit(gpa, .OpSelect, .{
2712 .id_result_type = u32_ty_id,3066 .id_result_type = u32_ty_id,
2713 .id_result = guarded,3067 .id_result = guarded,
...@@ -2727,17 +3081,18 @@ const CompositeInt = struct {...@@ -2727,17 +3081,18 @@ const CompositeInt = struct {
2727 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));3081 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));
2728 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);3082 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);
2729 const is_main = blk: {3083 const is_main = blk: {
2730 const r = cg.module.allocId();3084 const r = cg.allocId();
2731 try cg.body.emitRaw(gpa, .OpIEqual, 4);3085 try cg.body.emit(gpa, .OpIEqual, .{
2732 cg.body.writeOperand(Id, bool_ty_id);3086 .id_result_type = bool_ty_id,
2733 cg.body.writeOperand(Id, r);3087 .id_result = r,
2734 cg.body.writeOperand(Id, j_id);3088 .operand_1 = j_id,
2735 cg.body.writeOperand(Id, i_plus_whole);3089 .operand_2 = i_plus_whole,
3090 });
2736 break :blk r;3091 break :blk r;
2737 };3092 };
2738 const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac);3093 const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac);
2739 main_val = blk: {3094 main_val = blk: {
2740 const r = cg.module.allocId();3095 const r = cg.allocId();
2741 try cg.body.emit(gpa, .OpSelect, .{3096 try cg.body.emit(gpa, .OpSelect, .{
2742 .id_result_type = u32_ty_id,3097 .id_result_type = u32_ty_id,
2743 .id_result = r,3098 .id_result = r,
...@@ -2751,17 +3106,18 @@ const CompositeInt = struct {...@@ -2751,17 +3106,18 @@ const CompositeInt = struct {
2751 const one_id = try cg.constInt(.u32, @as(u32, 1));3106 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);3107 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);
2753 const is_carry = blk: {3108 const is_carry = blk: {
2754 const r = cg.module.allocId();3109 const r = cg.allocId();
2755 try cg.body.emitRaw(gpa, .OpIEqual, 4);3110 try cg.body.emit(gpa, .OpIEqual, .{
2756 cg.body.writeOperand(Id, bool_ty_id);3111 .id_result_type = bool_ty_id,
2757 cg.body.writeOperand(Id, r);3112 .id_result = r,
2758 cg.body.writeOperand(Id, j_id);3113 .operand_1 = j_id,
2759 cg.body.writeOperand(Id, i_plus_whole_plus_1);3114 .operand_2 = i_plus_whole_plus_1,
3115 });
2760 break :blk r;3116 break :blk r;
2761 };3117 };
2762 const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac);3118 const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac);
2763 const guarded_carry = blk: {3119 const guarded_carry = blk: {
2764 const r = cg.module.allocId();3120 const r = cg.allocId();
2765 try cg.body.emit(gpa, .OpSelect, .{3121 try cg.body.emit(gpa, .OpSelect, .{
2766 .id_result_type = u32_ty_id,3122 .id_result_type = u32_ty_id,
2767 .id_result = r,3123 .id_result = r,
...@@ -2772,7 +3128,7 @@ const CompositeInt = struct {...@@ -2772,7 +3128,7 @@ const CompositeInt = struct {
2772 break :blk r;3128 break :blk r;
2773 };3129 };
2774 carry_val = blk: {3130 carry_val = blk: {
2775 const r = cg.module.allocId();3131 const r = cg.allocId();
2776 try cg.body.emit(gpa, .OpSelect, .{3132 try cg.body.emit(gpa, .OpSelect, .{
2777 .id_result_type = u32_ty_id,3133 .id_result_type = u32_ty_id,
2778 .id_result = r,3134 .id_result = r,
...@@ -2792,9 +3148,9 @@ const CompositeInt = struct {...@@ -2792,9 +3148,9 @@ const CompositeInt = struct {
27923148
2793 fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id {3149 fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id {
2794 const cg = ci.cg;3150 const cg = ci.cg;
2795 const gpa = cg.module.gpa;3151 const gpa = cg.gpa;
2796 const pt = cg.pt;3152 const pt = cg.pt;
2797 const zcu = cg.module.zcu;3153 const zcu = cg.zcu;
2798 const ip = &zcu.intern_pool;3154 const ip = &zcu.intern_pool;
2799 const comp = zcu.comp;3155 const comp = zcu.comp;
2800 const io = comp.io;3156 const io = comp.io;
...@@ -2825,15 +3181,16 @@ const CompositeInt = struct {...@@ -2825,15 +3181,16 @@ const CompositeInt = struct {
2825 var hi: Id = undefined;3181 var hi: Id = undefined;
2826 switch (target.os.tag) {3182 switch (target.os.tag) {
2827 .opencl => {3183 .opencl => {
2828 lo = cg.module.allocId();3184 lo = cg.allocId();
2829 try cg.body.emitRaw(gpa, .OpIMul, 4);3185 try cg.body.emit(gpa, .OpIMul, .{
2830 cg.body.writeOperand(Id, u32_ty_id);3186 .id_result_type = u32_ty_id,
2831 cg.body.writeOperand(Id, lo);3187 .id_result = lo,
2832 cg.body.writeOperand(Id, ci.limbs[i]);3188 .operand_1 = ci.limbs[i],
2833 cg.body.writeOperand(Id, other.limbs[j]);3189 .operand_2 = other.limbs[j],
3190 });
28343191
2835 const set = try cg.importExtendedSet();3192 const set = try cg.importExtendedSet();
2836 hi = cg.module.allocId();3193 hi = cg.allocId();
2837 try cg.body.emit(gpa, .OpExtInst, .{3194 try cg.body.emit(gpa, .OpExtInst, .{
2838 .id_result_type = u32_ty_id,3195 .id_result_type = u32_ty_id,
2839 .id_result = hi,3196 .id_result = hi,
...@@ -2843,21 +3200,22 @@ const CompositeInt = struct {...@@ -2843,21 +3200,22 @@ const CompositeInt = struct {
2843 });3200 });
2844 },3201 },
2845 else => {3202 else => {
2846 const mul_result = cg.module.allocId();3203 const mul_result = cg.allocId();
2847 try cg.body.emitRaw(gpa, .OpUMulExtended, 4);3204 try cg.body.emit(gpa, .OpUMulExtended, .{
2848 cg.body.writeOperand(Id, pair_struct_ty_id);3205 .id_result_type = pair_struct_ty_id,
2849 cg.body.writeOperand(Id, mul_result);3206 .id_result = mul_result,
2850 cg.body.writeOperand(Id, ci.limbs[i]);3207 .operand_1 = ci.limbs[i],
2851 cg.body.writeOperand(Id, other.limbs[j]);3208 .operand_2 = other.limbs[j],
28523209 });
2853 lo = cg.module.allocId();3210
3211 lo = cg.allocId();
2854 try cg.body.emit(gpa, .OpCompositeExtract, .{3212 try cg.body.emit(gpa, .OpCompositeExtract, .{
2855 .id_result_type = u32_ty_id,3213 .id_result_type = u32_ty_id,
2856 .id_result = lo,3214 .id_result = lo,
2857 .composite = mul_result,3215 .composite = mul_result,
2858 .indexes = &.{0},3216 .indexes = &.{0},
2859 });3217 });
2860 hi = cg.module.allocId();3218 hi = cg.allocId();
2861 try cg.body.emit(gpa, .OpCompositeExtract, .{3219 try cg.body.emit(gpa, .OpCompositeExtract, .{
2862 .id_result_type = u32_ty_id,3220 .id_result_type = u32_ty_id,
2863 .id_result = hi,3221 .id_result = hi,
...@@ -2867,21 +3225,22 @@ const CompositeInt = struct {...@@ -2867,21 +3225,22 @@ const CompositeInt = struct {
2867 },3225 },
2868 }3226 }
28693227
2870 const add1 = cg.module.allocId();3228 const add1 = cg.allocId();
2871 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);3229 try cg.body.emit(gpa, .OpIAddCarry, .{
2872 cg.body.writeOperand(Id, pair_struct_ty_id);3230 .id_result_type = pair_struct_ty_id,
2873 cg.body.writeOperand(Id, add1);3231 .id_result = add1,
2874 cg.body.writeOperand(Id, result_limbs[k]);3232 .operand_1 = result_limbs[k],
2875 cg.body.writeOperand(Id, lo);3233 .operand_2 = lo,
3234 });
28763235
2877 const sum1 = cg.module.allocId();3236 const sum1 = cg.allocId();
2878 try cg.body.emit(gpa, .OpCompositeExtract, .{3237 try cg.body.emit(gpa, .OpCompositeExtract, .{
2879 .id_result_type = u32_ty_id,3238 .id_result_type = u32_ty_id,
2880 .id_result = sum1,3239 .id_result = sum1,
2881 .composite = add1,3240 .composite = add1,
2882 .indexes = &.{0},3241 .indexes = &.{0},
2883 });3242 });
2884 const c1 = cg.module.allocId();3243 const c1 = cg.allocId();
2885 try cg.body.emit(gpa, .OpCompositeExtract, .{3244 try cg.body.emit(gpa, .OpCompositeExtract, .{
2886 .id_result_type = u32_ty_id,3245 .id_result_type = u32_ty_id,
2887 .id_result = c1,3246 .id_result = c1,
...@@ -2889,21 +3248,22 @@ const CompositeInt = struct {...@@ -2889,21 +3248,22 @@ const CompositeInt = struct {
2889 .indexes = &.{1},3248 .indexes = &.{1},
2890 });3249 });
28913250
2892 const add2 = cg.module.allocId();3251 const add2 = cg.allocId();
2893 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);3252 try cg.body.emit(gpa, .OpIAddCarry, .{
2894 cg.body.writeOperand(Id, pair_struct_ty_id);3253 .id_result_type = pair_struct_ty_id,
2895 cg.body.writeOperand(Id, add2);3254 .id_result = add2,
2896 cg.body.writeOperand(Id, sum1);3255 .operand_1 = sum1,
2897 cg.body.writeOperand(Id, carry_id);3256 .operand_2 = carry_id,
3257 });
28983258
2899 result_limbs[k] = cg.module.allocId();3259 result_limbs[k] = cg.allocId();
2900 try cg.body.emit(gpa, .OpCompositeExtract, .{3260 try cg.body.emit(gpa, .OpCompositeExtract, .{
2901 .id_result_type = u32_ty_id,3261 .id_result_type = u32_ty_id,
2902 .id_result = result_limbs[k],3262 .id_result = result_limbs[k],
2903 .composite = add2,3263 .composite = add2,
2904 .indexes = &.{0},3264 .indexes = &.{0},
2905 });3265 });
2906 const c2 = cg.module.allocId();3266 const c2 = cg.allocId();
2907 try cg.body.emit(gpa, .OpCompositeExtract, .{3267 try cg.body.emit(gpa, .OpCompositeExtract, .{
2908 .id_result_type = u32_ty_id,3268 .id_result_type = u32_ty_id,
2909 .id_result = c2,3269 .id_result = c2,
...@@ -2925,8 +3285,8 @@ const CompositeInt = struct {...@@ -2925,8 +3285,8 @@ const CompositeInt = struct {
2925 fn normalize(ci: CompositeInt) !CompositeInt {3285 fn normalize(ci: CompositeInt) !CompositeInt {
2926 if (ci.info.bits == ci.info.backing_bits) return ci;3286 if (ci.info.bits == ci.info.backing_bits) return ci;
2927 const cg = ci.cg;3287 const cg = ci.cg;
2928 const gpa = cg.module.gpa;3288 const gpa = cg.gpa;
2929 const top_bits: u16 = ci.info.bits % Module.big_int_bits;3289 const top_bits: u16 = ci.info.bits % big_int_bits;
2930 assert(top_bits != 0);3290 assert(top_bits != 0);
29313291
2932 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);3292 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
...@@ -2947,25 +3307,27 @@ const CompositeInt = struct {...@@ -2947,25 +3307,27 @@ const CompositeInt = struct {
2947 const shift_amt: u32 = 32 - top_bits;3307 const shift_amt: u32 = 32 - top_bits;
2948 const shift_id = try cg.constInt(.u32, shift_amt);3308 const shift_id = try cg.constInt(.u32, shift_amt);
29493309
2950 const as_signed = cg.module.allocId();3310 const as_signed = cg.allocId();
2951 try cg.body.emit(gpa, .OpBitcast, .{3311 try cg.body.emit(gpa, .OpBitcast, .{
2952 .id_result_type = i32_ty_id,3312 .id_result_type = i32_ty_id,
2953 .id_result = as_signed,3313 .id_result = as_signed,
2954 .operand = top_limb,3314 .operand = top_limb,
2955 });3315 });
2956 const shifted_left = cg.module.allocId();3316 const shifted_left = cg.allocId();
2957 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);3317 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
2958 cg.body.writeOperand(Id, i32_ty_id);3318 .id_result_type = i32_ty_id,
2959 cg.body.writeOperand(Id, shifted_left);3319 .id_result = shifted_left,
2960 cg.body.writeOperand(Id, as_signed);3320 .base = as_signed,
2961 cg.body.writeOperand(Id, shift_id);3321 .shift = shift_id,
2962 const shifted_right = cg.module.allocId();3322 });
2963 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);3323 const shifted_right = cg.allocId();
2964 cg.body.writeOperand(Id, i32_ty_id);3324 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
2965 cg.body.writeOperand(Id, shifted_right);3325 .id_result_type = i32_ty_id,
2966 cg.body.writeOperand(Id, shifted_left);3326 .id_result = shifted_right,
2967 cg.body.writeOperand(Id, shift_id);3327 .base = shifted_left,
2968 const back = cg.module.allocId();3328 .shift = shift_id,
3329 });
3330 const back = cg.allocId();
2969 try cg.body.emit(gpa, .OpBitcast, .{3331 try cg.body.emit(gpa, .OpBitcast, .{
2970 .id_result_type = u32_ty_id,3332 .id_result_type = u32_ty_id,
2971 .id_result = back,3333 .id_result = back,
...@@ -3000,7 +3362,7 @@ const Vectorization = union(enum) {...@@ -3000,7 +3362,7 @@ const Vectorization = union(enum) {
30003362
3001 /// Derive a vectorization from a particular type3363 /// Derive a vectorization from a particular type
3002 fn fromType(ty: Type, cg: *CodeGen) Vectorization {3364 fn fromType(ty: Type, cg: *CodeGen) Vectorization {
3003 const zcu = cg.module.zcu;3365 const zcu = cg.zcu;
3004 if (!ty.isVector(zcu)) return .scalar;3366 if (!ty.isVector(zcu)) return .scalar;
3005 return .{ .unrolled = ty.vectorLen(zcu) };3367 return .{ .unrolled = ty.vectorLen(zcu) };
3006 }3368 }
...@@ -3034,7 +3396,7 @@ const Vectorization = union(enum) {...@@ -3034,7 +3396,7 @@ const Vectorization = union(enum) {
3034 /// `ty` may be a scalar or vector, it doesn't matter.3396 /// `ty` may be a scalar or vector, it doesn't matter.
3035 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {3397 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {
3036 const pt = cg.pt;3398 const pt = cg.pt;
3037 const zcu = cg.module.zcu;3399 const zcu = cg.zcu;
3038 const scalar_ty = ty.scalarType(zcu);3400 const scalar_ty = ty.scalarType(zcu);
3039 return switch (vec) {3401 return switch (vec) {
3040 .scalar => scalar_ty,3402 .scalar => scalar_ty,
...@@ -3046,7 +3408,7 @@ const Vectorization = union(enum) {...@@ -3046,7 +3408,7 @@ const Vectorization = union(enum) {
3046 /// this setup, and returns a new type that holds the relevant information on how to access3408 /// this setup, and returns a new type that holds the relevant information on how to access
3047 /// elements of the input.3409 /// elements of the input.
3048 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {3410 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {
3049 const zcu = cg.module.zcu;3411 const zcu = cg.zcu;
3050 const is_vector = tmp.ty.isVector(zcu);3412 const is_vector = tmp.ty.isVector(zcu);
3051 const value: PreparedOperand.Value = switch (tmp.value) {3413 const value: PreparedOperand.Value = switch (tmp.value) {
3052 .singleton => |id| switch (vec) {3414 .singleton => |id| switch (vec) {
...@@ -3146,26 +3508,28 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {...@@ -3146,26 +3508,28 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {
3146/// This function builds an OpSConvert of OpUConvert depending on the3508/// This function builds an OpSConvert of OpUConvert depending on the
3147/// signedness of the types.3509/// signedness of the types.
3148fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {3510fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3149 const zcu = cg.module.zcu;3511 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);
31533512
3154 const v = cg.vectorization(.{ dst_ty, src });3513 const v = cg.vectorization(.{ dst_ty, src });
3155 const result_ty = try v.resultType(cg, dst_ty);3514 const result_ty = try v.resultType(cg, dst_ty);
31563515
3157 // We can directly compare integers, because those type-IDs are cached.3516 const dst_scalar = dst_ty.scalarType(zcu);
3158 if (dst_ty_id == src_ty_id) {3517 const src_scalar = src.ty.scalarType(zcu);
3159 // Nothing to do, type-pun to the right value.3518 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);3519 return src.pun(result_ty);
3165 }3520 }
3521 if (dst_scalar.isInt(zcu) and src_scalar.isInt(zcu)) {
3522 const dst_info = dst_scalar.intInfo(zcu);
3523 const src_info = src_scalar.intInfo(zcu);
3524 if (cg.backingIntBits(dst_info.bits).@"0" == cg.backingIntBits(src_info.bits).@"0" and
3525 dst_info.signedness == src_info.signedness)
3526 {
3527 return src.pun(result_ty);
3528 }
3529 }
31663530
3167 const ops = v.components();3531 const ops = v.components();
3168 const results = cg.module.allocIds(ops);3532 const results = cg.allocIds(ops);
31693533
3170 const op_result_ty = dst_ty.scalarType(zcu);3534 const op_result_ty = dst_ty.scalarType(zcu);
3171 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3535 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
...@@ -3179,7 +3543,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {...@@ -3179,7 +3543,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3179 const op_src = try v.prepare(cg, src);3543 const op_src = try v.prepare(cg, src);
31803544
3181 for (0..ops) |i| {3545 for (0..ops) |i| {
3182 try cg.body.emitRaw(cg.module.gpa, opcode, 3);3546 try cg.body.emitRaw(cg.gpa, opcode, 3);
3183 cg.body.writeOperand(Id, op_result_ty_id);3547 cg.body.writeOperand(Id, op_result_ty_id);
3184 cg.body.writeOperand(Id, results.at(i));3548 cg.body.writeOperand(Id, results.at(i));
3185 cg.body.writeOperand(Id, op_src.at(i));3549 cg.body.writeOperand(Id, op_src.at(i));
...@@ -3188,51 +3552,12 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {...@@ -3188,51 +3552,12 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3188 return v.finalize(result_ty, results);3552 return v.finalize(result_ty, results);
3189}3553}
31903554
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 {3555fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary {
3231 const zcu = cg.module.zcu;3556 const zcu = cg.zcu;
32323557
3233 const v = cg.vectorization(.{ condition, lhs, rhs });3558 const v = cg.vectorization(.{ condition, lhs, rhs });
3234 const ops = v.components();3559 const ops = v.components();
3235 const results = cg.module.allocIds(ops);3560 const results = cg.allocIds(ops);
32363561
3237 const op_result_ty = lhs.ty.scalarType(zcu);3562 const op_result_ty = lhs.ty.scalarType(zcu);
3238 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3563 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
...@@ -3245,7 +3570,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar...@@ -3245,7 +3570,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar
3245 const object_2 = try v.prepare(cg, rhs);3570 const object_2 = try v.prepare(cg, rhs);
32463571
3247 for (0..ops) |i| {3572 for (0..ops) |i| {
3248 try cg.body.emit(cg.module.gpa, .OpSelect, .{3573 try cg.body.emit(cg.gpa, .OpSelect, .{
3249 .id_result_type = op_result_ty_id,3574 .id_result_type = op_result_ty_id,
3250 .id_result = results.at(i),3575 .id_result = results.at(i),
3251 .condition = cond.at(i),3576 .condition = cond.at(i),
...@@ -3260,7 +3585,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar...@@ -3260,7 +3585,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar
3260fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {3585fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
3261 const v = cg.vectorization(.{ lhs, rhs });3586 const v = cg.vectorization(.{ lhs, rhs });
3262 const ops = v.components();3587 const ops = v.components();
3263 const results = cg.module.allocIds(ops);3588 const results = cg.allocIds(ops);
32643589
3265 const op_result_ty: Type = .bool;3590 const op_result_ty: Type = .bool;
3266 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3591 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
...@@ -3270,7 +3595,7 @@ fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Tempo...@@ -3270,7 +3595,7 @@ fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Tempo
3270 const op_rhs = try v.prepare(cg, rhs);3595 const op_rhs = try v.prepare(cg, rhs);
32713596
3272 for (0..ops) |i| {3597 for (0..ops) |i| {
3273 try cg.body.emitRaw(cg.module.gpa, opcode, 4);3598 try cg.body.emitRaw(cg.gpa, opcode, 4);
3274 cg.body.writeOperand(Id, op_result_ty_id);3599 cg.body.writeOperand(Id, op_result_ty_id);
3275 cg.body.writeOperand(Id, results.at(i));3600 cg.body.writeOperand(Id, results.at(i));
3276 cg.body.writeOperand(Id, op_lhs.at(i));3601 cg.body.writeOperand(Id, op_lhs.at(i));
...@@ -3351,11 +3676,11 @@ const UnaryOp = enum {...@@ -3351,11 +3676,11 @@ const UnaryOp = enum {
3351};3676};
33523677
3353fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {3678fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3354 const zcu = cg.module.zcu;3679 const zcu = cg.zcu;
3355 const target = cg.module.zcu.getTarget();3680 const target = cg.zcu.getTarget();
3356 const v = cg.vectorization(.{operand});3681 const v = cg.vectorization(.{operand});
3357 const ops = v.components();3682 const ops = v.components();
3358 const results = cg.module.allocIds(ops);3683 const results = cg.allocIds(ops);
3359 const op_result_ty = operand.ty.scalarType(zcu);3684 const op_result_ty = operand.ty.scalarType(zcu);
3360 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3685 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
3361 const result_ty = try v.resultType(cg, operand.ty);3686 const result_ty = try v.resultType(cg, operand.ty);
...@@ -3364,7 +3689,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {...@@ -3364,7 +3689,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3364 if (op.extInstOpcode(target)) |opcode| {3689 if (op.extInstOpcode(target)) |opcode| {
3365 const set = try cg.importExtendedSet();3690 const set = try cg.importExtendedSet();
3366 for (0..ops) |i| {3691 for (0..ops) |i| {
3367 try cg.body.emit(cg.module.gpa, .OpExtInst, .{3692 try cg.body.emit(cg.gpa, .OpExtInst, .{
3368 .id_result_type = op_result_ty_id,3693 .id_result_type = op_result_ty_id,
3369 .id_result = results.at(i),3694 .id_result = results.at(i),
3370 .set = set,3695 .set = set,
...@@ -3384,7 +3709,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {...@@ -3384,7 +3709,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3384 ),3709 ),
3385 };3710 };
3386 for (0..ops) |i| {3711 for (0..ops) |i| {
3387 try cg.body.emitRaw(cg.module.gpa, opcode, 3);3712 try cg.body.emitRaw(cg.gpa, opcode, 3);
3388 cg.body.writeOperand(Id, op_result_ty_id);3713 cg.body.writeOperand(Id, op_result_ty_id);
3389 cg.body.writeOperand(Id, results.at(i));3714 cg.body.writeOperand(Id, results.at(i));
3390 cg.body.writeOperand(Id, op_operand.at(i));3715 cg.body.writeOperand(Id, op_operand.at(i));
...@@ -3395,11 +3720,11 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {...@@ -3395,11 +3720,11 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3395}3720}
33963721
3397fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {3722fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
3398 const zcu = cg.module.zcu;3723 const zcu = cg.zcu;
33993724
3400 const v = cg.vectorization(.{ lhs, rhs });3725 const v = cg.vectorization(.{ lhs, rhs });
3401 const ops = v.components();3726 const ops = v.components();
3402 const results = cg.module.allocIds(ops);3727 const results = cg.allocIds(ops);
34033728
3404 const op_result_ty = lhs.ty.scalarType(zcu);3729 const op_result_ty = lhs.ty.scalarType(zcu);
3405 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);3730 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
...@@ -3409,7 +3734,7 @@ fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Te...@@ -3409,7 +3734,7 @@ fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Te
3409 const op_rhs = try v.prepare(cg, rhs);3734 const op_rhs = try v.prepare(cg, rhs);
34103735
3411 for (0..ops) |i| {3736 for (0..ops) |i| {
3412 try cg.body.emitRaw(cg.module.gpa, opcode, 4);3737 try cg.body.emitRaw(cg.gpa, opcode, 4);
3413 cg.body.writeOperand(Id, op_result_ty_id);3738 cg.body.writeOperand(Id, op_result_ty_id);
3414 cg.body.writeOperand(Id, results.at(i));3739 cg.body.writeOperand(Id, results.at(i));
3415 cg.body.writeOperand(Id, op_lhs.at(i));3740 cg.body.writeOperand(Id, op_lhs.at(i));
...@@ -3428,11 +3753,11 @@ fn buildWideMul(...@@ -3428,11 +3753,11 @@ fn buildWideMul(
3428 rhs: Temporary,3753 rhs: Temporary,
3429) !struct { Temporary, Temporary } {3754) !struct { Temporary, Temporary } {
3430 const pt = cg.pt;3755 const pt = cg.pt;
3431 const zcu = cg.module.zcu;3756 const zcu = cg.zcu;
3432 const comp = zcu.comp;3757 const comp = zcu.comp;
3433 const gpa = comp.gpa;3758 const gpa = comp.gpa;
3434 const io = comp.io;3759 const io = comp.io;
3435 const target = cg.module.zcu.getTarget();3760 const target = cg.zcu.getTarget();
3436 const ip = &zcu.intern_pool;3761 const ip = &zcu.intern_pool;
34373762
3438 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));3763 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));
...@@ -3444,8 +3769,8 @@ fn buildWideMul(...@@ -3444,8 +3769,8 @@ fn buildWideMul(
3444 const lhs_op = try v.prepare(cg, lhs);3769 const lhs_op = try v.prepare(cg, lhs);
3445 const rhs_op = try v.prepare(cg, rhs);3770 const rhs_op = try v.prepare(cg, rhs);
34463771
3447 const value_results = cg.module.allocIds(ops);3772 const value_results = cg.allocIds(ops);
3448 const overflow_results = cg.module.allocIds(ops);3773 const overflow_results = cg.allocIds(ops);
34493774
3450 switch (target.os.tag) {3775 switch (target.os.tag) {
3451 .opencl => {3776 .opencl => {
...@@ -3490,7 +3815,7 @@ fn buildWideMul(...@@ -3490,7 +3815,7 @@ fn buildWideMul(
3490 };3815 };
34913816
3492 for (0..ops) |i| {3817 for (0..ops) |i| {
3493 const op_result = cg.module.allocId();3818 const op_result = cg.allocId();
34943819
3495 try cg.body.emitRaw(gpa, opcode, 4);3820 try cg.body.emitRaw(gpa, opcode, 4);
3496 cg.body.writeOperand(Id, op_result_ty_id);3821 cg.body.writeOperand(Id, op_result_ty_id);
...@@ -3550,12 +3875,12 @@ fn buildWideMul(...@@ -3550,12 +3875,12 @@ fn buildWideMul(
3550fn generateTestEntryPoint(3875fn generateTestEntryPoint(
3551 cg: *CodeGen,3876 cg: *CodeGen,
3552 name: []const u8,3877 name: []const u8,
3553 spv_decl_index: Module.Decl.Index,3878 spv_decl_index: Decl.Index,
3554 test_id: Id,3879 test_id: Id,
3555) !void {3880) !void {
3556 const gpa = cg.module.gpa;3881 const gpa = cg.gpa;
3557 const zcu = cg.module.zcu;3882 const zcu = cg.zcu;
3558 const target = cg.module.zcu.getTarget();3883 const target = cg.zcu.getTarget();
35593884
3560 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);3885 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);
3561 const ptr_anyerror_ty = try cg.pt.ptrType(.{3886 const ptr_anyerror_ty = try cg.pt.ptrType(.{
...@@ -3564,15 +3889,15 @@ fn generateTestEntryPoint(...@@ -3564,15 +3889,15 @@ fn generateTestEntryPoint(
3564 });3889 });
3565 const ptr_anyerror_ty_id = try cg.resolveType(ptr_anyerror_ty, .direct);3890 const ptr_anyerror_ty_id = try cg.resolveType(ptr_anyerror_ty, .direct);
35663891
3567 const kernel_id = cg.module.declPtr(spv_decl_index).result_id;3892 const kernel_id = cg.declPtr(spv_decl_index).result_id;
35683893
3569 const section = &cg.module.sections.functions;3894 const section = &cg.sections.functions;
35703895
3571 const p_error_id = cg.module.allocId();3896 const p_error_id = cg.allocId();
3572 switch (target.os.tag) {3897 switch (target.os.tag) {
3573 .opencl, .amdhsa => {3898 .opencl, .amdhsa => {
3574 const void_ty_id = try cg.resolveType(.void, .direct);3899 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});3900 const kernel_proto_ty_id = try cg.functionType(void_ty_id, &.{ptr_anyerror_ty_id});
35763901
3577 try section.emit(gpa, .OpFunction, .{3902 try section.emit(gpa, .OpFunction, .{
3578 .id_result_type = try cg.resolveType(.void, .direct),3903 .id_result_type = try cg.resolveType(.void, .direct),
...@@ -3587,43 +3912,43 @@ fn generateTestEntryPoint(...@@ -3587,43 +3912,43 @@ fn generateTestEntryPoint(
3587 });3912 });
35883913
3589 try section.emit(gpa, .OpLabel, .{3914 try section.emit(gpa, .OpLabel, .{
3590 .id_result = cg.module.allocId(),3915 .id_result = cg.allocId(),
3591 });3916 });
3592 },3917 },
3593 .vulkan, .opengl => {3918 .vulkan, .opengl => {
3594 if (cg.module.error_buffer == null) {3919 if (cg.error_buffer == null) {
3595 const spv_err_decl_index = try cg.module.allocDecl(.global);3920 const spv_err_decl_index = try cg.allocDecl(.global);
3596 const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id;3921 const err_buf_result_id = cg.declPtr(spv_err_decl_index).result_id;
35973922
3598 const buffer_struct_ty_id = cg.module.allocId();3923 const buffer_struct_ty_id = cg.allocId();
3599 try cg.module.sections.globals.emit(gpa, .OpTypeStruct, .{3924 try cg.sections.globals.emit(gpa, .OpTypeStruct, .{
3600 .id_result = buffer_struct_ty_id,3925 .id_result = buffer_struct_ty_id,
3601 .id_ref = &.{anyerror_ty_id},3926 .id_ref = &.{anyerror_ty_id},
3602 });3927 });
3603 try cg.module.memberDebugName(buffer_struct_ty_id, 0, "error_out");3928 try cg.memberDebugName(buffer_struct_ty_id, 0, "error_out");
3604 try cg.module.decorate(buffer_struct_ty_id, .block);3929 try cg.decorate(buffer_struct_ty_id, .block);
3605 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });3930 try cg.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
36063931
3607 const ptr_buffer_struct_ty_id = cg.module.allocId();3932 const ptr_buffer_struct_ty_id = cg.allocId();
3608 try cg.module.sections.globals.emit(gpa, .OpTypePointer, .{3933 try cg.sections.globals.emit(gpa, .OpTypePointer, .{
3609 .id_result = ptr_buffer_struct_ty_id,3934 .id_result = ptr_buffer_struct_ty_id,
3610 .storage_class = cg.module.storageClass(.global),3935 .storage_class = cg.storageClass(.global),
3611 .type = buffer_struct_ty_id,3936 .type = buffer_struct_ty_id,
3612 });3937 });
36133938
3614 try cg.module.sections.globals.emit(gpa, .OpVariable, .{3939 try cg.sections.globals.emit(gpa, .OpVariable, .{
3615 .id_result_type = ptr_buffer_struct_ty_id,3940 .id_result_type = ptr_buffer_struct_ty_id,
3616 .id_result = err_buf_result_id,3941 .id_result = err_buf_result_id,
3617 .storage_class = cg.module.storageClass(.global),3942 .storage_class = cg.storageClass(.global),
3618 });3943 });
3619 try cg.module.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } });3944 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 } });3945 try cg.decorate(err_buf_result_id, .{ .binding = .{ .binding_point = 0 } });
36213946
3622 cg.module.error_buffer = spv_err_decl_index;3947 cg.error_buffer = spv_err_decl_index;
3623 }3948 }
36243949
3625 const void_ty_id = try cg.resolveType(.void, .direct);3950 const void_ty_id = try cg.resolveType(.void, .direct);
3626 const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});3951 const kernel_proto_ty_id = try cg.functionType(void_ty_id, &.{});
3627 try section.emit(gpa, .OpFunction, .{3952 try section.emit(gpa, .OpFunction, .{
3628 .id_result_type = try cg.resolveType(.void, .direct),3953 .id_result_type = try cg.resolveType(.void, .direct),
3629 .id_result = kernel_id,3954 .id_result = kernel_id,
...@@ -3631,12 +3956,12 @@ fn generateTestEntryPoint(...@@ -3631,12 +3956,12 @@ fn generateTestEntryPoint(
3631 .function_type = kernel_proto_ty_id,3956 .function_type = kernel_proto_ty_id,
3632 });3957 });
3633 try section.emit(gpa, .OpLabel, .{3958 try section.emit(gpa, .OpLabel, .{
3634 .id_result = cg.module.allocId(),3959 .id_result = cg.allocId(),
3635 });3960 });
36363961
3637 const spv_err_decl_index = cg.module.error_buffer.?;3962 const spv_err_decl_index = cg.error_buffer.?;
3638 const buffer_id = cg.module.declPtr(spv_err_decl_index).result_id;3963 const buffer_id = cg.declPtr(spv_err_decl_index).result_id;
3639 try cg.module.decl_deps.append(gpa, spv_err_decl_index);3964 try cg.decl_deps.append(gpa, spv_err_decl_index);
36403965
3641 const zero_id = try cg.constInt(.u32, 0);3966 const zero_id = try cg.constInt(.u32, 0);
3642 try section.emit(gpa, .OpInBoundsAccessChain, .{3967 try section.emit(gpa, .OpInBoundsAccessChain, .{
...@@ -3649,7 +3974,7 @@ fn generateTestEntryPoint(...@@ -3649,7 +3974,7 @@ fn generateTestEntryPoint(
3649 else => unreachable,3974 else => unreachable,
3650 }3975 }
36513976
3652 const error_id = cg.module.allocId();3977 const error_id = cg.allocId();
3653 try section.emit(gpa, .OpFunctionCall, .{3978 try section.emit(gpa, .OpFunctionCall, .{
3654 .id_result_type = anyerror_ty_id,3979 .id_result_type = anyerror_ty_id,
3655 .id_result = error_id,3980 .id_result = error_id,
...@@ -3668,9 +3993,14 @@ fn generateTestEntryPoint(...@@ -3668,9 +3993,14 @@ fn generateTestEntryPoint(
36683993
3669 // Just generate a quick other name because the intel runtime crashes when the entry-3994 // Just generate a quick other name because the intel runtime crashes when the entry-
3670 // point name is the same as a different OpName.3995 // point name is the same as a different OpName.
3671 const test_name = try std.fmt.allocPrint(cg.module.arena, "test {s}", .{name});3996 const test_name = try std.fmt.allocPrint(cg.arena, "test {s}", .{name});
36723997
3673 try cg.module.declareEntryPoint(spv_decl_index, test_name, .{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } });3998 const ep_gop = try cg.entry_points.getOrPut(cg.gpa, cg.declPtr(spv_decl_index).result_id);
3999 ep_gop.value_ptr.* = .{
4000 .decl_index = spv_decl_index,
4001 .name = test_name,
4002 .cc = .{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } },
4003 };
3674}4004}
36754005
3676fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {4006fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
...@@ -3688,7 +4018,7 @@ fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {...@@ -3688,7 +4018,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).4018/// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct).
3689fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {4019fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3690 const pt = cg.pt;4020 const pt = cg.pt;
3691 const zcu = cg.module.zcu;4021 const zcu = cg.zcu;
3692 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {4022 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
3693 .bool => {4023 .bool => {
3694 const false_id = try cg.constBool(false, .indirect);4024 const false_id = try cg.constBool(false, .indirect);
...@@ -3714,7 +4044,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {...@@ -3714,7 +4044,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3714/// Convert representation from direct (in 'register) to direct (in memory)4044/// Convert representation from direct (in 'register) to direct (in memory)
3715/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).4045/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).
3716fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {4046fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3717 const zcu = cg.module.zcu;4047 const zcu = cg.zcu;
3718 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {4048 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
3719 .bool => {4049 .bool => {
3720 const result = try cg.intFromBool(.init(ty, operand_id), .u1);4050 const result = try cg.intFromBool(.init(ty, operand_id), .u1);
...@@ -3726,9 +4056,9 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {...@@ -3726,9 +4056,9 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
37264056
3727fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {4057fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
3728 const result_ty_id = try cg.resolveType(result_ty, .indirect);4058 const result_ty_id = try cg.resolveType(result_ty, .indirect);
3729 const result_id = cg.module.allocId();4059 const result_id = cg.allocId();
3730 const indexes = [_]u32{field};4060 const indexes = [_]u32{field};
3731 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{4061 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
3732 .id_result_type = result_ty_id,4062 .id_result_type = result_ty_id,
3733 .id_result = result_id,4063 .id_result = result_id,
3734 .composite = object,4064 .composite = object,
...@@ -3740,9 +4070,9 @@ fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {...@@ -3740,9 +4070,9 @@ fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
37404070
3741fn extractVectorComponent(cg: *CodeGen, result_ty: Type, vector_id: Id, field: u32) !Id {4071fn extractVectorComponent(cg: *CodeGen, result_ty: Type, vector_id: Id, field: u32) !Id {
3742 const result_ty_id = try cg.resolveType(result_ty, .direct);4072 const result_ty_id = try cg.resolveType(result_ty, .direct);
3743 const result_id = cg.module.allocId();4073 const result_id = cg.allocId();
3744 const indexes = [_]u32{field};4074 const indexes = [_]u32{field};
3745 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{4075 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
3746 .id_result_type = result_ty_id,4076 .id_result_type = result_ty_id,
3747 .id_result = result_id,4077 .id_result = result_id,
3748 .composite = vector_id,4078 .composite = vector_id,
...@@ -3757,15 +4087,15 @@ const MemoryOptions = struct {...@@ -3757,15 +4087,15 @@ const MemoryOptions = struct {
3757};4087};
37584088
3759fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {4089fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
3760 const zcu = cg.module.zcu;4090 const zcu = cg.zcu;
3761 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);4091 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);
3762 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);4092 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);
3763 const result_id = cg.module.allocId();4093 const result_id = cg.allocId();
3764 const access: spec.MemoryAccess.Extended = .{4094 const access: spec.MemoryAccess.Extended = .{
3765 .@"volatile" = options.is_volatile,4095 .@"volatile" = options.is_volatile,
3766 .aligned = .{ .literal_integer = alignment },4096 .aligned = .{ .literal_integer = alignment },
3767 };4097 };
3768 try cg.body.emit(cg.module.gpa, .OpLoad, .{4098 try cg.body.emit(cg.gpa, .OpLoad, .{
3769 .id_result_type = indirect_value_ty_id,4099 .id_result_type = indirect_value_ty_id,
3770 .id_result = result_id,4100 .id_result = result_id,
3771 .pointer = ptr_id,4101 .pointer = ptr_id,
...@@ -3777,7 +4107,7 @@ fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {...@@ -3777,7 +4107,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 {4107fn 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);4108 const indirect_value_id = try cg.convertToIndirect(value_ty, value_id);
3779 const access: spec.MemoryAccess.Extended = .{ .@"volatile" = options.is_volatile };4109 const access: spec.MemoryAccess.Extended = .{ .@"volatile" = options.is_volatile };
3780 try cg.body.emit(cg.module.gpa, .OpStore, .{4110 try cg.body.emit(cg.gpa, .OpStore, .{
3781 .pointer = ptr_id,4111 .pointer = ptr_id,
3782 .object = indirect_value_id,4112 .object = indirect_value_id,
3783 .memory_access = access,4113 .memory_access = access,
...@@ -3791,8 +4121,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {...@@ -3791,8 +4121,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {
3791}4121}
37924122
3793fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {4123fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
3794 const gpa = cg.module.gpa;4124 const gpa = cg.gpa;
3795 const zcu = cg.module.zcu;4125 const zcu = cg.zcu;
3796 const ip = &zcu.intern_pool;4126 const ip = &zcu.intern_pool;
3797 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))4127 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))
3798 return;4128 return;
...@@ -4028,7 +4358,7 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {...@@ -4028,7 +4358,7 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {
4028}4358}
40294359
4030fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id {4360fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id {
4031 const zcu = cg.module.zcu;4361 const zcu = cg.zcu;
4032 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4362 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
40334363
4034 if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) {4364 if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) {
...@@ -4048,8 +4378,8 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode...@@ -4048,8 +4378,8 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
4048 .composite_integer => blk: {4378 .composite_integer => blk: {
4049 const shift_id = try shift.materialize(cg);4379 const shift_id = try shift.materialize(cg);
4050 const u32_ty_id = try cg.resolveType(.u32, .direct);4380 const u32_ty_id = try cg.resolveType(.u32, .direct);
4051 const result_id = cg.module.allocId();4381 const result_id = cg.allocId();
4052 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{4382 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
4053 .id_result_type = u32_ty_id,4383 .id_result_type = u32_ty_id,
4054 .id_result = result_id,4384 .id_result = result_id,
4055 .composite = shift_id,4385 .composite = shift_id,
...@@ -4156,13 +4486,13 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id {...@@ -4156,13 +4486,13 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id {
4156}4486}
41574487
4158fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {4488fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4159 const zcu = cg.module.zcu;4489 const zcu = cg.zcu;
4160 const target = zcu.getTarget();4490 const target = zcu.getTarget();
4161 const info = cg.arithmeticTypeInfo(lhs.ty);4491 const info = cg.arithmeticTypeInfo(lhs.ty);
41624492
4163 const v = cg.vectorization(.{ lhs, rhs });4493 const v = cg.vectorization(.{ lhs, rhs });
4164 const ops = v.components();4494 const ops = v.components();
4165 const results = cg.module.allocIds(ops);4495 const results = cg.allocIds(ops);
41664496
4167 const op_result_ty = lhs.ty.scalarType(zcu);4497 const op_result_ty = lhs.ty.scalarType(zcu);
4168 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);4498 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
...@@ -4174,7 +4504,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {...@@ -4174,7 +4504,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4174 const set = try cg.importExtendedSet();4504 const set = try cg.importExtendedSet();
4175 const opcode = op.extInstOpcode(target, info);4505 const opcode = op.extInstOpcode(target, info);
4176 for (0..ops) |i| {4506 for (0..ops) |i| {
4177 try cg.body.emit(cg.module.gpa, .OpExtInst, .{4507 try cg.body.emit(cg.gpa, .OpExtInst, .{
4178 .id_result_type = op_result_ty_id,4508 .id_result_type = op_result_ty_id,
4179 .id_result = results.at(i),4509 .id_result = results.at(i),
4180 .set = set,4510 .set = set,
...@@ -4195,7 +4525,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {...@@ -4195,7 +4525,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4195/// All other values are returned unmodified (this makes strange integer4525/// All other values are returned unmodified (this makes strange integer
4196/// wrapping easier to use in generic operations).4526/// wrapping easier to use in generic operations).
4197fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {4527fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {
4198 const zcu = cg.module.zcu;4528 const zcu = cg.zcu;
4199 const ty = value.ty;4529 const ty = value.ty;
4200 switch (info.class) {4530 switch (info.class) {
4201 .integer, .bool, .float => return value,4531 .integer, .bool, .float => return value,
...@@ -4341,29 +4671,24 @@ fn airArithOp(...@@ -4341,29 +4671,24 @@ fn airArithOp(
4341}4671}
43424672
4343fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4673fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4674 const zcu = cg.zcu;
4675 const target = zcu.getTarget();
4344 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4676 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4345 const operand = try cg.temporary(ty_op.operand);4677 const value = try cg.temporary(ty_op.operand);
4346 // Note: operand_ty may be signed, while ty is always unsigned!4678 // Note: operand_ty may be signed, while ty is always unsigned.
4347 const result_ty = cg.typeOfIndex(inst);4679 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);4680 const operand_info = cg.arithmeticTypeInfo(value.ty);
4356 switch (operand_info.class) {4681 const result: Temporary = switch (operand_info.class) {
4357 .float => return try cg.buildUnary(.f_abs, value),4682 .float => try cg.buildUnary(.f_abs, value),
4358 .integer, .strange_integer => {4683 .integer, .strange_integer => abs: {
4359 var abs_value = try cg.buildUnary(.i_abs, value);4684 var abs_value = try cg.buildUnary(.i_abs, value);
4360 switch (target.os.tag) {4685 switch (target.os.tag) {
4361 .vulkan, .opengl => {4686 .vulkan, .opengl => {
4362 if (value.ty.intInfo(zcu).signedness == .signed) {4687 if (value.ty.intInfo(zcu).signedness == .signed) {
4363 const abs_id = try abs_value.materialize(cg);4688 const abs_id = try abs_value.materialize(cg);
4364 const dst_ty_id = try cg.resolveType(result_ty, .direct);4689 const dst_ty_id = try cg.resolveType(result_ty, .direct);
4365 const cast_id = cg.module.allocId();4690 const cast_id = cg.allocId();
4366 try cg.body.emit(cg.module.gpa, .OpBitcast, .{4691 try cg.body.emit(cg.gpa, .OpBitcast, .{
4367 .id_result_type = dst_ty_id,4692 .id_result_type = dst_ty_id,
4368 .id_result = cast_id,4693 .id_result = cast_id,
4369 .operand = abs_id,4694 .operand = abs_id,
...@@ -4373,9 +4698,9 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -4373,9 +4698,9 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
4373 },4698 },
4374 else => {},4699 else => {},
4375 }4700 }
4376 return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));4701 break :abs try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
4377 },4702 },
4378 .composite_integer => {4703 .composite_integer => abs: {
4379 const val_id = try value.materialize(cg);4704 const val_id = try value.materialize(cg);
4380 const scratch_top = cg.id_scratch.items.len;4705 const scratch_top = cg.id_scratch.items.len;
4381 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);4706 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
...@@ -4385,10 +4710,10 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -4385,10 +4710,10 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
4385 const ci_neg = try ci_z.addSub(ci, false);4710 const ci_neg = try ci_z.addSub(ci, false);
4386 const result_info = cg.arithmeticTypeInfo(result_ty);4711 const result_info = cg.arithmeticTypeInfo(result_ty);
4387 const u32_ty_id = try cg.resolveType(.u32, .direct);4712 const u32_ty_id = try cg.resolveType(.u32, .direct);
4388 const result_limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, ci.n_limbs);4713 const result_limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, ci.n_limbs);
4389 for (0..ci.n_limbs) |i| {4714 for (0..ci.n_limbs) |i| {
4390 result_limbs[i] = cg.module.allocId();4715 result_limbs[i] = cg.allocId();
4391 try cg.body.emit(cg.module.gpa, .OpSelect, .{4716 try cg.body.emit(cg.gpa, .OpSelect, .{
4392 .id_result_type = u32_ty_id,4717 .id_result_type = u32_ty_id,
4393 .id_result = result_limbs[i],4718 .id_result = result_limbs[i],
4394 .condition = is_neg,4719 .condition = is_neg,
...@@ -4398,10 +4723,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -4398,10 +4723,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
4398 }4723 }
4399 const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info);4724 const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info);
4400 const normalized = try ci_result.normalize();4725 const normalized = try ci_result.normalize();
4401 return .init(result_ty, try normalized.materialize(result_ty));4726 break :abs .init(result_ty, try normalized.materialize(result_ty));
4402 },4727 },
4403 .bool => unreachable,4728 .bool => unreachable,
4404 }4729 };
4730 return try result.materialize(cg);
4405}4731}
44064732
4407fn airAddSubOverflow(4733fn airAddSubOverflow(
...@@ -4457,32 +4783,36 @@ fn airAddSubOverflow(...@@ -4457,32 +4783,36 @@ fn airAddSubOverflow(
4457 const res_neg = try ci_res2.cmp(ci_z, .lt);4783 const res_neg = try ci_res2.cmp(ci_z, .lt);
44584784
4459 const bool_ty_id = try cg.resolveType(.bool, .direct);4785 const bool_ty_id = try cg.resolveType(.bool, .direct);
4460 const signs_match = cg.module.allocId();4786 const signs_match = cg.allocId();
4461 try cg.body.emitRaw(cg.module.gpa, .OpLogicalEqual, 4);4787 try cg.body.emit(cg.gpa, .OpLogicalEqual, .{
4462 cg.body.writeOperand(Id, bool_ty_id);4788 .id_result_type = bool_ty_id,
4463 cg.body.writeOperand(Id, signs_match);4789 .id_result = signs_match,
4464 cg.body.writeOperand(Id, lhs_neg);4790 .operand_1 = lhs_neg,
4465 cg.body.writeOperand(Id, rhs_neg);4791 .operand_2 = rhs_neg,
4466 const res_sign_diff = cg.module.allocId();4792 });
4467 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNotEqual, 4);4793 const res_sign_diff = cg.allocId();
4468 cg.body.writeOperand(Id, bool_ty_id);4794 try cg.body.emit(cg.gpa, .OpLogicalNotEqual, .{
4469 cg.body.writeOperand(Id, res_sign_diff);4795 .id_result_type = bool_ty_id,
4470 cg.body.writeOperand(Id, lhs_neg);4796 .id_result = res_sign_diff,
4471 cg.body.writeOperand(Id, res_neg);4797 .operand_1 = lhs_neg,
4798 .operand_2 = res_neg,
4799 });
4472 const ov_cond = if (add == .OpIAdd) signs_match else blk2: {4800 const ov_cond = if (add == .OpIAdd) signs_match else blk2: {
4473 const not_match = cg.module.allocId();4801 const not_match = cg.allocId();
4474 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNot, 3);4802 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
4475 cg.body.writeOperand(Id, bool_ty_id);4803 .id_result_type = bool_ty_id,
4476 cg.body.writeOperand(Id, not_match);4804 .id_result = not_match,
4477 cg.body.writeOperand(Id, signs_match);4805 .operand = signs_match,
4806 });
4478 break :blk2 not_match;4807 break :blk2 not_match;
4479 };4808 };
4480 const ov_result = cg.module.allocId();4809 const ov_result = cg.allocId();
4481 try cg.body.emitRaw(cg.module.gpa, .OpLogicalAnd, 4);4810 try cg.body.emit(cg.gpa, .OpLogicalAnd, .{
4482 cg.body.writeOperand(Id, bool_ty_id);4811 .id_result_type = bool_ty_id,
4483 cg.body.writeOperand(Id, ov_result);4812 .id_result = ov_result,
4484 cg.body.writeOperand(Id, ov_cond);4813 .operand_1 = ov_cond,
4485 cg.body.writeOperand(Id, res_sign_diff);4814 .operand_2 = res_sign_diff,
4815 });
4486 break :blk ov_result;4816 break :blk ov_result;
4487 },4817 },
4488 };4818 };
...@@ -4531,7 +4861,7 @@ fn airAddSubOverflow(...@@ -4531,7 +4861,7 @@ fn airAddSubOverflow(
45314861
4532fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4862fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4533 const pt = cg.pt;4863 const pt = cg.pt;
4534 const gpa = cg.module.gpa;4864 const gpa = cg.gpa;
4535 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4865 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4536 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;4866 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
4537 const lhs = try cg.temporary(extra.lhs);4867 const lhs = try cg.temporary(extra.lhs);
...@@ -4559,32 +4889,35 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4559,32 +4889,35 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45594889
4560 const bool_ty_id = try cg.resolveType(.bool, .direct);4890 const bool_ty_id = try cg.resolveType(.bool, .direct);
4561 const u32_ty_id = try cg.resolveType(.u32, .direct);4891 const u32_ty_id = try cg.resolveType(.u32, .direct);
4562 const n: usize = info.backing_bits / Module.big_int_bits;4892 const n: usize = info.backing_bits / big_int_bits;
45634893
4564 const ov_bool = switch (info.signedness) {4894 const ov_bool = switch (info.signedness) {
4565 .unsigned => blk: {4895 .unsigned => blk: {
4566 const zero_id = try cg.constInt(.u32, @as(u32, 0));4896 const zero_id = try cg.constInt(.u32, @as(u32, 0));
4567 var any_nonzero = cg.module.allocId();4897 var any_nonzero = cg.allocId();
4568 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4898 try cg.body.emit(gpa, .OpINotEqual, .{
4569 cg.body.writeOperand(Id, bool_ty_id);4899 .id_result_type = bool_ty_id,
4570 cg.body.writeOperand(Id, any_nonzero);4900 .id_result = any_nonzero,
4571 cg.body.writeOperand(Id, high_limbs[0]);4901 .operand_1 = high_limbs[0],
4572 cg.body.writeOperand(Id, zero_id);4902 .operand_2 = zero_id,
4903 });
45734904
4574 for (1..n) |i| {4905 for (1..n) |i| {
4575 const limb_nz = cg.module.allocId();4906 const limb_nz = cg.allocId();
4576 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4907 try cg.body.emit(gpa, .OpINotEqual, .{
4577 cg.body.writeOperand(Id, bool_ty_id);4908 .id_result_type = bool_ty_id,
4578 cg.body.writeOperand(Id, limb_nz);4909 .id_result = limb_nz,
4579 cg.body.writeOperand(Id, high_limbs[i]);4910 .operand_1 = high_limbs[i],
4580 cg.body.writeOperand(Id, zero_id);4911 .operand_2 = zero_id,
45814912 });
4582 const combined = cg.module.allocId();4913
4583 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);4914 const combined = cg.allocId();
4584 cg.body.writeOperand(Id, bool_ty_id);4915 try cg.body.emit(gpa, .OpLogicalOr, .{
4585 cg.body.writeOperand(Id, combined);4916 .id_result_type = bool_ty_id,
4586 cg.body.writeOperand(Id, any_nonzero);4917 .id_result = combined,
4587 cg.body.writeOperand(Id, limb_nz);4918 .operand_1 = any_nonzero,
4919 .operand_2 = limb_nz,
4920 });
4588 any_nonzero = combined;4921 any_nonzero = combined;
4589 }4922 }
45904923
...@@ -4595,92 +4928,99 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4595,92 +4928,99 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4595 const top_limb = ci_res.limbs[n - 1];4928 const top_limb = ci_res.limbs[n - 1];
4596 const i32_ty_id = try cg.resolveType(.i32, .direct);4929 const i32_ty_id = try cg.resolveType(.i32, .direct);
45974930
4598 const top_bits: u16 = if (info.bits % Module.big_int_bits == 0)4931 const top_bits: u16 = if (info.bits % big_int_bits == 0)
4599 Module.big_int_bits4932 big_int_bits
4600 else4933 else
4601 info.bits % Module.big_int_bits;4934 info.bits % big_int_bits;
46024935
4603 const shift_amt: u32 = top_bits - 1;4936 const shift_amt: u32 = top_bits - 1;
4604 const shift_id = try cg.constInt(.u32, shift_amt);4937 const shift_id = try cg.constInt(.u32, shift_amt);
46054938
4606 const as_signed = cg.module.allocId();4939 const as_signed = cg.allocId();
4607 try cg.body.emit(gpa, .OpBitcast, .{4940 try cg.body.emit(gpa, .OpBitcast, .{
4608 .id_result_type = i32_ty_id,4941 .id_result_type = i32_ty_id,
4609 .id_result = as_signed,4942 .id_result = as_signed,
4610 .operand = top_limb,4943 .operand = top_limb,
4611 });4944 });
4612 const sign_ext = cg.module.allocId();4945 const sign_ext = cg.allocId();
4613 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);4946 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4614 cg.body.writeOperand(Id, i32_ty_id);4947 .id_result_type = i32_ty_id,
4615 cg.body.writeOperand(Id, sign_ext);4948 .id_result = sign_ext,
4616 cg.body.writeOperand(Id, as_signed);4949 .base = as_signed,
4617 cg.body.writeOperand(Id, shift_id);4950 .shift = shift_id,
4618 const expected = cg.module.allocId();4951 });
4952 const expected = cg.allocId();
4619 try cg.body.emit(gpa, .OpBitcast, .{4953 try cg.body.emit(gpa, .OpBitcast, .{
4620 .id_result_type = u32_ty_id,4954 .id_result_type = u32_ty_id,
4621 .id_result = expected,4955 .id_result = expected,
4622 .operand = sign_ext,4956 .operand = sign_ext,
4623 });4957 });
46244958
4625 var any_mismatch = cg.module.allocId();4959 var any_mismatch = cg.allocId();
4626 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4960 try cg.body.emit(gpa, .OpINotEqual, .{
4627 cg.body.writeOperand(Id, bool_ty_id);4961 .id_result_type = bool_ty_id,
4628 cg.body.writeOperand(Id, any_mismatch);4962 .id_result = any_mismatch,
4629 cg.body.writeOperand(Id, high_limbs[0]);4963 .operand_1 = high_limbs[0],
4630 cg.body.writeOperand(Id, expected);4964 .operand_2 = expected,
4965 });
46314966
4632 for (1..n) |i| {4967 for (1..n) |i| {
4633 const limb_ne = cg.module.allocId();4968 const limb_ne = cg.allocId();
4634 try cg.body.emitRaw(gpa, .OpINotEqual, 4);4969 try cg.body.emit(gpa, .OpINotEqual, .{
4635 cg.body.writeOperand(Id, bool_ty_id);4970 .id_result_type = bool_ty_id,
4636 cg.body.writeOperand(Id, limb_ne);4971 .id_result = limb_ne,
4637 cg.body.writeOperand(Id, high_limbs[i]);4972 .operand_1 = high_limbs[i],
4638 cg.body.writeOperand(Id, expected);4973 .operand_2 = expected,
46394974 });
4640 const combined = cg.module.allocId();4975
4641 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);4976 const combined = cg.allocId();
4642 cg.body.writeOperand(Id, bool_ty_id);4977 try cg.body.emit(gpa, .OpLogicalOr, .{
4643 cg.body.writeOperand(Id, combined);4978 .id_result_type = bool_ty_id,
4644 cg.body.writeOperand(Id, any_mismatch);4979 .id_result = combined,
4645 cg.body.writeOperand(Id, limb_ne);4980 .operand_1 = any_mismatch,
4981 .operand_2 = limb_ne,
4982 });
4646 any_mismatch = combined;4983 any_mismatch = combined;
4647 }4984 }
46484985
4649 if (info.bits != info.backing_bits) {4986 if (info.bits != info.backing_bits) {
4650 const top_bits_s: u16 = info.bits % Module.big_int_bits;4987 const top_bits_s: u16 = info.bits % big_int_bits;
4651 const s_shift_id = try cg.constInt(.u32, top_bits_s - 1);4988 const s_shift_id = try cg.constInt(.u32, top_bits_s - 1);
46524989
4653 const top_as_signed = cg.module.allocId();4990 const top_as_signed = cg.allocId();
4654 try cg.body.emit(gpa, .OpBitcast, .{4991 try cg.body.emit(gpa, .OpBitcast, .{
4655 .id_result_type = i32_ty_id,4992 .id_result_type = i32_ty_id,
4656 .id_result = top_as_signed,4993 .id_result = top_as_signed,
4657 .operand = top_limb,4994 .operand = top_limb,
4658 });4995 });
4659 const top_sign_ext = cg.module.allocId();4996 const top_sign_ext = cg.allocId();
4660 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);4997 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4661 cg.body.writeOperand(Id, i32_ty_id);4998 .id_result_type = i32_ty_id,
4662 cg.body.writeOperand(Id, top_sign_ext);4999 .id_result = top_sign_ext,
4663 cg.body.writeOperand(Id, top_as_signed);5000 .base = top_as_signed,
4664 cg.body.writeOperand(Id, s_shift_id);5001 .shift = s_shift_id,
4665 const top_expected = cg.module.allocId();5002 });
5003 const top_expected = cg.allocId();
4666 try cg.body.emit(gpa, .OpBitcast, .{5004 try cg.body.emit(gpa, .OpBitcast, .{
4667 .id_result_type = u32_ty_id,5005 .id_result_type = u32_ty_id,
4668 .id_result = top_expected,5006 .id_result = top_expected,
4669 .operand = top_sign_ext,5007 .operand = top_sign_ext,
4670 });5008 });
4671 const top_mismatch = cg.module.allocId();5009 const top_mismatch = cg.allocId();
4672 try cg.body.emitRaw(gpa, .OpINotEqual, 4);5010 try cg.body.emit(gpa, .OpINotEqual, .{
4673 cg.body.writeOperand(Id, bool_ty_id);5011 .id_result_type = bool_ty_id,
4674 cg.body.writeOperand(Id, top_mismatch);5012 .id_result = top_mismatch,
4675 cg.body.writeOperand(Id, top_limb);5013 .operand_1 = top_limb,
4676 cg.body.writeOperand(Id, top_expected);5014 .operand_2 = top_expected,
46775015 });
4678 const combined = cg.module.allocId();5016
4679 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);5017 const combined = cg.allocId();
4680 cg.body.writeOperand(Id, bool_ty_id);5018 try cg.body.emit(gpa, .OpLogicalOr, .{
4681 cg.body.writeOperand(Id, combined);5019 .id_result_type = bool_ty_id,
4682 cg.body.writeOperand(Id, any_mismatch);5020 .id_result = combined,
4683 cg.body.writeOperand(Id, top_mismatch);5021 .operand_1 = any_mismatch,
5022 .operand_2 = top_mismatch,
5023 });
4684 any_mismatch = combined;5024 any_mismatch = combined;
4685 }5025 }
46865026
...@@ -4702,7 +5042,8 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4702,7 +5042,8 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4702 // - Additionally, if info.bits != 32, we'll have to check the high bits5042 // - Additionally, if info.bits != 32, we'll have to check the high bits
4703 // of the result too.5043 // of the result too.
47045044
4705 const largest_int_bits = cg.largestSupportedIntBits();5045 const target = cg.zcu.getTarget();
5046 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. If5047 // If non-null, the number of bits that the multiplication should be performed in. If
4707 // null, we have to use wide multiplication.5048 // null, we have to use wide multiplication.
4708 const maybe_op_ty_bits: ?u16 = switch (info.bits) {5049 const maybe_op_ty_bits: ?u16 = switch (info.bits) {
...@@ -4846,7 +5187,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4846,7 +5187,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4846}5187}
48475188
4848fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5189fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4849 const zcu = cg.module.zcu;5190 const zcu = cg.zcu;
48505191
4851 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5192 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4852 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;5193 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
...@@ -4898,14 +5239,48 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4898,14 +5239,48 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4898 const info = cg.arithmeticTypeInfo(result_ty);5239 const info = cg.arithmeticTypeInfo(result_ty);
4899 assert(info.class == .float); // .mul_add is only emitted for floats5240 assert(info.class == .float); // .mul_add is only emitted for floats
49005241
4901 const result = try cg.buildFma(a, b, c);5242 const zcu = cg.zcu;
5243 const target = zcu.getTarget();
5244
5245 const v = cg.vectorization(.{ a, b, c });
5246 const ops = v.components();
5247 const results = cg.allocIds(ops);
5248
5249 const op_result_ty = a.ty.scalarType(zcu);
5250 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
5251 const result_temp_ty = try v.resultType(cg, a.ty);
5252
5253 const op_a = try v.prepare(cg, a);
5254 const op_b = try v.prepare(cg, b);
5255 const op_c = try v.prepare(cg, c);
5256
5257 const set = try cg.importExtendedSet();
5258 const opcode: u32 = switch (target.os.tag) {
5259 .opencl => @intFromEnum(spec.OpenClOpcode.fma),
5260 // NOTE: Vulkan's FMA does not meet Zig's nor OpenCL's precision guarantees and needs
5261 // to be emulated.
5262 .vulkan, .opengl => @intFromEnum(spec.GlslOpcode.Fma),
5263 else => unreachable,
5264 };
5265
5266 for (0..ops) |i| {
5267 try cg.body.emit(cg.gpa, .OpExtInst, .{
5268 .id_result_type = op_result_ty_id,
5269 .id_result = results.at(i),
5270 .set = set,
5271 .instruction = .{ .inst = opcode },
5272 .id_ref_4 = &.{ op_a.at(i), op_b.at(i), op_c.at(i) },
5273 });
5274 }
5275
5276 const result = v.finalize(result_temp_ty, results);
4902 return try result.materialize(cg);5277 return try result.materialize(cg);
4903}5278}
49045279
4905fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {5280fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {
4906 if (cg.liveness.isUnused(inst)) return null;5281 if (cg.liveness.isUnused(inst)) return null;
49075282
4908 const zcu = cg.module.zcu;5283 const zcu = cg.zcu;
4909 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5284 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4910 const operand = try cg.temporary(ty_op.operand);5285 const operand = try cg.temporary(ty_op.operand);
49115286
...@@ -4948,7 +5323,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4948,7 +5323,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4948}5323}
49495324
4950fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5325fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4951 const zcu = cg.module.zcu;5326 const zcu = cg.zcu;
4952 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;5327 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
4953 const operand = try cg.resolve(reduce.operand);5328 const operand = try cg.resolve(reduce.operand);
4954 const operand_ty = cg.typeOf(reduce.operand);5329 const operand_ty = cg.typeOf(reduce.operand);
...@@ -5016,7 +5391,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5016,7 +5391,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5016}5391}
50175392
5018fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5393fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5019 const zcu = cg.module.zcu;5394 const zcu = cg.zcu;
5020 const gpa = zcu.gpa;5395 const gpa = zcu.gpa;
50215396
5022 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);5397 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);
...@@ -5041,7 +5416,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5041,7 +5416,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5041}5416}
50425417
5043fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5418fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5044 const zcu = cg.module.zcu;5419 const zcu = cg.zcu;
5045 const gpa = zcu.gpa;5420 const gpa = zcu.gpa;
50465421
5047 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);5422 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);
...@@ -5060,7 +5435,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5060,7 +5435,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5060 id.* = switch (mask_elem.unwrap()) {5435 id.* = switch (mask_elem.unwrap()) {
5061 .a_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_a, idx),5436 .a_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_a, idx),
5062 .b_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_b, idx),5437 .b_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_b, idx),
5063 .undef => try cg.module.constUndef(elem_ty_id),5438 .undef => try cg.constUndef(elem_ty_id),
5064 };5439 };
5065 }5440 }
50665441
...@@ -5074,8 +5449,8 @@ fn accessChainId(...@@ -5074,8 +5449,8 @@ fn accessChainId(
5074 base: Id,5449 base: Id,
5075 indices: []const Id,5450 indices: []const Id,
5076) !Id {5451) !Id {
5077 const result_id = cg.module.allocId();5452 const result_id = cg.allocId();
5078 try cg.body.emit(cg.module.gpa, .OpInBoundsAccessChain, .{5453 try cg.body.emit(cg.gpa, .OpInBoundsAccessChain, .{
5079 .id_result_type = result_ty_id,5454 .id_result_type = result_ty_id,
5080 .id_result = result_id,5455 .id_result = result_id,
5081 .base = base,5456 .base = base,
...@@ -5094,7 +5469,7 @@ fn accessChain(...@@ -5094,7 +5469,7 @@ fn accessChain(
5094 base: Id,5469 base: Id,
5095 indices: []const u32,5470 indices: []const u32,
5096) !Id {5471) !Id {
5097 const gpa = cg.module.gpa;5472 const gpa = cg.gpa;
5098 const scratch_top = cg.id_scratch.items.len;5473 const scratch_top = cg.id_scratch.items.len;
5099 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);5474 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
5100 const ids = try cg.id_scratch.addManyAsSlice(gpa, indices.len);5475 const ids = try cg.id_scratch.addManyAsSlice(gpa, indices.len);
...@@ -5111,8 +5486,8 @@ fn ptrAccessChain(...@@ -5111,8 +5486,8 @@ fn ptrAccessChain(
5111 element: Id,5486 element: Id,
5112 indices: []const u32,5487 indices: []const u32,
5113) !Id {5488) !Id {
5114 const gpa = cg.module.gpa;5489 const gpa = cg.gpa;
5115 const target = cg.module.zcu.getTarget();5490 const target = cg.zcu.getTarget();
51165491
5117 const scratch_top = cg.id_scratch.items.len;5492 const scratch_top = cg.id_scratch.items.len;
5118 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);5493 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
...@@ -5121,7 +5496,7 @@ fn ptrAccessChain(...@@ -5121,7 +5496,7 @@ fn ptrAccessChain(
5121 id.* = try cg.constInt(.u32, index);5496 id.* = try cg.constInt(.u32, index);
5122 }5497 }
51235498
5124 const result_id = cg.module.allocId();5499 const result_id = cg.allocId();
5125 switch (target.os.tag) {5500 switch (target.os.tag) {
5126 .opencl, .amdhsa => {5501 .opencl, .amdhsa => {
5127 try cg.body.emit(gpa, .OpInBoundsPtrAccessChain, .{5502 try cg.body.emit(gpa, .OpInBoundsPtrAccessChain, .{
...@@ -5147,7 +5522,7 @@ fn ptrAccessChain(...@@ -5147,7 +5522,7 @@ fn ptrAccessChain(
5147}5522}
51485523
5149fn ptrAdd(cg: *CodeGen, result_ty: Type, ptr_ty: Type, ptr_id: Id, offset_id: Id) !Id {5524fn ptrAdd(cg: *CodeGen, result_ty: Type, ptr_ty: Type, ptr_id: Id, offset_id: Id) !Id {
5150 const zcu = cg.module.zcu;5525 const zcu = cg.zcu;
5151 const result_ty_id = try cg.resolveType(result_ty, .direct);5526 const result_ty_id = try cg.resolveType(result_ty, .direct);
51525527
5153 switch (ptr_ty.ptrSize(zcu)) {5528 switch (ptr_ty.ptrSize(zcu)) {
...@@ -5188,8 +5563,8 @@ fn airPtrSub(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5188,8 +5563,8 @@ fn airPtrSub(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5188 const offset_ty_id = try cg.resolveType(offset_ty, .direct);5563 const offset_ty_id = try cg.resolveType(offset_ty, .direct);
5189 const result_ty = cg.typeOfIndex(inst);5564 const result_ty = cg.typeOfIndex(inst);
51905565
5191 const negative_offset_id = cg.module.allocId();5566 const negative_offset_id = cg.allocId();
5192 try cg.body.emit(cg.module.gpa, .OpSNegate, .{5567 try cg.body.emit(cg.gpa, .OpSNegate, .{
5193 .id_result_type = offset_ty_id,5568 .id_result_type = offset_ty_id,
5194 .id_result = negative_offset_id,5569 .id_result = negative_offset_id,
5195 .operand = offset_id,5570 .operand = offset_id,
...@@ -5203,9 +5578,9 @@ fn cmp(...@@ -5203,9 +5578,9 @@ fn cmp(
5203 lhs: Temporary,5578 lhs: Temporary,
5204 rhs: Temporary,5579 rhs: Temporary,
5205) !Temporary {5580) !Temporary {
5206 const gpa = cg.module.gpa;5581 const gpa = cg.gpa;
5207 const pt = cg.pt;5582 const pt = cg.pt;
5208 const zcu = cg.module.zcu;5583 const zcu = cg.zcu;
5209 const scalar_ty = lhs.ty.scalarType(zcu);5584 const scalar_ty = lhs.ty.scalarType(zcu);
5210 const is_vector = lhs.ty.isVector(zcu);5585 const is_vector = lhs.ty.isVector(zcu);
52115586
...@@ -5234,14 +5609,14 @@ fn cmp(...@@ -5234,14 +5609,14 @@ fn cmp(
52345609
5235 const usize_ty_id = try cg.resolveType(.usize, .direct);5610 const usize_ty_id = try cg.resolveType(.usize, .direct);
52365611
5237 const lhs_int_id = cg.module.allocId();5612 const lhs_int_id = cg.allocId();
5238 try cg.body.emit(gpa, .OpConvertPtrToU, .{5613 try cg.body.emit(gpa, .OpConvertPtrToU, .{
5239 .id_result_type = usize_ty_id,5614 .id_result_type = usize_ty_id,
5240 .id_result = lhs_int_id,5615 .id_result = lhs_int_id,
5241 .pointer = try lhs.materialize(cg),5616 .pointer = try lhs.materialize(cg),
5242 });5617 });
52435618
5244 const rhs_int_id = cg.module.allocId();5619 const rhs_int_id = cg.allocId();
5245 try cg.body.emit(gpa, .OpConvertPtrToU, .{5620 try cg.body.emit(gpa, .OpConvertPtrToU, .{
5246 .id_result_type = usize_ty_id,5621 .id_result_type = usize_ty_id,
5247 .id_result = rhs_int_id,5622 .id_result = rhs_int_id,
...@@ -5410,14 +5785,29 @@ fn bitCast(...@@ -5410,14 +5785,29 @@ fn bitCast(
5410 src_ty: Type,5785 src_ty: Type,
5411 src_id: Id,5786 src_id: Id,
5412) !Id {5787) !Id {
5413 const gpa = cg.module.gpa;5788 const gpa = cg.gpa;
5414 const zcu = cg.module.zcu;5789 const zcu = cg.zcu;
5415 const target = zcu.getTarget();5790 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);
54185791
5792 if (src_ty.toIntern() == dst_ty.toIntern()) return src_id;
5793 if (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu)) switch (target.os.tag) {
5794 .vulkan, .opengl => if (src_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) return src_id,
5795 else => {},
5796 };
5797
5798 const dst_ty_id = try cg.resolveType(dst_ty, .direct);
5419 const result_id = blk: {5799 const result_id = blk: {
5420 if (src_ty_id == dst_ty_id) break :blk src_id;5800 // Big-int ↔ big-int bitcast: the indirect representation is an array,
5801 // which OpBitcast cannot operate on. The arrays are bitwise identical
5802 // apart from the top limb's padding; the normalize pass below fixes
5803 // the padding.
5804 if (src_ty.isInt(zcu) and dst_ty.isInt(zcu)) {
5805 const src_info = src_ty.intInfo(zcu);
5806 const dst_info = dst_ty.intInfo(zcu);
5807 const src_backing, const src_big = cg.backingIntBits(src_info.bits);
5808 const dst_backing, const dst_big = cg.backingIntBits(dst_info.bits);
5809 if (src_backing == dst_backing and src_big and dst_big) break :blk src_id;
5810 }
54215811
5422 // TODO: Some more cases are missing here5812 // TODO: Some more cases are missing here
5423 // See fn bitCast in llvm.zig5813 // See fn bitCast in llvm.zig
...@@ -5432,7 +5822,7 @@ fn bitCast(...@@ -5432,7 +5822,7 @@ fn bitCast(
5432 }5822 }
5433 }5823 }
54345824
5435 const result_id = cg.module.allocId();5825 const result_id = cg.allocId();
5436 try cg.body.emit(gpa, .OpConvertUToPtr, .{5826 try cg.body.emit(gpa, .OpConvertUToPtr, .{
5437 .id_result_type = dst_ty_id,5827 .id_result_type = dst_ty_id,
5438 .id_result = result_id,5828 .id_result = result_id,
...@@ -5446,7 +5836,7 @@ fn bitCast(...@@ -5446,7 +5836,7 @@ fn bitCast(
5446 // otherwise use a temporary and perform a pointer cast.5836 // 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));5837 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) {5838 if (can_bitcast) {
5449 const result_id = cg.module.allocId();5839 const result_id = cg.allocId();
5450 try cg.body.emit(gpa, .OpBitcast, .{5840 try cg.body.emit(gpa, .OpBitcast, .{
5451 .id_result_type = dst_ty_id,5841 .id_result_type = dst_ty_id,
5452 .id_result = result_id,5842 .id_result = result_id,
...@@ -5456,12 +5846,24 @@ fn bitCast(...@@ -5456,12 +5846,24 @@ fn bitCast(
5456 break :blk result_id;5846 break :blk result_id;
5457 }5847 }
54585848
5459 const dst_ptr_ty_id = try cg.module.ptrType(dst_ty_id, .function);5849 switch (target.os.tag) {
5850 .vulkan, .opengl => {
5851 // Logical addressing forbids OpBitcast on pointers. Allocate
5852 // the temp with dst_ty so the load reads through a slot of the right type.
5853 const dst_ty_indirect_id = try cg.resolveType(dst_ty, .indirect);
5854 const tmp_id = try cg.alloc(dst_ty_indirect_id, null);
5855 try cg.store(dst_ty, tmp_id, src_id, .{});
5856 break :blk try cg.load(dst_ty, tmp_id, .{});
5857 },
5858 else => {},
5859 }
5860
5861 const dst_ptr_ty_id = try cg.ptrType(dst_ty_id, .function);
54605862
5461 const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect);5863 const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect);
5462 const tmp_id = try cg.alloc(src_ty_indirect_id, null);5864 const tmp_id = try cg.alloc(src_ty_indirect_id, null);
5463 try cg.store(src_ty, tmp_id, src_id, .{});5865 try cg.store(src_ty, tmp_id, src_id, .{});
5464 const casted_ptr_id = cg.module.allocId();5866 const casted_ptr_id = cg.allocId();
5465 try cg.body.emit(gpa, .OpBitcast, .{5867 try cg.body.emit(gpa, .OpBitcast, .{
5466 .id_result_type = dst_ptr_ty_id,5868 .id_result_type = dst_ptr_ty_id,
5467 .id_result = casted_ptr_id,5869 .id_result = casted_ptr_id,
...@@ -5492,8 +5894,13 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5492,8 +5894,13 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5492 const result = try cg.intFromBool(operand, .u1);5894 const result = try cg.intFromBool(operand, .u1);
5493 return try result.materialize(cg);5895 return try result.materialize(cg);
5494 }5896 }
5897 if (operand_ty.zigTypeTag(cg.zcu) == .pointer) {
5898 switch (try cg.resolvePtr(ty_op.operand)) {
5899 .tracked => |t| return t.id, // TODO
5900 .id => |operand_id| return try cg.bitCast(result_ty, operand_ty, operand_id),
5901 }
5902 }
5495 const operand_id = try cg.resolve(ty_op.operand);5903 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);5904 return try cg.bitCast(result_ty, operand_ty, operand_id);
5498}5905}
54995906
...@@ -5509,19 +5916,19 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5509,19 +5916,19 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5509 const dst_composite = dst_info.class == .composite_integer;5916 const dst_composite = dst_info.class == .composite_integer;
55105917
5511 if (src_composite or dst_composite) {5918 if (src_composite or dst_composite) {
5512 const gpa = cg.module.gpa;5919 const gpa = cg.gpa;
5513 const scratch_top = cg.id_scratch.items.len;5920 const scratch_top = cg.id_scratch.items.len;
5514 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);5921 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
55155922
5516 if (src_composite and dst_composite) {5923 if (src_composite and dst_composite) {
5517 const src_id = try src.materialize(cg);5924 const src_id = try src.materialize(cg);
5518 const src_n: u16 = src_info.backing_bits / Module.big_int_bits;5925 const src_n: u16 = src_info.backing_bits / big_int_bits;
5519 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;5926 const dst_n: u16 = dst_info.backing_bits / big_int_bits;
5520 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);5927 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
5521 const min_n = @min(src_n, dst_n);5928 const min_n = @min(src_n, dst_n);
5522 const u32_ty_id = try cg.resolveType(.u32, .direct);5929 const u32_ty_id = try cg.resolveType(.u32, .direct);
5523 for (0..min_n) |i| {5930 for (0..min_n) |i| {
5524 result_limbs[i] = cg.module.allocId();5931 result_limbs[i] = cg.allocId();
5525 try cg.body.emit(gpa, .OpCompositeExtract, .{5932 try cg.body.emit(gpa, .OpCompositeExtract, .{
5526 .id_result_type = u32_ty_id,5933 .id_result_type = u32_ty_id,
5527 .id_result = result_limbs[i],5934 .id_result = result_limbs[i],
...@@ -5533,20 +5940,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5533,20 +5940,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5533 const fill = if (src_info.signedness == .signed) blk: {5940 const fill = if (src_info.signedness == .signed) blk: {
5534 const i32_ty_id = try cg.resolveType(.i32, .direct);5941 const i32_ty_id = try cg.resolveType(.i32, .direct);
5535 const msb = result_limbs[src_n - 1];5942 const msb = result_limbs[src_n - 1];
5536 const msb_signed = cg.module.allocId();5943 const msb_signed = cg.allocId();
5537 try cg.body.emit(gpa, .OpBitcast, .{5944 try cg.body.emit(gpa, .OpBitcast, .{
5538 .id_result_type = i32_ty_id,5945 .id_result_type = i32_ty_id,
5539 .id_result = msb_signed,5946 .id_result = msb_signed,
5540 .operand = msb,5947 .operand = msb,
5541 });5948 });
5542 const shift31 = try cg.constInt(.i32, @as(i32, 31));5949 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5543 const sign_ext = cg.module.allocId();5950 const sign_ext = cg.allocId();
5544 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);5951 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5545 cg.body.writeOperand(Id, i32_ty_id);5952 .id_result_type = i32_ty_id,
5546 cg.body.writeOperand(Id, sign_ext);5953 .id_result = sign_ext,
5547 cg.body.writeOperand(Id, msb_signed);5954 .base = msb_signed,
5548 cg.body.writeOperand(Id, shift31);5955 .shift = shift31,
5549 const back = cg.module.allocId();5956 });
5957 const back = cg.allocId();
5550 try cg.body.emit(gpa, .OpBitcast, .{5958 try cg.body.emit(gpa, .OpBitcast, .{
5551 .id_result_type = u32_ty_id,5959 .id_result_type = u32_ty_id,
5552 .id_result = back,5960 .id_result = back,
...@@ -5565,7 +5973,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5565,7 +5973,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5565 const src_id = try src.materialize(cg);5973 const src_id = try src.materialize(cg);
5566 const u32_ty_id = try cg.resolveType(.u32, .direct);5974 const u32_ty_id = try cg.resolveType(.u32, .direct);
5567 if (dst_info.backing_bits <= 32) {5975 if (dst_info.backing_bits <= 32) {
5568 const limb0 = cg.module.allocId();5976 const limb0 = cg.allocId();
5569 try cg.body.emit(gpa, .OpCompositeExtract, .{5977 try cg.body.emit(gpa, .OpCompositeExtract, .{
5570 .id_result_type = u32_ty_id,5978 .id_result_type = u32_ty_id,
5571 .id_result = limb0,5979 .id_result = limb0,
...@@ -5580,14 +5988,14 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5580,14 +5988,14 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5580 converted;5988 converted;
5581 return try result.materialize(cg);5989 return try result.materialize(cg);
5582 } else {5990 } else {
5583 const limb0 = cg.module.allocId();5991 const limb0 = cg.allocId();
5584 try cg.body.emit(gpa, .OpCompositeExtract, .{5992 try cg.body.emit(gpa, .OpCompositeExtract, .{
5585 .id_result_type = u32_ty_id,5993 .id_result_type = u32_ty_id,
5586 .id_result = limb0,5994 .id_result = limb0,
5587 .composite = src_id,5995 .composite = src_id,
5588 .indexes = &.{@as(u32, 0)},5996 .indexes = &.{@as(u32, 0)},
5589 });5997 });
5590 const limb1 = cg.module.allocId();5998 const limb1 = cg.allocId();
5591 try cg.body.emit(gpa, .OpCompositeExtract, .{5999 try cg.body.emit(gpa, .OpCompositeExtract, .{
5592 .id_result_type = u32_ty_id,6000 .id_result_type = u32_ty_id,
5593 .id_result = limb1,6001 .id_result = limb1,
...@@ -5595,29 +6003,33 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5595,29 +6003,33 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5595 .indexes = &.{@as(u32, 1)},6003 .indexes = &.{@as(u32, 1)},
5596 });6004 });
5597 const u64_ty_id = try cg.resolveType(.u64, .direct);6005 const u64_ty_id = try cg.resolveType(.u64, .direct);
5598 const lo = cg.module.allocId();6006 const lo = cg.allocId();
5599 try cg.body.emitRaw(gpa, .OpUConvert, 3);6007 try cg.body.emit(gpa, .OpUConvert, .{
5600 cg.body.writeOperand(Id, u64_ty_id);6008 .id_result_type = u64_ty_id,
5601 cg.body.writeOperand(Id, lo);6009 .id_result = lo,
5602 cg.body.writeOperand(Id, limb0);6010 .unsigned_value = limb0,
5603 const hi = cg.module.allocId();6011 });
5604 try cg.body.emitRaw(gpa, .OpUConvert, 3);6012 const hi = cg.allocId();
5605 cg.body.writeOperand(Id, u64_ty_id);6013 try cg.body.emit(gpa, .OpUConvert, .{
5606 cg.body.writeOperand(Id, hi);6014 .id_result_type = u64_ty_id,
5607 cg.body.writeOperand(Id, limb1);6015 .id_result = hi,
6016 .unsigned_value = limb1,
6017 });
5608 const shift32 = try cg.constInt(.u64, @as(u64, 32));6018 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5609 const hi_shifted = cg.module.allocId();6019 const hi_shifted = cg.allocId();
5610 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);6020 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
5611 cg.body.writeOperand(Id, u64_ty_id);6021 .id_result_type = u64_ty_id,
5612 cg.body.writeOperand(Id, hi_shifted);6022 .id_result = hi_shifted,
5613 cg.body.writeOperand(Id, hi);6023 .base = hi,
5614 cg.body.writeOperand(Id, shift32);6024 .shift = shift32,
5615 const combined = cg.module.allocId();6025 });
5616 try cg.body.emitRaw(gpa, .OpBitwiseOr, 4);6026 const combined = cg.allocId();
5617 cg.body.writeOperand(Id, u64_ty_id);6027 try cg.body.emit(gpa, .OpBitwiseOr, .{
5618 cg.body.writeOperand(Id, combined);6028 .id_result_type = u64_ty_id,
5619 cg.body.writeOperand(Id, lo);6029 .id_result = combined,
5620 cg.body.writeOperand(Id, hi_shifted);6030 .operand_1 = lo,
6031 .operand_2 = hi_shifted,
6032 });
5621 const tmp: Temporary = .init(.u64, combined);6033 const tmp: Temporary = .init(.u64, combined);
5622 const converted = try cg.buildConvert(dst_ty, tmp);6034 const converted = try cg.buildConvert(dst_ty, tmp);
5623 const result = if (dst_info.bits < src_info.bits)6035 const result = if (dst_info.bits < src_info.bits)
...@@ -5627,7 +6039,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5627,7 +6039,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5627 return try result.materialize(cg);6039 return try result.materialize(cg);
5628 }6040 }
5629 } else {6041 } else {
5630 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;6042 const dst_n: u16 = dst_info.backing_bits / big_int_bits;
5631 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);6043 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
5632 const u32_ty_id = try cg.resolveType(.u32, .direct);6044 const u32_ty_id = try cg.resolveType(.u32, .direct);
56336045
...@@ -5637,44 +6049,48 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5637,44 +6049,48 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5637 } else {6049 } else {
5638 const src_as_u64 = try cg.buildConvert(.u64, src);6050 const src_as_u64 = try cg.buildConvert(.u64, src);
5639 const src_id = try src_as_u64.materialize(cg);6051 const src_id = try src_as_u64.materialize(cg);
5640 result_limbs[0] = cg.module.allocId();6052 result_limbs[0] = cg.allocId();
5641 try cg.body.emitRaw(gpa, .OpUConvert, 3);6053 try cg.body.emit(gpa, .OpUConvert, .{
5642 cg.body.writeOperand(Id, u32_ty_id);6054 .id_result_type = u32_ty_id,
5643 cg.body.writeOperand(Id, result_limbs[0]);6055 .id_result = result_limbs[0],
5644 cg.body.writeOperand(Id, src_id);6056 .unsigned_value = src_id,
6057 });
5645 const u64_ty_id = try cg.resolveType(.u64, .direct);6058 const u64_ty_id = try cg.resolveType(.u64, .direct);
5646 const shift32 = try cg.constInt(.u64, @as(u64, 32));6059 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5647 const hi = cg.module.allocId();6060 const hi = cg.allocId();
5648 try cg.body.emitRaw(gpa, .OpShiftRightLogical, 4);6061 try cg.body.emit(gpa, .OpShiftRightLogical, .{
5649 cg.body.writeOperand(Id, u64_ty_id);6062 .id_result_type = u64_ty_id,
5650 cg.body.writeOperand(Id, hi);6063 .id_result = hi,
5651 cg.body.writeOperand(Id, src_id);6064 .base = src_id,
5652 cg.body.writeOperand(Id, shift32);6065 .shift = shift32,
5653 result_limbs[1] = cg.module.allocId();6066 });
5654 try cg.body.emitRaw(gpa, .OpUConvert, 3);6067 result_limbs[1] = cg.allocId();
5655 cg.body.writeOperand(Id, u32_ty_id);6068 try cg.body.emit(gpa, .OpUConvert, .{
5656 cg.body.writeOperand(Id, result_limbs[1]);6069 .id_result_type = u32_ty_id,
5657 cg.body.writeOperand(Id, hi);6070 .id_result = result_limbs[1],
6071 .unsigned_value = hi,
6072 });
5658 }6073 }
5659 // Sign/zero-extend remaining limbs.6074 // Sign/zero-extend remaining limbs.
5660 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;6075 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;
5661 const fill = if (src_info.signedness == .signed) blk: {6076 const fill = if (src_info.signedness == .signed) blk: {
5662 const i32_ty_id = try cg.resolveType(.i32, .direct);6077 const i32_ty_id = try cg.resolveType(.i32, .direct);
5663 const msb = result_limbs[fill_start - 1];6078 const msb = result_limbs[fill_start - 1];
5664 const msb_signed = cg.module.allocId();6079 const msb_signed = cg.allocId();
5665 try cg.body.emit(gpa, .OpBitcast, .{6080 try cg.body.emit(gpa, .OpBitcast, .{
5666 .id_result_type = i32_ty_id,6081 .id_result_type = i32_ty_id,
5667 .id_result = msb_signed,6082 .id_result = msb_signed,
5668 .operand = msb,6083 .operand = msb,
5669 });6084 });
5670 const shift31 = try cg.constInt(.i32, @as(i32, 31));6085 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5671 const sign_ext = cg.module.allocId();6086 const sign_ext = cg.allocId();
5672 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);6087 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5673 cg.body.writeOperand(Id, i32_ty_id);6088 .id_result_type = i32_ty_id,
5674 cg.body.writeOperand(Id, sign_ext);6089 .id_result = sign_ext,
5675 cg.body.writeOperand(Id, msb_signed);6090 .base = msb_signed,
5676 cg.body.writeOperand(Id, shift31);6091 .shift = shift31,
5677 const back = cg.module.allocId();6092 });
6093 const back = cg.allocId();
5678 try cg.body.emit(gpa, .OpBitcast, .{6094 try cg.body.emit(gpa, .OpBitcast, .{
5679 .id_result_type = u32_ty_id,6095 .id_result_type = u32_ty_id,
5680 .id_result = back,6096 .id_result = back,
...@@ -5715,8 +6131,8 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5715,8 +6131,8 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
57156131
5716fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {6132fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
5717 const result_type_id = try cg.resolveType(.usize, .direct);6133 const result_type_id = try cg.resolveType(.usize, .direct);
5718 const result_id = cg.module.allocId();6134 const result_id = cg.allocId();
5719 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{6135 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
5720 .id_result_type = result_type_id,6136 .id_result_type = result_type_id,
5721 .id_result = result_id,6137 .id_result = result_id,
5722 .pointer = operand_id,6138 .pointer = operand_id,
...@@ -5725,17 +6141,13 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {...@@ -5725,17 +6141,13 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
5725}6141}
57266142
5727fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6143fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6144 const gpa = cg.gpa;
5728 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6145 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5729 const operand_ty = cg.typeOf(ty_op.operand);6146 const operand_ty = cg.typeOf(ty_op.operand);
5730 const operand_id = try cg.resolve(ty_op.operand);6147 const operand_id = try cg.resolve(ty_op.operand);
5731 const result_ty = cg.typeOfIndex(inst);6148 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);6149 const operand_info = cg.arithmeticTypeInfo(operand_ty);
5738 const result_id = cg.module.allocId();6150 const result_id = cg.allocId();
5739 const result_ty_id = try cg.resolveType(result_ty, .direct);6151 const result_ty_id = try cg.resolveType(result_ty, .direct);
5740 switch (operand_info.signedness) {6152 switch (operand_info.signedness) {
5741 .signed => try cg.body.emit(gpa, .OpConvertSToF, .{6153 .signed => try cg.body.emit(gpa, .OpConvertSToF, .{
...@@ -5753,17 +6165,13 @@ fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id)...@@ -5753,17 +6165,13 @@ fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id)
5753}6165}
57546166
5755fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6167fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6168 const gpa = cg.gpa;
5756 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6169 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5757 const operand_id = try cg.resolve(ty_op.operand);6170 const operand_id = try cg.resolve(ty_op.operand);
5758 const result_ty = cg.typeOfIndex(inst);6171 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);6172 const result_info = cg.arithmeticTypeInfo(result_ty);
5765 const result_ty_id = try cg.resolveType(result_ty, .direct);6173 const result_ty_id = try cg.resolveType(result_ty, .direct);
5766 const result_id = cg.module.allocId();6174 const result_id = cg.allocId();
5767 switch (result_info.signedness) {6175 switch (result_info.signedness) {
5768 .signed => try cg.body.emit(gpa, .OpConvertFToS, .{6176 .signed => try cg.body.emit(gpa, .OpConvertFToS, .{
5769 .id_result_type = result_ty_id,6177 .id_result_type = result_ty_id,
...@@ -5815,7 +6223,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5815,7 +6223,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5815}6223}
58166224
5817fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6225fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5818 const zcu = cg.module.zcu;6226 const zcu = cg.zcu;
5819 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6227 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5820 const array_ptr_ty = cg.typeOf(ty_op.operand);6228 const array_ptr_ty = cg.typeOf(ty_op.operand);
5821 const array_ty = array_ptr_ty.childType(zcu);6229 const array_ty = array_ptr_ty.childType(zcu);
...@@ -5849,11 +6257,11 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5849,11 +6257,11 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5849}6257}
58506258
5851fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6259fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5852 const gpa = cg.module.gpa;6260 const gpa = cg.gpa;
5853 const pt = cg.pt;6261 const pt = cg.pt;
5854 const zcu = cg.module.zcu;6262 const zcu = cg.zcu;
5855 const ip = &zcu.intern_pool;6263 const ip = &zcu.intern_pool;
5856 const target = cg.module.zcu.getTarget();6264 const target = cg.zcu.getTarget();
5857 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6265 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5858 const result_ty = cg.typeOfIndex(inst);6266 const result_ty = cg.typeOfIndex(inst);
5859 const len: usize = @intCast(result_ty.arrayLen(zcu));6267 const len: usize = @intCast(result_ty.arrayLen(zcu));
...@@ -5978,23 +6386,8 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5978,23 +6386,8 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5978 }6386 }
5979}6387}
59806388
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 {6389fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
5997 const zcu = cg.module.zcu;6390 const zcu = cg.zcu;
5998 if (ty.isSlice(zcu)) {6391 if (ty.isSlice(zcu)) {
5999 const ptr_ty = ty.slicePtrFieldType(zcu);6392 const ptr_ty = ty.slicePtrFieldType(zcu);
6000 return cg.extractField(ptr_ty, operand_id, 0);6393 return cg.extractField(ptr_ty, operand_id, 0);
...@@ -6010,8 +6403,17 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6010,8 +6403,17 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) !void {
6010 const src_ty = cg.typeOf(bin_op.rhs);6403 const src_ty = cg.typeOf(bin_op.rhs);
6011 const dest_ptr = try cg.sliceOrArrayPtr(dest_slice, dest_ty);6404 const dest_ptr = try cg.sliceOrArrayPtr(dest_slice, dest_ty);
6012 const src_ptr = try cg.sliceOrArrayPtr(src_slice, src_ty);6405 const src_ptr = try cg.sliceOrArrayPtr(src_slice, src_ty);
6013 const len = try cg.sliceOrArrayLen(dest_slice, dest_ty);6406 const len = switch (dest_ty.ptrSize(cg.zcu)) {
6014 try cg.body.emit(cg.module.gpa, .OpCopyMemorySized, .{6407 .slice => try cg.extractField(.usize, dest_slice, 1),
6408 .one => len: {
6409 const array_ty = dest_ty.childType(cg.zcu);
6410 const elem_ty = array_ty.childType(cg.zcu);
6411 const size = array_ty.arrayLenIncludingSentinel(cg.zcu) * elem_ty.abiSize(cg.zcu);
6412 break :len try cg.constInt(.usize, size);
6413 },
6414 .many, .c => unreachable,
6415 };
6416 try cg.body.emit(cg.gpa, .OpCopyMemorySized, .{
6015 .target = dest_ptr,6417 .target = dest_ptr,
6016 .source = src_ptr,6418 .source = src_ptr,
6017 .size = len,6419 .size = len,
...@@ -6031,12 +6433,12 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {...@@ -6031,12 +6433,12 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {
6031}6433}
60326434
6033fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6435fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6034 const gpa = cg.module.gpa;6436 const gpa = cg.gpa;
6035 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6437 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6036 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;6438 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
6037 const struct_ptr_id = try cg.resolve(extra.struct_operand);6439 const struct_ptr_id = try cg.resolve(extra.struct_operand);
6038 const u32_ty_id = try cg.module.intType(.unsigned, 32);6440 const u32_ty_id = try cg.intType(.unsigned, 32);
6039 const result_id = cg.module.allocId();6441 const result_id = cg.allocId();
6040 try cg.body.emit(gpa, .OpArrayLength, .{6442 try cg.body.emit(gpa, .OpArrayLength, .{
6041 .id_result_type = u32_ty_id,6443 .id_result_type = u32_ty_id,
6042 .id_result = result_id,6444 .id_result = result_id,
...@@ -6047,7 +6449,7 @@ fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6047,7 +6449,7 @@ fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6047}6449}
60486450
6049fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6451fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6050 const zcu = cg.module.zcu;6452 const zcu = cg.zcu;
6051 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6453 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;6454 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
6053 const slice_ty = cg.typeOf(bin_op.lhs);6455 const slice_ty = cg.typeOf(bin_op.lhs);
...@@ -6064,7 +6466,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6064,7 +6466,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6064}6466}
60656467
6066fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6468fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6067 const zcu = cg.module.zcu;6469 const zcu = cg.zcu;
6068 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6470 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6069 const slice_ty = cg.typeOf(bin_op.lhs);6471 const slice_ty = cg.typeOf(bin_op.lhs);
6070 if (!slice_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;6472 if (!slice_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;
...@@ -6081,11 +6483,11 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6081,11 +6483,11 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6081}6483}
60826484
6083fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {6485fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
6084 const zcu = cg.module.zcu;6486 const zcu = cg.zcu;
6085 // Construct new pointer type for the resulting pointer6487 // Construct new pointer type for the resulting pointer
6086 const elem_ty = ptr_ty.indexableElem(zcu);6488 const elem_ty = ptr_ty.indexableElem(zcu);
6087 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);6489 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)));6490 const elem_ptr_ty_id = try cg.ptrType(elem_ty_id, cg.storageClass(ptr_ty.ptrAddressSpace(zcu)));
6089 if (ptr_ty.isSinglePointer(zcu)) {6491 if (ptr_ty.isSinglePointer(zcu)) {
6090 // Pointer-to-array. In this case, the resulting pointer is not of the same type6492 // 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.6493 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.
...@@ -6097,7 +6499,7 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {...@@ -6097,7 +6499,7 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
6097}6499}
60986500
6099fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6501fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6100 const zcu = cg.module.zcu;6502 const zcu = cg.zcu;
6101 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6503 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;6504 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
6103 const src_ptr_ty = cg.typeOf(bin_op.lhs);6505 const src_ptr_ty = cg.typeOf(bin_op.lhs);
...@@ -6111,8 +6513,8 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6111,8 +6513,8 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6111}6513}
61126514
6113fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6515fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6114 const gpa = cg.module.gpa;6516 const gpa = cg.gpa;
6115 const zcu = cg.module.zcu;6517 const zcu = cg.zcu;
6116 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6518 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6117 const array_ty = cg.typeOf(bin_op.lhs);6519 const array_ty = cg.typeOf(bin_op.lhs);
6118 const elem_ty = array_ty.childType(zcu);6520 const elem_ty = array_ty.childType(zcu);
...@@ -6127,10 +6529,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6127,10 +6529,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6127 const elem_repr: Repr = if (is_vector) .direct else .indirect;6529 const elem_repr: Repr = if (is_vector) .direct else .indirect;
6128 const array_ty_id = try cg.resolveType(array_ty, .direct);6530 const array_ty_id = try cg.resolveType(array_ty, .direct);
6129 const elem_ty_id = try cg.resolveType(elem_ty, elem_repr);6531 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);6532 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);6533 const ptr_elem_ty_id = try cg.ptrType(elem_ty_id, .function);
61326534
6133 const tmp_id = cg.module.allocId();6535 const tmp_id = cg.allocId();
6134 try cg.prologue.emit(gpa, .OpVariable, .{6536 try cg.prologue.emit(gpa, .OpVariable, .{
6135 .id_result_type = ptr_array_ty_id,6537 .id_result_type = ptr_array_ty_id,
6136 .id_result = tmp_id,6538 .id_result = tmp_id,
...@@ -6144,7 +6546,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6144,7 +6546,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61446546
6145 const elem_ptr_id = try cg.accessChainId(ptr_elem_ty_id, tmp_id, &.{index_id});6547 const elem_ptr_id = try cg.accessChainId(ptr_elem_ty_id, tmp_id, &.{index_id});
61466548
6147 const result_id = cg.module.allocId();6549 const result_id = cg.allocId();
6148 try cg.body.emit(gpa, .OpLoad, .{6550 try cg.body.emit(gpa, .OpLoad, .{
6149 .id_result_type = try cg.resolveType(elem_ty, elem_repr),6551 .id_result_type = try cg.resolveType(elem_ty, elem_repr),
6150 .id_result = result_id,6552 .id_result = result_id,
...@@ -6163,7 +6565,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6163,7 +6565,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6163}6565}
61646566
6165fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6567fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6166 const zcu = cg.module.zcu;6568 const zcu = cg.zcu;
6167 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6569 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6168 const ptr_ty = cg.typeOf(bin_op.lhs);6570 const ptr_ty = cg.typeOf(bin_op.lhs);
6169 const elem_ty = cg.typeOfIndex(inst);6571 const elem_ty = cg.typeOfIndex(inst);
...@@ -6174,7 +6576,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6174,7 +6576,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6174}6576}
61756577
6176fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {6578fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
6177 const zcu = cg.module.zcu;6579 const zcu = cg.zcu;
6178 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6580 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6179 const un_ptr_ty = cg.typeOf(bin_op.lhs);6581 const un_ptr_ty = cg.typeOf(bin_op.lhs);
6180 const un_ty = un_ptr_ty.childType(zcu);6582 const un_ty = un_ptr_ty.childType(zcu);
...@@ -6184,7 +6586,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6184,7 +6586,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
61846586
6185 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;6587 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
6186 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);6588 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)));6589 const tag_ptr_ty_id = try cg.ptrType(tag_ty_id, cg.storageClass(un_ptr_ty.ptrAddressSpace(zcu)));
61886590
6189 const union_ptr_id = try cg.resolve(bin_op.lhs);6591 const union_ptr_id = try cg.resolve(bin_op.lhs);
6190 const new_tag_id = try cg.resolve(bin_op.rhs);6592 const new_tag_id = try cg.resolve(bin_op.rhs);
...@@ -6201,7 +6603,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6201,7 +6603,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6201 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6603 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6202 const un_ty = cg.typeOf(ty_op.operand);6604 const un_ty = cg.typeOf(ty_op.operand);
62036605
6204 const zcu = cg.module.zcu;6606 const zcu = cg.zcu;
6205 const layout = cg.unionLayout(un_ty);6607 const layout = cg.unionLayout(un_ty);
6206 if (layout.tag_size == 0) return null;6608 if (layout.tag_size == 0) return null;
62076609
...@@ -6225,7 +6627,7 @@ fn unionInit(...@@ -6225,7 +6627,7 @@ fn unionInit(
6225 // Note: The result here is not cached, because it generates runtime code.6627 // Note: The result here is not cached, because it generates runtime code.
62266628
6227 const pt = cg.pt;6629 const pt = cg.pt;
6228 const zcu = cg.module.zcu;6630 const zcu = cg.zcu;
6229 const ip = &zcu.intern_pool;6631 const ip = &zcu.intern_pool;
6230 const union_ty = zcu.typeToUnion(ty).?;6632 const union_ty = zcu.typeToUnion(ty).?;
6231 const tag_ty: Type = .fromInterned(union_ty.enum_tag_type);6633 const tag_ty: Type = .fromInterned(union_ty.enum_tag_type);
...@@ -6250,7 +6652,7 @@ fn unionInit(...@@ -6250,7 +6652,7 @@ fn unionInit(
62506652
6251 if (layout.tag_size != 0) {6653 if (layout.tag_size != 0) {
6252 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);6654 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
6253 const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, .function);6655 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))});6656 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);6657 const tag_id = try cg.constInt(tag_ty, tag_int);
6256 try cg.store(tag_ty, ptr_id, tag_id, .{});6658 try cg.store(tag_ty, ptr_id, tag_id, .{});
...@@ -6258,13 +6660,13 @@ fn unionInit(...@@ -6258,13 +6660,13 @@ fn unionInit(
62586660
6259 if (payload_ty.hasRuntimeBits(zcu)) {6661 if (payload_ty.hasRuntimeBits(zcu)) {
6260 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);6662 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);6663 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});6664 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: {6665 const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty)) blk: {
6264 const payload_ty_id = try cg.resolveType(payload_ty, .indirect);6666 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);6667 const active_pl_ptr_ty_id = try cg.ptrType(payload_ty_id, .function);
6266 const active_pl_ptr_id = cg.module.allocId();6668 const active_pl_ptr_id = cg.allocId();
6267 try cg.body.emit(cg.module.gpa, .OpBitcast, .{6669 try cg.body.emit(cg.gpa, .OpBitcast, .{
6268 .id_result_type = active_pl_ptr_ty_id,6670 .id_result_type = active_pl_ptr_ty_id,
6269 .id_result = active_pl_ptr_id,6671 .id_result = active_pl_ptr_id,
6270 .operand = pl_ptr_id,6672 .operand = pl_ptr_id,
...@@ -6284,7 +6686,7 @@ fn unionInit(...@@ -6284,7 +6686,7 @@ fn unionInit(
6284}6686}
62856687
6286fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6688fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6287 const zcu = cg.module.zcu;6689 const zcu = cg.zcu;
6288 const ip = &zcu.intern_pool;6690 const ip = &zcu.intern_pool;
6289 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6691 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6290 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;6692 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
...@@ -6301,7 +6703,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6301,7 +6703,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63016703
6302fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6704fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6303 const pt = cg.pt;6705 const pt = cg.pt;
6304 const zcu = cg.module.zcu;6706 const zcu = cg.zcu;
6305 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6707 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;6708 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
63076709
...@@ -6316,7 +6718,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6316,7 +6718,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6316 .@"struct" => switch (object_ty.containerLayout(zcu)) {6718 .@"struct" => switch (object_ty.containerLayout(zcu)) {
6317 .@"packed" => {6719 .@"packed" => {
6318 const struct_ty = zcu.typeToPackedStruct(object_ty).?;6720 const struct_ty = zcu.typeToPackedStruct(object_ty).?;
6319 const struct_backing_int_bits = cg.module.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0";6721 const struct_backing_int_bits = cg.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0";
6320 const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index);6722 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 would6723 // 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.6724 // be valid SPIR-V to use an smaller type like u16, some implementations like PoCL will complain.
...@@ -6329,7 +6731,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6329,7 +6731,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);6731 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 } });6732 const masked = try cg.buildBinary(.OpBitwiseAnd, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });
6331 const result_id = blk: {6733 const result_id = blk: {
6332 if (cg.module.backingIntBits(field_bit_size).@"0" == struct_backing_int_bits)6734 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));6735 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));
6334 const trunc = try cg.buildConvert(field_int_ty, masked);6736 const trunc = try cg.buildConvert(field_int_ty, masked);
6335 break :blk try trunc.materialize(cg);6737 break :blk try trunc.materialize(cg);
...@@ -6353,7 +6755,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6353,7 +6755,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6353 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },6755 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },
6354 );6756 );
6355 const result_id = blk: {6757 const result_id = blk: {
6356 if (cg.module.backingIntBits(field_bit_size).@"0" == cg.module.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0")6758 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));6759 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));
6358 const trunc = try cg.buildConvert(int_ty, masked);6760 const trunc = try cg.buildConvert(int_ty, masked);
6359 break :blk try trunc.materialize(cg);6761 break :blk try trunc.materialize(cg);
...@@ -6372,13 +6774,13 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6372,13 +6774,13 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6372 try cg.store(object_ty, tmp_id, object_id, .{});6774 try cg.store(object_ty, tmp_id, object_id, .{});
63736775
6374 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);6776 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);6777 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});6778 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
63776779
6378 const field_ty_id = try cg.resolveType(field_ty, .indirect);6780 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);6781 const active_pl_ptr_ty_id = try cg.ptrType(field_ty_id, .function);
6380 const active_pl_ptr_id = cg.module.allocId();6782 const active_pl_ptr_id = cg.allocId();
6381 try cg.body.emit(cg.module.gpa, .OpBitcast, .{6783 try cg.body.emit(cg.gpa, .OpBitcast, .{
6382 .id_result_type = active_pl_ptr_ty_id,6784 .id_result_type = active_pl_ptr_ty_id,
6383 .id_result = active_pl_ptr_id,6785 .id_result = active_pl_ptr_id,
6384 .operand = pl_ptr_id,6786 .operand = pl_ptr_id,
...@@ -6391,7 +6793,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6391,7 +6793,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6391}6793}
63926794
6393fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6795fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6394 const zcu = cg.module.zcu;6796 const zcu = cg.zcu;
6395 const target = zcu.getTarget();6797 const target = zcu.getTarget();
6396 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6798 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6397 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;6799 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
...@@ -6424,8 +6826,8 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6424,8 +6826,8 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6424 }6826 }
6425 }6827 }
64266828
6427 const base_ptr = cg.module.allocId();6829 const base_ptr = cg.allocId();
6428 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{6830 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
6429 .id_result_type = result_ty_id,6831 .id_result_type = result_ty_id,
6430 .id_result = base_ptr,6832 .id_result = base_ptr,
6431 .integer_value = base_ptr_int,6833 .integer_value = base_ptr_int,
...@@ -6443,7 +6845,7 @@ fn structFieldPtr(...@@ -6443,7 +6845,7 @@ fn structFieldPtr(
6443) !Id {6845) !Id {
6444 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);6846 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);
64456847
6446 const zcu = cg.module.zcu;6848 const zcu = cg.zcu;
6447 const object_ty = object_ptr_ty.childType(zcu);6849 const object_ty = object_ptr_ty.childType(zcu);
6448 switch (object_ty.zigTypeTag(zcu)) {6850 switch (object_ty.zigTypeTag(zcu)) {
6449 .pointer => {6851 .pointer => {
...@@ -6455,8 +6857,8 @@ fn structFieldPtr(...@@ -6455,8 +6857,8 @@ fn structFieldPtr(
6455 const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu);6857 const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu);
6456 if (byte_offset == 0) return object_ptr;6858 if (byte_offset == 0) return object_ptr;
6457 const usize_ty_id = try cg.resolveType(.usize, .direct);6859 const usize_ty_id = try cg.resolveType(.usize, .direct);
6458 const base_int = cg.module.allocId();6860 const base_int = cg.allocId();
6459 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{6861 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
6460 .id_result_type = usize_ty_id,6862 .id_result_type = usize_ty_id,
6461 .id_result = base_int,6863 .id_result = base_int,
6462 .pointer = object_ptr,6864 .pointer = object_ptr,
...@@ -6464,8 +6866,8 @@ fn structFieldPtr(...@@ -6464,8 +6866,8 @@ fn structFieldPtr(
6464 const offset_id = try cg.constInt(.usize, byte_offset);6866 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 } });6867 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);6868 const adjusted_id = try adjusted.materialize(cg);
6467 const result_id = cg.module.allocId();6869 const result_id = cg.allocId();
6468 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{6870 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
6469 .id_result_type = result_ty_id,6871 .id_result_type = result_ty_id,
6470 .id_result = result_id,6872 .id_result = result_id,
6471 .integer_value = adjusted_id,6873 .integer_value = adjusted_id,
...@@ -6483,19 +6885,19 @@ fn structFieldPtr(...@@ -6483,19 +6885,19 @@ fn structFieldPtr(
6483 if (!layout.has_payload) {6885 if (!layout.has_payload) {
6484 // Asked to get a pointer to a zero-sized field. Just lower this6886 // 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.6887 // to undefined, there is no reason to make it be a valid pointer.
6486 return try cg.module.constUndef(result_ty_id);6888 return try cg.constUndef(result_ty_id);
6487 }6889 }
64886890
6489 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));6891 const storage_class = cg.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
6490 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);6892 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);6893 const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, storage_class);
6492 const pl_ptr_id = blk: {6894 const pl_ptr_id = blk: {
6493 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;6895 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});6896 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
6495 };6897 };
64966898
6497 const active_pl_ptr_id = cg.module.allocId();6899 const active_pl_ptr_id = cg.allocId();
6498 try cg.body.emit(cg.module.gpa, .OpBitcast, .{6900 try cg.body.emit(cg.gpa, .OpBitcast, .{
6499 .id_result_type = result_ty_id,6901 .id_result_type = result_ty_id,
6500 .id_result = active_pl_ptr_id,6902 .id_result = active_pl_ptr_id,
6501 .operand = pl_ptr_id,6903 .operand = pl_ptr_id,
...@@ -6525,9 +6927,9 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32)...@@ -6525,9 +6927,9 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32)
6525}6927}
65266928
6527fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {6929fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
6528 const ptr_ty_id = try cg.module.ptrType(ty_id, .function);6930 const ptr_ty_id = try cg.ptrType(ty_id, .function);
6529 const result_id = cg.module.allocId();6931 const result_id = cg.allocId();
6530 try cg.prologue.emit(cg.module.gpa, .OpVariable, .{6932 try cg.prologue.emit(cg.gpa, .OpVariable, .{
6531 .id_result_type = ptr_ty_id,6933 .id_result_type = ptr_ty_id,
6532 .id_result = result_id,6934 .id_result = result_id,
6533 .storage_class = .function,6935 .storage_class = .function,
...@@ -6537,7 +6939,7 @@ fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {...@@ -6537,7 +6939,7 @@ fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
6537}6939}
65386940
6539fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6941fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6540 const zcu = cg.module.zcu;6942 const zcu = cg.zcu;
6541 const target = zcu.getTarget();6943 const target = zcu.getTarget();
6542 const ptr_ty = cg.typeOfIndex(inst);6944 const ptr_ty = cg.typeOfIndex(inst);
6543 const child_ty = ptr_ty.childType(zcu);6945 const child_ty = ptr_ty.childType(zcu);
...@@ -6546,9 +6948,9 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6546,9 +6948,9 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6546 .vulkan, .opengl => {6948 .vulkan, .opengl => {
6547 if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) {6949 if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) {
6548 const as = child_ty.ptrAddressSpace(zcu);6950 const as = child_ty.ptrAddressSpace(zcu);
6549 if (cg.module.storageClass(as) == .function) {6951 if (cg.storageClass(as) == .function) {
6550 const result_id = cg.module.allocId();6952 const result_id = cg.allocId();
6551 try cg.virtual_allocas.put(cg.module.gpa, result_id, null);6953 try cg.tracked_allocas.put(cg.gpa, result_id, null);
6552 return result_id;6954 return result_id;
6553 }6955 }
6554 }6956 }
...@@ -6561,7 +6963,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6561,7 +6963,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6561 const result_id = try cg.alloc(child_ty_id, null);6963 const result_id = try cg.alloc(child_ty_id, null);
6562 if (ptr_align != child_ty.abiAlignment(zcu)) {6964 if (ptr_align != child_ty.abiAlignment(zcu)) {
6563 if (target.os.tag != .opencl) return cg.fail("cannot apply alignment to variables", .{});6965 if (target.os.tag != .opencl) return cg.fail("cannot apply alignment to variables", .{});
6564 try cg.module.decorate(result_id, .{6966 try cg.decorate(result_id, .{
6565 .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) },6967 .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) },
6566 });6968 });
6567 }6969 }
...@@ -6578,9 +6980,9 @@ fn airArg(cg: *CodeGen) Id {...@@ -6578,9 +6980,9 @@ fn airArg(cg: *CodeGen) Id {
6578/// inside the merge block of the block.6980/// inside the merge block of the block.
6579/// This function should only be called with structured control flow generation.6981/// This function should only be called with structured control flow generation.
6580fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {6982fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
6581 const result_id = cg.module.allocId();6983 const result_id = cg.allocId();
6582 const block_id_ty_id = try cg.resolveType(.u32, .direct);6984 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...6985 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);6986 cg.body.writeOperand(Id, block_id_ty_id);
6585 cg.body.writeOperand(Id, result_id);6987 cg.body.writeOperand(Id, result_id);
65866988
...@@ -6597,11 +6999,11 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {...@@ -6597,11 +6999,11 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
6597fn structuredBreak(cg: *CodeGen, target_block: Id) !void {6999fn structuredBreak(cg: *CodeGen, target_block: Id) !void {
6598 if (cg.block_terminated) return;7000 if (cg.block_terminated) return;
65997001
6600 const gpa = cg.module.gpa;7002 const gpa = cg.gpa;
6601 const sblock = cg.block_stack.getLast().?;7003 const sblock = cg.block_stack.getLast().?;
6602 const merge_block = switch (sblock.*) {7004 const merge_block = switch (sblock.*) {
6603 .selection => |*merge| blk: {7005 .selection => |*merge| blk: {
6604 const merge_label = cg.module.allocId();7006 const merge_label = cg.allocId();
6605 try merge.merge_stack.append(gpa, .{7007 try merge.merge_stack.append(gpa, .{
6606 .incoming = .{7008 .incoming = .{
6607 .src_label = cg.block_label,7009 .src_label = cg.block_label,
...@@ -6641,7 +7043,7 @@ fn genStructuredBody(...@@ -6641,7 +7043,7 @@ fn genStructuredBody(
6641 },7043 },
6642 body: []const Air.Inst.Index,7044 body: []const Air.Inst.Index,
6643) !Id {7045) !Id {
6644 const gpa = cg.module.gpa;7046 const gpa = cg.gpa;
66457047
6646 var sblock: Block = switch (block_merge_type) {7048 var sblock: Block = switch (block_merge_type) {
6647 .loop => |merge| .{ .loop = .{7049 .loop => |merge| .{ .loop = .{
...@@ -6679,9 +7081,9 @@ fn genStructuredBody(...@@ -6679,9 +7081,9 @@ fn genStructuredBody(
66797081
6680 // Make sure that we are still in a block when exiting the function.7082 // Make sure that we are still in a block when exiting the function.
6681 // TODO: Can we get rid of that?7083 // TODO: Can we get rid of that?
6682 try cg.beginSpvBlock(cg.module.allocId());7084 try cg.beginSpvBlock(cg.allocId());
6683 const block_id_ty_id = try cg.resolveType(.u32, .direct);7085 const block_id_ty_id = try cg.resolveType(.u32, .direct);
6684 return try cg.module.constUndef(block_id_ty_id);7086 return try cg.constUndef(block_id_ty_id);
6685 }7087 }
66867088
6687 // The top-most merge actually only has a single source, the7089 // The top-most merge actually only has a single source, the
...@@ -6735,8 +7137,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6735,8 +7137,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 current7137 // of the block, then a label, and then generate the rest of the current
6736 // ir.Block in a different SPIR-V block.7138 // ir.Block in a different SPIR-V block.
67377139
6738 const gpa = cg.module.gpa;7140 const gpa = cg.gpa;
6739 const zcu = cg.module.zcu;7141 const zcu = cg.zcu;
6740 const ty = cg.typeOfIndex(inst);7142 const ty = cg.typeOfIndex(inst);
6741 const have_block_result = ty.hasRuntimeBits(zcu);7143 const have_block_result = ty.hasRuntimeBits(zcu);
67427144
...@@ -6756,7 +7158,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6756,7 +7158,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
67567158
6757 // Check if the target of the branch was this current block.7159 // Check if the target of the branch was this current block.
6758 const this_block = try cg.constInt(.u32, @intFromEnum(inst));7160 const this_block = try cg.constInt(.u32, @intFromEnum(inst));
6759 const jump_to_this_block_id = cg.module.allocId();7161 const jump_to_this_block_id = cg.allocId();
6760 const bool_ty_id = try cg.resolveType(.bool, .direct);7162 const bool_ty_id = try cg.resolveType(.bool, .direct);
6761 try cg.body.emit(gpa, .OpIEqual, .{7163 try cg.body.emit(gpa, .OpIEqual, .{
6762 .id_result_type = bool_ty_id,7164 .id_result_type = bool_ty_id,
...@@ -6776,8 +7178,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6776,8 +7178,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
6776 .selection => |*merge| {7178 .selection => |*merge| {
6777 // To jump out of a selection block, push a new entry onto its merge stack and7179 // 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.7180 // generate a conditional branch to there and to the instructions following this block.
6779 const merge_label = cg.module.allocId();7181 const merge_label = cg.allocId();
6780 const then_label = cg.module.allocId();7182 const then_label = cg.allocId();
6781 try cg.body.emit(gpa, .OpSelectionMerge, .{7183 try cg.body.emit(gpa, .OpSelectionMerge, .{
6782 .merge_block = merge_label,7184 .merge_block = merge_label,
6783 .selection_control = .{},7185 .selection_control = .{},
...@@ -6800,7 +7202,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6800,7 +7202,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
6800 .loop => |*merge| {7202 .loop => |*merge| {
6801 // To jump out of a loop block, generate a conditional that exits the block7203 // 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.7204 // to the loop merge if the target ID is not the one of this block.
6803 const continue_label = cg.module.allocId();7205 const continue_label = cg.allocId();
6804 try cg.body.emit(gpa, .OpBranchConditional, .{7206 try cg.body.emit(gpa, .OpBranchConditional, .{
6805 .condition = jump_to_this_block_id,7207 .condition = jump_to_this_block_id,
6806 .true_label = continue_label,7208 .true_label = continue_label,
...@@ -6823,7 +7225,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -6823,7 +7225,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
6823}7225}
68247226
6825fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {7227fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6826 const zcu = cg.module.zcu;7228 const zcu = cg.zcu;
6827 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;7229 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
6828 const operand_ty = cg.typeOf(br.operand);7230 const operand_ty = cg.typeOf(br.operand);
68297231
...@@ -6838,16 +7240,16 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6838,16 +7240,16 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6838}7240}
68397241
6840fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {7242fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6841 const gpa = cg.module.gpa;7243 const gpa = cg.gpa;
6842 const cond_br = cg.air.unwrapCondBr(inst);7244 const cond_br = cg.air.unwrapCondBr(inst);
6843 const then_body = cond_br.then_body;7245 const then_body = cond_br.then_body;
6844 const else_body = cond_br.else_body;7246 const else_body = cond_br.else_body;
6845 const condition_id = try cg.resolve(cond_br.condition);7247 const condition_id = try cg.resolve(cond_br.condition);
68467248
6847 const then_label = cg.module.allocId();7249 const then_label = cg.allocId();
6848 const else_label = cg.module.allocId();7250 const else_label = cg.allocId();
68497251
6850 const merge_label = cg.module.allocId();7252 const merge_label = cg.allocId();
68517253
6852 try cg.body.emit(gpa, .OpSelectionMerge, .{7254 try cg.body.emit(gpa, .OpSelectionMerge, .{
6853 .merge_block = merge_label,7255 .merge_block = merge_label,
...@@ -6888,14 +7290,14 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6888,14 +7290,14 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6888}7290}
68897291
6890fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {7292fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
6891 const gpa = cg.module.gpa;7293 const gpa = cg.gpa;
6892 const block = cg.air.unwrapBlock(inst);7294 const block = cg.air.unwrapBlock(inst);
68937295
6894 const body_label = cg.module.allocId();7296 const body_label = cg.allocId();
68957297
6896 const header_label = cg.module.allocId();7298 const header_label = cg.allocId();
6897 const merge_label = cg.module.allocId();7299 const merge_label = cg.allocId();
6898 const continue_label = cg.module.allocId();7300 const continue_label = cg.allocId();
68997301
6900 // The back-edge must point to the loop header, so generate a separate block for the7302 // 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 there7303 // loop header so that we don't accidentally include some instructions from there
...@@ -6927,18 +7329,19 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6927,18 +7329,19 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
6927}7329}
69287330
6929fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7331fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6930 const zcu = cg.module.zcu;7332 const zcu = cg.zcu;
6931 const pt = cg.pt;7333 const pt = cg.pt;
6932 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7334 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
69337335 const ptr_ty = cg.typeOf(ty_op.operand);
6934 const ptr_info = cg.typeOf(ty_op.operand).ptrInfo(zcu);7336 const ptr_info = ptr_ty.ptrInfo(zcu);
6935
6936 const elem_ty = cg.typeOfIndex(inst);7337 const elem_ty = cg.typeOfIndex(inst);
6937 const operand_ptr_id = try cg.resolve(ty_op.operand);7338 const ptr = try cg.resolvePtr(ty_op.operand);
6938
6939 assert(ptr_info.child == elem_ty.toIntern());7339 assert(ptr_info.child == elem_ty.toIntern());
69407340
6941 if (cg.virtual_allocas.get(operand_ptr_id)) |stored| return stored.?;7341 const operand_ptr_id = switch (ptr) {
7342 .tracked => |t| return t.slot.*.?,
7343 .id => |id| id,
7344 };
69427345
6943 if (ptr_info.packed_offset.host_size != 0 and7346 if (ptr_info.packed_offset.host_size != 0 and
6944 ptr_info.flags.vector_index == .none)7347 ptr_info.flags.vector_index == .none)
...@@ -6955,7 +7358,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6955,7 +7358,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6955 break :blk try shifted.materialize(cg);7358 break :blk try shifted.materialize(cg);
6956 } else host_val;7359 } else host_val;
6957 const result_id = blk: {7360 const result_id = blk: {
6958 if (cg.module.backingIntBits(elem_bit_size).@"0" == cg.module.backingIntBits(host_bits).@"0")7361 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);7362 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 } });7363 const trunc = try cg.buildConvert(field_int_ty, .{ .ty = host_int_ty, .value = .{ .singleton = narrowed } });
6961 break :blk try trunc.materialize(cg);7364 break :blk try trunc.materialize(cg);
...@@ -6968,9 +7371,9 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6968,9 +7371,9 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6968 const ptr_id = switch (ptr_info.flags.vector_index) {7371 const ptr_id = switch (ptr_info.flags.vector_index) {
6969 .none => operand_ptr_id,7372 .none => operand_ptr_id,
6970 else => |index| ptr_id: {7373 else => |index| ptr_id: {
6971 const elem_ptr_ty_id = try cg.module.ptrType(7374 const elem_ptr_ty_id = try cg.ptrType(
6972 try cg.resolveType(elem_ty, .indirect),7375 try cg.resolveType(elem_ty, .indirect),
6973 cg.module.storageClass(ptr_info.flags.address_space),7376 cg.storageClass(ptr_info.flags.address_space),
6974 );7377 );
6975 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});7378 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
6976 },7379 },
...@@ -6979,18 +7382,20 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6979,18 +7382,20 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6979}7382}
69807383
6981fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {7384fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
6982 const zcu = cg.module.zcu;7385 const zcu = cg.zcu;
6983 const pt = cg.pt;7386 const pt = cg.pt;
6984 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;7387 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6985 const ptr_info = cg.typeOf(bin_op.lhs).ptrInfo(zcu);7388 const ptr_ty = cg.typeOf(bin_op.lhs);
7389 const ptr_info = ptr_ty.ptrInfo(zcu);
6986 const elem_ty: Type = .fromInterned(ptr_info.child);7390 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);7391 const value_id = try cg.resolve(bin_op.rhs);
69897392 const operand_ptr_id = switch (try cg.resolvePtr(bin_op.lhs)) {
6990 if (cg.virtual_allocas.getPtr(operand_ptr_id)) |slot| {7393 .tracked => |t| {
6991 slot.* = value_id;7394 t.slot.* = value_id;
6992 return;7395 return;
6993 }7396 },
7397 .id => |id| id,
7398 };
69947399
6995 if (ptr_info.packed_offset.host_size != 0 and7400 if (ptr_info.packed_offset.host_size != 0 and
6996 ptr_info.flags.vector_index == .none)7401 ptr_info.flags.vector_index == .none)
...@@ -7013,7 +7418,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7013,7 +7418,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
7013 }7418 }
70147419
7015 const extended = blk: {7420 const extended = blk: {
7016 if (cg.module.backingIntBits(elem_bit_size).@"0" == cg.module.backingIntBits(host_bits).@"0")7421 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);7422 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 } });7423 const conv = try cg.buildConvert(host_int_ty, .{ .ty = field_int_ty, .value = .{ .singleton = value_as_int } });
7019 break :blk try conv.materialize(cg);7424 break :blk try conv.materialize(cg);
...@@ -7037,9 +7442,9 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7037,9 +7442,9 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
7037 const ptr_id = switch (ptr_info.flags.vector_index) {7442 const ptr_id = switch (ptr_info.flags.vector_index) {
7038 .none => operand_ptr_id,7443 .none => operand_ptr_id,
7039 else => |index| ptr_id: {7444 else => |index| ptr_id: {
7040 const elem_ptr_ty_id = try cg.module.ptrType(7445 const elem_ptr_ty_id = try cg.ptrType(
7041 try cg.resolveType(elem_ty, .indirect),7446 try cg.resolveType(elem_ty, .indirect),
7042 cg.module.storageClass(ptr_info.flags.address_space),7447 cg.storageClass(ptr_info.flags.address_space),
7043 );7448 );
7044 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});7449 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
7045 },7450 },
...@@ -7049,8 +7454,8 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7049,8 +7454,8 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
7049}7454}
70507455
7051fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {7456fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
7052 const gpa = cg.module.gpa;7457 const gpa = cg.gpa;
7053 const zcu = cg.module.zcu;7458 const zcu = cg.zcu;
7054 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7459 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7055 const ret_ty = cg.typeOf(operand);7460 const ret_ty = cg.typeOf(operand);
7056 if (!ret_ty.hasRuntimeBits(zcu)) {7461 if (!ret_ty.hasRuntimeBits(zcu)) {
...@@ -7071,8 +7476,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7071,8 +7476,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
7071}7476}
70727477
7073fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {7478fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
7074 const gpa = cg.module.gpa;7479 const gpa = cg.gpa;
7075 const zcu = cg.module.zcu;7480 const zcu = cg.zcu;
7076 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7481 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7077 const ptr_ty = cg.typeOf(un_op);7482 const ptr_ty = cg.typeOf(un_op);
7078 const ret_ty = ptr_ty.childType(zcu);7483 const ret_ty = ptr_ty.childType(zcu);
...@@ -7090,16 +7495,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7090,16 +7495,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
7090 }7495 }
7091 }7496 }
70927497
7093 const ptr = try cg.resolve(un_op);7498 const value = switch (try cg.resolvePtr(un_op)) {
7094 const value = try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });7499 .tracked => |t| t.slot.*.?,
7500 .id => |ptr| try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }),
7501 };
7095 try cg.body.emit(gpa, .OpReturnValue, .{7502 try cg.body.emit(gpa, .OpReturnValue, .{
7096 .value = value,7503 .value = value,
7097 });7504 });
7098}7505}
70997506
7100fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7507fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7101 const gpa = cg.module.gpa;7508 const gpa = cg.gpa;
7102 const zcu = cg.module.zcu;7509 const zcu = cg.zcu;
7103 const unwrapped_try = cg.air.unwrapTry(inst);7510 const unwrapped_try = cg.air.unwrapTry(inst);
7104 const body = unwrapped_try.else_body;7511 const body = unwrapped_try.else_body;
71057512
...@@ -7118,7 +7525,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7118,7 +7525,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7118 err_union_id;7525 err_union_id;
71197526
7120 const zero_id = try cg.constInt(.anyerror, 0);7527 const zero_id = try cg.constInt(.anyerror, 0);
7121 const is_err_id = cg.module.allocId();7528 const is_err_id = cg.allocId();
7122 try cg.body.emit(gpa, .OpINotEqual, .{7529 try cg.body.emit(gpa, .OpINotEqual, .{
7123 .id_result_type = bool_ty_id,7530 .id_result_type = bool_ty_id,
7124 .id_result = is_err_id,7531 .id_result = is_err_id,
...@@ -7130,8 +7537,8 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7130,8 +7537,8 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7130 // with the current body.7537 // with the current body.
7131 // Just generate a new block here, then generate a new block inline for the remainder of the body.7538 // Just generate a new block here, then generate a new block inline for the remainder of the body.
71327539
7133 const err_block = cg.module.allocId();7540 const err_block = cg.allocId();
7134 const ok_block = cg.module.allocId();7541 const ok_block = cg.allocId();
71357542
7136 // According to AIR documentation, this block is guaranteed7543 // According to AIR documentation, this block is guaranteed
7137 // to not break and end in a return instruction. Thus,7544 // to not break and end in a return instruction. Thus,
...@@ -7162,7 +7569,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7162,7 +7569,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7162}7569}
71637570
7164fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7571fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7165 const zcu = cg.module.zcu;7572 const zcu = cg.zcu;
7166 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7573 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7167 const operand_id = try cg.resolve(ty_op.operand);7574 const operand_id = try cg.resolve(ty_op.operand);
7168 const err_union_ty = cg.typeOf(ty_op.operand);7575 const err_union_ty = cg.typeOf(ty_op.operand);
...@@ -7170,7 +7577,7 @@ fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7170,7 +7577,7 @@ fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71707577
7171 if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {7578 if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
7172 // No error possible, so just return undefined.7579 // No error possible, so just return undefined.
7173 return try cg.module.constUndef(err_ty_id);7580 return try cg.constUndef(err_ty_id);
7174 }7581 }
71757582
7176 const payload_ty = err_union_ty.errorUnionPayload(zcu);7583 const payload_ty = err_union_ty.errorUnionPayload(zcu);
...@@ -7198,7 +7605,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7198,7 +7605,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7198}7605}
71997606
7200fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7607fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7201 const zcu = cg.module.zcu;7608 const zcu = cg.zcu;
7202 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7609 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7203 const err_union_ty = cg.typeOfIndex(inst);7610 const err_union_ty = cg.typeOfIndex(inst);
7204 const payload_ty = err_union_ty.errorUnionPayload(zcu);7611 const payload_ty = err_union_ty.errorUnionPayload(zcu);
...@@ -7213,7 +7620,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7213,7 +7620,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
72137620
7214 var members: [2]Id = undefined;7621 var members: [2]Id = undefined;
7215 members[eu_layout.errorFieldIndex()] = operand_id;7622 members[eu_layout.errorFieldIndex()] = operand_id;
7216 members[eu_layout.payloadFieldIndex()] = try cg.module.constUndef(payload_ty_id);7623 members[eu_layout.payloadFieldIndex()] = try cg.constUndef(payload_ty_id);
72177624
7218 var types: [2]Type = undefined;7625 var types: [2]Type = undefined;
7219 types[eu_layout.errorFieldIndex()] = .anyerror;7626 types[eu_layout.errorFieldIndex()] = .anyerror;
...@@ -7247,7 +7654,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7247,7 +7654,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7247}7654}
72487655
7249fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?Id {7656fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?Id {
7250 const zcu = cg.module.zcu;7657 const zcu = cg.zcu;
7251 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7658 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7252 const operand_id = try cg.resolve(un_op);7659 const operand_id = try cg.resolve(un_op);
7253 const operand_ty = cg.typeOf(un_op);7660 const operand_ty = cg.typeOf(un_op);
...@@ -7274,7 +7681,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -7274,7 +7681,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7274 loaded_id;7681 loaded_id;
72757682
7276 const ptr_ty_id = try cg.resolveType(ptr_ty, .direct);7683 const ptr_ty_id = try cg.resolveType(ptr_ty, .direct);
7277 const null_id = try cg.module.constNull(ptr_ty_id);7684 const null_id = try cg.constNull(ptr_ty_id);
7278 const null_tmp: Temporary = .init(ptr_ty, null_id);7685 const null_tmp: Temporary = .init(ptr_ty, null_id);
7279 const ptr: Temporary = .init(ptr_ty, ptr_id);7686 const ptr: Temporary = .init(ptr_ty, ptr_id);
72807687
...@@ -7289,9 +7696,9 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -7289,9 +7696,9 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7289 const is_non_null_id = blk: {7696 const is_non_null_id = blk: {
7290 if (is_pointer) {7697 if (is_pointer) {
7291 if (payload_ty.hasRuntimeBits(zcu)) {7698 if (payload_ty.hasRuntimeBits(zcu)) {
7292 const storage_class = cg.module.storageClass(operand_ty.ptrAddressSpace(zcu));7699 const storage_class = cg.storageClass(operand_ty.ptrAddressSpace(zcu));
7293 const bool_indirect_ty_id = try cg.resolveType(.bool, .indirect);7700 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);7701 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});7702 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});
7296 break :blk try cg.load(.bool, tag_ptr_id, .{});7703 break :blk try cg.load(.bool, tag_ptr_id, .{});
7297 }7704 }
...@@ -7311,8 +7718,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -7311,8 +7718,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7311 return switch (pred) {7718 return switch (pred) {
7312 .is_null => blk: {7719 .is_null => blk: {
7313 // Invert condition7720 // Invert condition
7314 const result_id = cg.module.allocId();7721 const result_id = cg.allocId();
7315 try cg.body.emit(cg.module.gpa, .OpLogicalNot, .{7722 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
7316 .id_result_type = bool_ty_id,7723 .id_result_type = bool_ty_id,
7317 .id_result = result_id,7724 .id_result = result_id,
7318 .operand = is_non_null_id,7725 .operand = is_non_null_id,
...@@ -7324,7 +7731,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -7324,7 +7731,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
7324}7731}
73257732
7326fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?Id {7733fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?Id {
7327 const zcu = cg.module.zcu;7734 const zcu = cg.zcu;
7328 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7735 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7329 const operand_id = try cg.resolve(un_op);7736 const operand_id = try cg.resolve(un_op);
7330 const err_union_ty = cg.typeOf(un_op);7737 const err_union_ty = cg.typeOf(un_op);
...@@ -7342,10 +7749,10 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err...@@ -7342,10 +7749,10 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
7342 else7749 else
7343 try cg.extractField(.anyerror, operand_id, eu_layout.errorFieldIndex());7750 try cg.extractField(.anyerror, operand_id, eu_layout.errorFieldIndex());
73447751
7345 const result_id = cg.module.allocId();7752 const result_id = cg.allocId();
7346 switch (pred) {7753 switch (pred) {
7347 inline else => |pred_ct| try cg.body.emit(7754 inline else => |pred_ct| try cg.body.emit(
7348 cg.module.gpa,7755 cg.gpa,
7349 switch (pred_ct) {7756 switch (pred_ct) {
7350 .is_err => .OpINotEqual,7757 .is_err => .OpINotEqual,
7351 .is_non_err => .OpIEqual,7758 .is_non_err => .OpIEqual,
...@@ -7362,7 +7769,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err...@@ -7362,7 +7769,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
7362}7769}
73637770
7364fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7771fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7365 const zcu = cg.module.zcu;7772 const zcu = cg.zcu;
7366 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7773 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7367 const operand_id = try cg.resolve(ty_op.operand);7774 const operand_id = try cg.resolve(ty_op.operand);
7368 const optional_ty = cg.typeOf(ty_op.operand);7775 const optional_ty = cg.typeOf(ty_op.operand);
...@@ -7378,7 +7785,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7378,7 +7785,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7378}7785}
73797786
7380fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7787fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7381 const zcu = cg.module.zcu;7788 const zcu = cg.zcu;
7382 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7789 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7383 const operand_id = try cg.resolve(ty_op.operand);7790 const operand_id = try cg.resolve(ty_op.operand);
7384 const operand_ty = cg.typeOf(ty_op.operand);7791 const operand_ty = cg.typeOf(ty_op.operand);
...@@ -7402,7 +7809,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7402,7 +7809,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7402}7809}
74037810
7404fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {7811fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7405 const zcu = cg.module.zcu;7812 const zcu = cg.zcu;
7406 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7813 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
7407 const payload_ty = cg.typeOf(ty_op.operand);7814 const payload_ty = cg.typeOf(ty_op.operand);
74087815
...@@ -7422,9 +7829,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7422,9 +7829,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7422}7829}
74237830
7424fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {7831fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7425 const gpa = cg.module.gpa;7832 const gpa = cg.gpa;
7426 const zcu = cg.module.zcu;7833 const zcu = cg.zcu;
7427 const target = cg.module.zcu.getTarget();7834 const target = cg.zcu.getTarget();
7428 const switch_br = cg.air.unwrapSwitch(inst);7835 const switch_br = cg.air.unwrapSwitch(inst);
7429 const cond_ty = cg.typeOf(switch_br.operand);7836 const cond_ty = cg.typeOf(switch_br.operand);
7430 const cond = try cg.resolve(switch_br.operand);7837 const cond = try cg.resolve(switch_br.operand);
...@@ -7434,14 +7841,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7434,14 +7841,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7434 .bool, .error_set => 1,7841 .bool, .error_set => 1,
7435 .int => blk: {7842 .int => blk: {
7436 const bits = cond_ty.intInfo(zcu).bits;7843 const bits = cond_ty.intInfo(zcu).bits;
7437 const backing_bits, const big_int = cg.module.backingIntBits(bits);7844 const backing_bits, const big_int = cg.backingIntBits(bits);
7438 if (big_int) return cg.todo("implement composite int switch", .{});7845 if (big_int) return cg.todo("implement composite int switch", .{});
7439 break :blk if (backing_bits <= 32) 1 else 2;7846 break :blk if (backing_bits <= 32) 1 else 2;
7440 },7847 },
7441 .@"enum" => blk: {7848 .@"enum" => blk: {
7442 const int_ty = cond_ty.intTagType(zcu);7849 const int_ty = cond_ty.intTagType(zcu);
7443 const int_info = int_ty.intInfo(zcu);7850 const int_info = int_ty.intInfo(zcu);
7444 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);7851 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
7445 if (big_int) return cg.todo("implement composite int switch", .{});7852 if (big_int) return cg.todo("implement composite int switch", .{});
7446 break :blk if (backing_bits <= 32) 1 else 2;7853 break :blk if (backing_bits <= 32) 1 else 2;
7447 },7854 },
...@@ -7470,12 +7877,12 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7470,12 +7877,12 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7470 }7877 }
74717878
7472 // First, pre-allocate the labels for the cases.7879 // First, pre-allocate the labels for the cases.
7473 const case_labels = cg.module.allocIds(num_cases);7880 const case_labels = cg.allocIds(num_cases);
7474 // We always need the default case - if zig has none, we will generate unreachable there.7881 // We always need the default case - if zig has none, we will generate unreachable there.
7475 const default_label = cg.module.allocId();7882 const default_label = cg.allocId();
7476 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;7883 const switch_default = if (last_range_case != null) cg.allocId() else default_label;
74777884
7478 const merge_label = cg.module.allocId();7885 const merge_label = cg.allocId();
74797886
7480 try cg.body.emit(gpa, .OpSelectionMerge, .{7887 try cg.body.emit(gpa, .OpSelectionMerge, .{
7481 .merge_block = merge_label,7888 .merge_block = merge_label,
...@@ -7540,12 +7947,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7540,12 +7947,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7540 const item_tmp: Temporary = try cg.temporary(item);7947 const item_tmp: Temporary = try cg.temporary(item);
7541 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);7948 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
7542 case_cond = if (case_cond) |prev| blk: {7949 case_cond = if (case_cond) |prev| blk: {
7543 const combined = cg.module.allocId();7950 const combined = cg.allocId();
7544 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);7951 try cg.body.emit(gpa, .OpLogicalOr, .{
7545 cg.body.writeOperand(Id, bool_ty_id);7952 .id_result_type = bool_ty_id,
7546 cg.body.writeOperand(Id, combined);7953 .id_result = combined,
7547 cg.body.writeOperand(Id, prev);7954 .operand_1 = prev,
7548 cg.body.writeOperand(Id, eq);7955 .operand_2 = eq,
7956 });
7549 break :blk combined;7957 break :blk combined;
7550 } else eq;7958 } else eq;
7551 }7959 }
...@@ -7555,26 +7963,28 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7555,26 +7963,28 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7555 const hi_tmp: Temporary = try cg.temporary(range[1]);7963 const hi_tmp: Temporary = try cg.temporary(range[1]);
7556 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);7964 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);7965 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7558 const in_range = cg.module.allocId();7966 const in_range = cg.allocId();
7559 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);7967 try cg.body.emit(gpa, .OpLogicalAnd, .{
7560 cg.body.writeOperand(Id, bool_ty_id);7968 .id_result_type = bool_ty_id,
7561 cg.body.writeOperand(Id, in_range);7969 .id_result = in_range,
7562 cg.body.writeOperand(Id, ge);7970 .operand_1 = ge,
7563 cg.body.writeOperand(Id, le);7971 .operand_2 = le,
7972 });
7564 case_cond = if (case_cond) |prev| blk: {7973 case_cond = if (case_cond) |prev| blk: {
7565 const combined = cg.module.allocId();7974 const combined = cg.allocId();
7566 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);7975 try cg.body.emit(gpa, .OpLogicalOr, .{
7567 cg.body.writeOperand(Id, bool_ty_id);7976 .id_result_type = bool_ty_id,
7568 cg.body.writeOperand(Id, combined);7977 .id_result = combined,
7569 cg.body.writeOperand(Id, prev);7978 .operand_1 = prev,
7570 cg.body.writeOperand(Id, in_range);7979 .operand_2 = in_range,
7980 });
7571 break :blk combined;7981 break :blk combined;
7572 } else in_range;7982 } else in_range;
7573 }7983 }
75747984
7575 const case_label = case_labels.at(case.idx);7985 const case_label = case_labels.at(case.idx);
7576 const is_last = case.idx == last_range_case.?;7986 const is_last = case.idx == last_range_case.?;
7577 const next_check = if (is_last) default_label else cg.module.allocId();7987 const next_check = if (is_last) default_label else cg.allocId();
75787988
7579 try cg.body.emit(gpa, .OpSelectionMerge, .{7989 try cg.body.emit(gpa, .OpSelectionMerge, .{
7580 .merge_block = next_check,7990 .merge_block = next_check,
...@@ -7633,9 +8043,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7633,9 +8043,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7633}8043}
76348044
7635fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {8045fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7636 const gpa = cg.module.gpa;8046 const gpa = cg.gpa;
7637 const zcu = cg.module.zcu;8047 const zcu = cg.zcu;
7638 const target = cg.module.zcu.getTarget();8048 const target = cg.zcu.getTarget();
7639 const switch_br = cg.air.unwrapSwitch(inst);8049 const switch_br = cg.air.unwrapSwitch(inst);
7640 const cond_ty = cg.typeOf(switch_br.operand);8050 const cond_ty = cg.typeOf(switch_br.operand);
7641 const initial_cond = try cg.resolve(switch_br.operand);8051 const initial_cond = try cg.resolve(switch_br.operand);
...@@ -7645,14 +8055,14 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7645,14 +8055,14 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7645 .bool, .error_set => 1,8055 .bool, .error_set => 1,
7646 .int => blk: {8056 .int => blk: {
7647 const bits = cond_ty.intInfo(zcu).bits;8057 const bits = cond_ty.intInfo(zcu).bits;
7648 const backing_bits, const big_int = cg.module.backingIntBits(bits);8058 const backing_bits, const big_int = cg.backingIntBits(bits);
7649 if (big_int) return cg.todo("implement composite int loop switch", .{});8059 if (big_int) return cg.todo("implement composite int loop switch", .{});
7650 break :blk if (backing_bits <= 32) 1 else 2;8060 break :blk if (backing_bits <= 32) 1 else 2;
7651 },8061 },
7652 .@"enum" => blk: {8062 .@"enum" => blk: {
7653 const int_ty = cond_ty.intTagType(zcu);8063 const int_ty = cond_ty.intTagType(zcu);
7654 const int_info = int_ty.intInfo(zcu);8064 const int_info = int_ty.intInfo(zcu);
7655 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);8065 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
7656 if (big_int) return cg.todo("implement composite int loop switch", .{});8066 if (big_int) return cg.todo("implement composite int loop switch", .{});
7657 break :blk if (backing_bits <= 32) 1 else 2;8067 break :blk if (backing_bits <= 32) 1 else 2;
7658 },8068 },
...@@ -7682,15 +8092,15 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7682,15 +8092,15 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7682 }8092 }
7683 }8093 }
76848094
7685 const case_labels = cg.module.allocIds(num_cases);8095 const case_labels = cg.allocIds(num_cases);
7686 const default_label = cg.module.allocId();8096 const default_label = cg.allocId();
7687 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;8097 const switch_default = if (last_range_case != null) cg.allocId() else default_label;
76888098
7689 const header_label = cg.module.allocId();8099 const header_label = cg.allocId();
7690 const loop_merge = cg.module.allocId();8100 const loop_merge = cg.allocId();
7691 const continue_label = cg.module.allocId();8101 const continue_label = cg.allocId();
7692 const switch_merge = cg.module.allocId();8102 const switch_merge = cg.allocId();
7693 const body_label = cg.module.allocId();8103 const body_label = cg.allocId();
76948104
7695 // switch_dispatch signals "continue the loop" by using this sentinel as the8105 // switch_dispatch signals "continue the loop" by using this sentinel as the
7696 // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes8106 // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes
...@@ -7772,12 +8182,13 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7772,12 +8182,13 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7772 const item_tmp: Temporary = try cg.temporary(item);8182 const item_tmp: Temporary = try cg.temporary(item);
7773 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);8183 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
7774 case_cond = if (case_cond) |prev| blk: {8184 case_cond = if (case_cond) |prev| blk: {
7775 const combined = cg.module.allocId();8185 const combined = cg.allocId();
7776 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);8186 try cg.body.emit(gpa, .OpLogicalOr, .{
7777 cg.body.writeOperand(Id, bool_ty_id);8187 .id_result_type = bool_ty_id,
7778 cg.body.writeOperand(Id, combined);8188 .id_result = combined,
7779 cg.body.writeOperand(Id, prev);8189 .operand_1 = prev,
7780 cg.body.writeOperand(Id, eq);8190 .operand_2 = eq,
8191 });
7781 break :blk combined;8192 break :blk combined;
7782 } else eq;8193 } else eq;
7783 }8194 }
...@@ -7787,26 +8198,28 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7787,26 +8198,28 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7787 const hi_tmp: Temporary = try cg.temporary(range[1]);8198 const hi_tmp: Temporary = try cg.temporary(range[1]);
7788 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);8199 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);8200 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7790 const in_range = cg.module.allocId();8201 const in_range = cg.allocId();
7791 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);8202 try cg.body.emit(gpa, .OpLogicalAnd, .{
7792 cg.body.writeOperand(Id, bool_ty_id);8203 .id_result_type = bool_ty_id,
7793 cg.body.writeOperand(Id, in_range);8204 .id_result = in_range,
7794 cg.body.writeOperand(Id, ge);8205 .operand_1 = ge,
7795 cg.body.writeOperand(Id, le);8206 .operand_2 = le,
8207 });
7796 case_cond = if (case_cond) |prev| blk: {8208 case_cond = if (case_cond) |prev| blk: {
7797 const combined = cg.module.allocId();8209 const combined = cg.allocId();
7798 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);8210 try cg.body.emit(gpa, .OpLogicalOr, .{
7799 cg.body.writeOperand(Id, bool_ty_id);8211 .id_result_type = bool_ty_id,
7800 cg.body.writeOperand(Id, combined);8212 .id_result = combined,
7801 cg.body.writeOperand(Id, prev);8213 .operand_1 = prev,
7802 cg.body.writeOperand(Id, in_range);8214 .operand_2 = in_range,
8215 });
7803 break :blk combined;8216 break :blk combined;
7804 } else in_range;8217 } else in_range;
7805 }8218 }
78068219
7807 const case_label = case_labels.at(case.idx);8220 const case_label = case_labels.at(case.idx);
7808 const is_last = case.idx == last_range_case.?;8221 const is_last = case.idx == last_range_case.?;
7809 const next_check = if (is_last) default_label else cg.module.allocId();8222 const next_check = if (is_last) default_label else cg.allocId();
78108223
7811 try cg.body.emit(gpa, .OpSelectionMerge, .{8224 try cg.body.emit(gpa, .OpSelectionMerge, .{
7812 .merge_block = next_check,8225 .merge_block = next_check,
...@@ -7860,7 +8273,7 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7860,7 +8273,7 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7860 try cg.beginSpvBlock(switch_merge);8273 try cg.beginSpvBlock(switch_merge);
7861 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);8274 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);
78628275
7863 const is_dispatch = cg.module.allocId();8276 const is_dispatch = cg.allocId();
7864 const bool_ty_id = try cg.resolveType(.bool, .direct);8277 const bool_ty_id = try cg.resolveType(.bool, .direct);
7865 try cg.body.emit(gpa, .OpIEqual, .{8278 try cg.body.emit(gpa, .OpIEqual, .{
7866 .id_result_type = bool_ty_id,8279 .id_result_type = bool_ty_id,
...@@ -7869,12 +8282,12 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7869,12 +8282,12 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7869 .operand_2 = dispatch_sentinel,8282 .operand_2 = dispatch_sentinel,
7870 });8283 });
78718284
7872 const dispatch_check_merge = cg.module.allocId();8285 const dispatch_check_merge = cg.allocId();
7873 try cg.body.emit(gpa, .OpSelectionMerge, .{8286 try cg.body.emit(gpa, .OpSelectionMerge, .{
7874 .merge_block = dispatch_check_merge,8287 .merge_block = dispatch_check_merge,
7875 .selection_control = .{},8288 .selection_control = .{},
7876 });8289 });
7877 const exit_block = cg.module.allocId();8290 const exit_block = cg.allocId();
7878 try cg.body.emit(gpa, .OpBranchConditional, .{8291 try cg.body.emit(gpa, .OpBranchConditional, .{
7879 .condition = is_dispatch,8292 .condition = is_dispatch,
7880 .true_label = dispatch_check_merge,8293 .true_label = dispatch_check_merge,
...@@ -7906,25 +8319,30 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7906,25 +8319,30 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void {
7906}8319}
79078320
7908fn airUnreach(cg: *CodeGen) !void {8321fn airUnreach(cg: *CodeGen) !void {
7909 try cg.body.emit(cg.module.gpa, .OpUnreachable, {});8322 try cg.body.emit(cg.gpa, .OpUnreachable, {});
7910}8323}
79118324
7912fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {8325fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {
7913 const zcu = cg.module.zcu;8326 const zcu = cg.zcu;
7914 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;8327 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
7915 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;8328 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;
79168329
7917 if (zcu.comp.config.root_strip) return;8330 if (zcu.comp.config.root_strip) return;
79188331
7919 try cg.body.emit(cg.module.gpa, .OpLine, .{8332 const path_id = cg.allocId();
7920 .file = try cg.module.debugString(path),8333 try cg.sections.debug_strings.emit(cg.gpa, .OpString, .{
8334 .id_result = path_id,
8335 .string = path,
8336 });
8337 try cg.body.emit(cg.gpa, .OpLine, .{
8338 .file = path_id,
7921 .line = cg.base_line + dbg_stmt.line + 1,8339 .line = cg.base_line + dbg_stmt.line + 1,
7922 .column = dbg_stmt.column + 1,8340 .column = dbg_stmt.column + 1,
7923 });8341 });
7924}8342}
79258343
7926fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {8344fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7927 const zcu = cg.module.zcu;8345 const zcu = cg.zcu;
7928 const block = cg.air.unwrapDbgBlock(inst);8346 const block = cg.air.unwrapDbgBlock(inst);
7929 const old_base_line = cg.base_line;8347 const old_base_line = cg.base_line;
7930 defer cg.base_line = old_base_line;8348 defer cg.base_line = old_base_line;
...@@ -7934,15 +8352,17 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7934,15 +8352,17 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
79348352
7935fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {8353fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
7936 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;8354 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
7937 const target_id = try cg.resolve(pl_op.operand);8355 const target_id = switch (try cg.resolvePtr(pl_op.operand)) {
7938 if (cg.virtual_allocas.contains(target_id)) return;8356 .tracked => return,
8357 .id => |id| id,
8358 };
7939 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);8359 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
7940 try cg.module.debugName(target_id, name.toSlice(cg.air));8360 try cg.debugName(target_id, name.toSlice(cg.air));
7941}8361}
79428362
7943fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {8363fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7944 const gpa = cg.module.gpa;8364 const gpa = cg.gpa;
7945 const zcu = cg.module.zcu;8365 const zcu = cg.zcu;
7946 const unwrapped_asm = cg.air.unwrapAsm(inst);8366 const unwrapped_asm = cg.air.unwrapAsm(inst);
79478367
7948 const is_volatile = unwrapped_asm.is_volatile;8368 const is_volatile = unwrapped_asm.is_volatile;
...@@ -7974,7 +8394,6 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -7974,7 +8394,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", .{});8394 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});
7975 });8395 });
79768396
7977 // TODO: This entire function should be handled a bit better...
7978 const ip = &zcu.intern_pool;8397 const ip = &zcu.intern_pool;
7979 switch (ip.indexToKey(val.toIntern())) {8398 switch (ip.indexToKey(val.toIntern())) {
7980 .int_type,8399 .int_type,
...@@ -8080,8 +8499,8 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -8080,8 +8499,8 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
8080fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) !?Id {8499fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) !?Id {
8081 _ = modifier;8500 _ = modifier;
80828501
8083 const gpa = cg.module.gpa;8502 const gpa = cg.gpa;
8084 const zcu = cg.module.zcu;8503 const zcu = cg.zcu;
8085 const air_call = cg.air.unwrapCall(inst);8504 const air_call = cg.air.unwrapCall(inst);
8086 const args = air_call.args;8505 const args = air_call.args;
8087 const callee_ty = cg.typeOf(air_call.callee);8506 const callee_ty = cg.typeOf(air_call.callee);
...@@ -8094,11 +8513,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -8094,11 +8513,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
8094 const return_type = fn_info.return_type;8513 const return_type = fn_info.return_type;
80958514
8096 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));8515 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));
8097 const result_id = cg.module.allocId();8516 const result_id = cg.allocId();
8098 const callee_id = try cg.resolve(air_call.callee);8517 const callee_id = try cg.resolve(air_call.callee);
80998518
8100 comptime assert(zig_call_abi_ver == 3);
8101
8102 const scratch_top = cg.id_scratch.items.len;8519 const scratch_top = cg.id_scratch.items.len;
8103 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);8520 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
8104 const params = try cg.id_scratch.addManyAsSlice(gpa, args.len);8521 const params = try cg.id_scratch.addManyAsSlice(gpa, args.len);
...@@ -8112,7 +8529,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -8112,7 +8529,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
8112 if (!arg_ty.hasRuntimeBits(zcu)) continue;8529 if (!arg_ty.hasRuntimeBits(zcu)) continue;
81138530
8114 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and8531 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and
8115 !arg_ty.childType(zcu).hasRuntimeBits(zcu))8532 !arg_ty.childType(zcu).hasRuntimeBits(zcu) and
8533 cg.storageClass(arg_ty.ptrAddressSpace(zcu)) == .function)
8116 {8534 {
8117 // in logical addressing, pointer arguments to function calls8535 // in logical addressing, pointer arguments to function calls
8118 // must be memory object declarations (OpVariable). for pointers to8536 // must be memory object declarations (OpVariable). for pointers to
...@@ -8147,15 +8565,26 @@ fn builtin3D(...@@ -8147,15 +8565,26 @@ fn builtin3D(
8147 dimension: u32,8565 dimension: u32,
8148 out_of_range_value: anytype,8566 out_of_range_value: anytype,
8149) !Id {8567) !Id {
8150 const gpa = cg.module.gpa;8568 const gpa = cg.gpa;
8151 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);8569 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);
8152 const u32_ty_id = try cg.module.intType(.unsigned, 32);8570 const u32_ty_id = try cg.intType(.unsigned, 32);
8153 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);8571 const vec_ty_id = try cg.vectorType(3, u32_ty_id);
8154 const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input);8572 const ptr_ty_id = try cg.ptrType(vec_ty_id, .input);
8155 const spv_decl_index = try cg.module.builtin(ptr_ty_id, built_in, .input);8573 const builtins_gop = try cg.builtins.getOrPut(gpa, .{ built_in, .input });
8156 try cg.module.decl_deps.append(gpa, spv_decl_index);8574 if (!builtins_gop.found_existing) {
8157 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;8575 builtins_gop.value_ptr.* = try cg.allocDecl(.global);
8158 const vec_id = cg.module.allocId();8576 const decl = cg.declPtr(builtins_gop.value_ptr.*);
8577 try cg.sections.globals.emit(gpa, .OpVariable, .{
8578 .id_result_type = ptr_ty_id,
8579 .id_result = decl.result_id,
8580 .storage_class = .input,
8581 });
8582 try cg.decorate(decl.result_id, .{ .built_in = .{ .built_in = built_in } });
8583 }
8584 const spv_decl_index = builtins_gop.value_ptr.*;
8585 try cg.decl_deps.append(gpa, spv_decl_index);
8586 const ptr_id = cg.declPtr(spv_decl_index).result_id;
8587 const vec_id = cg.allocId();
8159 try cg.body.emit(gpa, .OpLoad, .{8588 try cg.body.emit(gpa, .OpLoad, .{
8160 .id_result_type = vec_ty_id,8589 .id_result_type = vec_ty_id,
8161 .id_result = vec_id,8590 .id_result = vec_id,
...@@ -8186,12 +8615,30 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -8186,12 +8615,30 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
8186 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);8615 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
8187}8616}
81888617
8189fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {8618const std = @import("std");
8190 const zcu = cg.module.zcu;8619const Allocator = std.mem.Allocator;
8191 return cg.air.typeOf(inst, &zcu.intern_pool);8620const Target = std.Target;
8192}8621const Signedness = std.lang.Signedness;
8622const assert = std.debug.assert;
8623const log = std.log.scoped(.codegen);
81938624
8194fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {8625const builtin = @import("builtin");
8195 const zcu = cg.module.zcu;8626const link = @import("../../link.zig");
8196 return cg.air.typeOfIndex(inst, &zcu.intern_pool);8627const codegen = @import("../../codegen.zig");
8197}8628const Zcu = @import("../../Zcu.zig");
8629const Type = @import("../../Type.zig");
8630const Value = @import("../../Value.zig");
8631const Air = @import("../../Air.zig");
8632const InternPool = @import("../../InternPool.zig");
8633const Section = @import("Section.zig");
8634const Assembler = @import("Assembler.zig");
8635const Mir = @import("Mir.zig");
8636
8637const spec = @import("spec.zig");
8638const Opcode = spec.Opcode;
8639const Word = spec.Word;
8640const Id = spec.Id;
8641const IdRange = spec.IdRange;
8642const StorageClass = spec.StorageClass;
8643
8644const 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}
src/link/SpirV.zig+66-40
...@@ -1034,10 +1034,6 @@ fn collectEntryPointInterface(...@@ -1034,10 +1034,6 @@ fn collectEntryPointInterface(
1034 for (mir.decl_deps) |dep| {1034 for (mir.decl_deps) |dep| {
1035 try collectEntryPointInterface(linker, dep.nav, interface, visited, nav_final_ids, uav_final_ids, frag_infos, gpa);1035 try collectEntryPointInterface(linker, dep.nav, interface, visited, nav_final_ids, uav_final_ids, frag_infos, gpa);
1036 }1036 }
1037
1038 for (mir.nav_refs) |ref| {
1039 try collectEntryPointInterface(linker, ref.nav, interface, visited, nav_final_ids, uav_final_ids, frag_infos, gpa);
1040 }
1041}1037}
10421038
1043fn remapAndAppend(1039fn remapAndAppend(
...@@ -1078,52 +1074,82 @@ fn remapAndAppendInst(...@@ -1078,52 +1074,82 @@ fn remapAndAppendInst(
1078 for (inst_spec.operands) |operand| {1074 for (inst_spec.operands) |operand| {
1079 const cat = operand.kind.category();1075 const cat = operand.kind.category();
1080 switch (operand.quantifier) {1076 switch (operand.quantifier) {
1081 .required => {1077 .required, .optional => {
1082 if (offset >= inst.operands.len) break;1078 if (offset >= inst.operands.len) break;
1083 if (cat == .id) {1079 offset += remapOperand(operand.kind, cat, inst, inst_slice, offset, id_offset, id_remap);
1084 remapSingleId(&inst_slice[1 + offset], id_offset, id_remap);
1085 offset += 1;
1086 } else if (cat == .literal) {
1087 offset += operandLiteralWordCount(operand.kind, inst, offset);
1088 } else if (cat == .composite) {
1089 remapCompositeOperand(operand.kind, inst_slice, offset, id_offset, id_remap);
1090 offset += 2;
1091 } else {
1092 offset += 1;
1093 }
1094 },
1095 .optional => {
1096 if (offset >= inst.operands.len) break;
1097 if (cat == .id) {
1098 remapSingleId(&inst_slice[1 + offset], id_offset, id_remap);
1099 offset += 1;
1100 } else if (cat == .literal) {
1101 offset += operandLiteralWordCount(operand.kind, inst, offset);
1102 } else {
1103 offset += 1;
1104 }
1105 },1080 },
1106 .variadic => {1081 .variadic => {
1107 while (offset < inst.operands.len) {1082 while (offset < inst.operands.len) {
1108 if (cat == .id) {1083 offset += remapOperand(operand.kind, cat, inst, inst_slice, offset, id_offset, id_remap);
1109 remapSingleId(&inst_slice[1 + offset], id_offset, id_remap);
1110 offset += 1;
1111 } else if (cat == .literal) {
1112 offset += operandLiteralWordCount(operand.kind, inst, offset);
1113 } else if (cat == .composite) {
1114 if (offset + 1 < inst.operands.len) {
1115 remapCompositeOperand(operand.kind, inst_slice, offset, id_offset, id_remap);
1116 }
1117 offset += 2;
1118 } else {
1119 offset += 1;
1120 }
1121 }1084 }
1122 },1085 },
1123 }1086 }
1124 }1087 }
1125}1088}
11261089
1090fn remapOperand(
1091 kind: spec.OperandKind,
1092 cat: spec.OperandCategory,
1093 inst: BinaryModule.Instruction,
1094 inst_slice: []Word,
1095 offset: usize,
1096 id_offset: Word,
1097 id_remap: *const std.AutoHashMapUnmanaged(Id, Id),
1098) usize {
1099 switch (cat) {
1100 .id => {
1101 remapSingleId(&inst_slice[1 + offset], id_offset, id_remap);
1102 return 1;
1103 },
1104 .literal => return operandLiteralWordCount(kind, inst, offset),
1105 .composite => {
1106 remapCompositeOperand(kind, inst_slice, offset, id_offset, id_remap);
1107 return 2;
1108 },
1109 .bit_enum => {
1110 const mask = inst_slice[1 + offset];
1111 var consumed: usize = 1;
1112 for (kind.enumerants()) |e| {
1113 if ((mask & e.value) == 0) continue;
1114 for (e.parameters) |param_kind| {
1115 if (offset + consumed >= inst.operands.len) return consumed;
1116 consumed += remapOperand(
1117 param_kind,
1118 param_kind.category(),
1119 inst,
1120 inst_slice,
1121 offset + consumed,
1122 id_offset,
1123 id_remap,
1124 );
1125 }
1126 }
1127 return consumed;
1128 },
1129 .value_enum => {
1130 const value = inst_slice[1 + offset];
1131 var consumed: usize = 1;
1132 for (kind.enumerants()) |e| {
1133 if (e.value != value) continue;
1134 for (e.parameters) |param_kind| {
1135 if (offset + consumed >= inst.operands.len) return consumed;
1136 consumed += remapOperand(
1137 param_kind,
1138 param_kind.category(),
1139 inst,
1140 inst_slice,
1141 offset + consumed,
1142 id_offset,
1143 id_remap,
1144 );
1145 }
1146 break;
1147 }
1148 return consumed;
1149 },
1150 }
1151}
1152
1127fn remapCompositeOperand(1153fn remapCompositeOperand(
1128 kind: spec.OperandKind,1154 kind: spec.OperandKind,
1129 inst_slice: []Word,1155 inst_slice: []Word,
src/link/SpirV/prune_unused.zig+1-3
...@@ -92,9 +92,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {...@@ -92,9 +92,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
92 }92 }
9393
94 // mark operands of alive function contents94 // mark operands of alive function contents
95 if (!canPrune(inst.opcode)) {95 try markAlive(parser, binary.*, inst, &alive, &id_to_index, &code_offsets, &id_offset_buf);
96 try markAlive(parser, binary.*, inst, &alive, &id_to_index, &code_offsets, &id_offset_buf);
97 }
98 }96 }
9997
100 // rewrite98 // rewrite
test/behavior/array.zig+4
...@@ -654,6 +654,8 @@ test "array of array agregate init" {...@@ -654,6 +654,8 @@ test "array of array agregate init" {
654}654}
655655
656test "pointer to array has ptr field" {656test "pointer to array has ptr field" {
657 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
658
657 const arr: *const [5]u32 = &.{ 10, 20, 30, 40, 50 };659 const arr: *const [5]u32 = &.{ 10, 20, 30, 40, 50 };
658 try std.testing.expect(arr.ptr == @as([*]const u32, arr));660 try std.testing.expect(arr.ptr == @as([*]const u32, arr));
659 try std.testing.expect(arr.ptr[0] == 10);661 try std.testing.expect(arr.ptr[0] == 10);
...@@ -1150,6 +1152,8 @@ test "resist alias of explicit copy of array passed as arg" {...@@ -1150,6 +1152,8 @@ test "resist alias of explicit copy of array passed as arg" {
1150}1152}
11511153
1152test "access element through reference" {1154test "access element through reference" {
1155 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1156
1153 const S = struct {1157 const S = struct {
1154 fn doTheTest(x: u8) !void {1158 fn doTheTest(x: u8) !void {
1155 {1159 {
test/behavior/bitcast.zig+10
...@@ -439,6 +439,8 @@ test "@bitCast of packed struct with void field to integer" {...@@ -439,6 +439,8 @@ test "@bitCast of packed struct with void field to integer" {
439}439}
440440
441test "@bitCast vector to array with different element size" {441test "@bitCast vector to array with different element size" {
442 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
443
442 const static = struct {444 const static = struct {
443 fn doTheTest(v: @Vector(4, u5)) !void {445 fn doTheTest(v: @Vector(4, u5)) !void {
444 const result: [5]u4 = @bitCast(v);446 const result: [5]u4 = @bitCast(v);
...@@ -462,6 +464,8 @@ test "@bitCast vector to array with different element size" {...@@ -462,6 +464,8 @@ test "@bitCast vector to array with different element size" {
462}464}
463465
464test "@bitCast packed struct to array of bits" {466test "@bitCast packed struct to array of bits" {
467 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
468
465 const S = packed struct(u16) {469 const S = packed struct(u16) {
466 foo: u5,470 foo: u5,
467 bar: i7,471 bar: i7,
...@@ -508,6 +512,8 @@ test "@bitCast packed struct to array of bits" {...@@ -508,6 +512,8 @@ test "@bitCast packed struct to array of bits" {
508}512}
509513
510test "@bitCast nested arrays of vectors" {514test "@bitCast nested arrays of vectors" {
515 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
516
511 const Src = [2][2]@Vector(4, u5);517 const Src = [2][2]@Vector(4, u5);
512 const Dest = [5]@Vector(2, u8);518 const Dest = [5]@Vector(2, u8);
513519
...@@ -543,6 +549,8 @@ test "@bitCast nested arrays of vectors" {...@@ -543,6 +549,8 @@ test "@bitCast nested arrays of vectors" {
543}549}
544550
545test "@bitCast nested arrays of bool to scalar" {551test "@bitCast nested arrays of bool to scalar" {
552 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
553
546 const static = struct {554 const static = struct {
547 fn doTheTest(src: [4][4]bool) !void {555 fn doTheTest(src: [4][4]bool) !void {
548 const result: u16 = @bitCast(src);556 const result: u16 = @bitCast(src);
...@@ -560,6 +568,8 @@ test "@bitCast nested arrays of bool to scalar" {...@@ -560,6 +568,8 @@ test "@bitCast nested arrays of bool to scalar" {
560}568}
561569
562test "@bitCast deeply nested arrays to scalar" {570test "@bitCast deeply nested arrays to scalar" {
571 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
572
563 const static = struct {573 const static = struct {
564 fn doTheTest(src: [2][1][3][5]u4) !void {574 fn doTheTest(src: [2][1][3][5]u4) !void {
565 const signed: i120 = @bitCast(src);575 const signed: i120 = @bitCast(src);
test/behavior/comptime_memory.zig+2
...@@ -585,6 +585,8 @@ test "comptime store to extern struct reinterpreted as byte array" {...@@ -585,6 +585,8 @@ test "comptime store to extern struct reinterpreted as byte array" {
585}585}
586586
587test "reinterpret sentinel-terminated array as packed struct" {587test "reinterpret sentinel-terminated array as packed struct" {
588 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
589
588 const S = packed struct(u16) { lo: u8, hi: u8 };590 const S = packed struct(u16) { lo: u8, hi: u8 };
589 const data: [2:0]u8 = .{ 0x12, 0x34 };591 const data: [2:0]u8 = .{ 0x12, 0x34 };
590 const ptr: *align(1) const S = @ptrCast(&data);592 const ptr: *align(1) const S = @ptrCast(&data);
test/behavior/globals.zig+1
...@@ -16,6 +16,7 @@ var vpos = @Vector(2, f32){ 0.0, 0.0 };...@@ -16,6 +16,7 @@ var vpos = @Vector(2, f32){ 0.0, 0.0 };
16test "store to global vector" {16test "store to global vector" {
17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1920
20 try expect(vpos[1] == 0.0);21 try expect(vpos[1] == 0.0);
21 vpos = @Vector(2, f32){ 0.0, 1.0 };22 vpos = @Vector(2, f32){ 0.0, 1.0 };
test/behavior/spirv.zig+1-1
...@@ -10,7 +10,7 @@ const Image = @SpirvType(.{ .image = .{...@@ -10,7 +10,7 @@ const Image = @SpirvType(.{ .image = .{
10} });10} });
11const SampledImage = @SpirvType(.{ .sampled_image = Image });11const SampledImage = @SpirvType(.{ .sampled_image = Image });
12const StorageImage = @SpirvType(.{ .image = .{12const StorageImage = @SpirvType(.{ .image = .{
13 .usage = .storage,13 .usage = .{ .storage = u32 },
14 .format = .unknown,14 .format = .unknown,
15 .dim = .@"2d",15 .dim = .@"2d",
16 .depth = .unknown,16 .depth = .unknown,
test/behavior/type_info.zig+40
...@@ -613,3 +613,43 @@ test "@typeInfo function with generic return type and inferred error set" {...@@ -613,3 +613,43 @@ test "@typeInfo function with generic return type and inferred error set" {
613 const ret_ty = @typeInfo(@TypeOf(S.testFn)).@"fn".return_type;613 const ret_ty = @typeInfo(@TypeOf(S.testFn)).@"fn".return_type;
614 comptime assert(ret_ty == null);614 comptime assert(ret_ty == null);
615}615}
616
617test "type info: spirv info" {
618 if (builtin.zig_backend != .stage2_spirv) return error.SkipZigTest;
619
620 try testSpirv();
621 try comptime testSpirv();
622}
623
624fn testSpirv() !void {
625 const image_info = @typeInfo(Image);
626 try expect(image_info.spirv.image.usage.sampled == f32);
627 try expect(image_info.spirv.image.format == .unknown);
628 try expect(image_info.spirv.image.dim == .@"2d");
629 try expect(image_info.spirv.image.depth == .not_depth);
630 try expect(image_info.spirv.image.arrayed == false);
631 try expect(image_info.spirv.image.multisampled == false);
632 try expect(image_info.spirv.image.access == .unknown);
633
634 const sampled_image_info = @typeInfo(SampledImage);
635 try expect(sampled_image_info.spirv.sampled_image == Image);
636
637 const sampler_info = @typeInfo(Sampler);
638 try expect(sampler_info.spirv.sampler == {});
639
640 const runtime_array_info = @typeInfo(RuntimeArray);
641 try expect(runtime_array_info.spirv.runtime_array == f32);
642}
643
644pub const Image = @SpirvType(.{ .image = .{
645 .usage = .{ .sampled = f32 },
646 .format = .unknown,
647 .dim = .@"2d",
648 .depth = .not_depth,
649 .arrayed = false,
650 .multisampled = false,
651 .access = .unknown,
652} });
653pub const SampledImage = @SpirvType(.{ .sampled_image = Image });
654pub const Sampler = @SpirvType(.sampler);
655pub const RuntimeArray = @SpirvType(.{ .runtime_array = f32 });
test/cases/callconv_spirv.zig+3-2
...@@ -7,5 +7,6 @@ export fn mesh() callconv(.{ .spirv_mesh = .{ .stage_output = .output_lines, .ma...@@ -7,5 +7,6 @@ export fn mesh() callconv(.{ .spirv_mesh = .{ .stage_output = .output_lines, .ma
7// compile7// compile
8// output_mode=Obj8// output_mode=Obj
9// backend=selfhosted9// backend=selfhosted
10// target=spirv64-vulkan10// target=spirv32-vulkan
11// emit_bin=false11// cpu_features=vulkan_v1_2+mesh_shading_ext
12// emit_bin=true
test/cases/compile_errors/SpirvType_vulkan_target.zig+2-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1comptime {1comptime {
2 _ = @SpirvType(.{ .image = .{2 _ = @SpirvType(.{ .image = .{
3 .usage = .storage,3 .usage = .{ .storage = u32 },
4 .format = .unknown,4 .format = .unknown,
5 .dim = .@"2d",5 .dim = .@"2d",
6 .depth = .unknown,6 .depth = .unknown,
...@@ -48,7 +48,7 @@ comptime {...@@ -48,7 +48,7 @@ comptime {
4848
49// error49// error
50// backend=selfhosted50// backend=selfhosted
51// target=spirv64-vulkan51// target=spirv32-vulkan
52//52//
53// :2:21: error: access qualifier '.read_only' is only valid under the 'opencl' os53// :2:21: error: access qualifier '.read_only' is only valid under the 'opencl' os
54// :14:21: error: invalid 'sampled' field value 'bool'54// :14:21: error: invalid 'sampled' field value 'bool'
test/cases/compile_errors/callconv_spirv_invalid_options.zig+1-1
...@@ -21,7 +21,7 @@ export fn entry4() void {...@@ -21,7 +21,7 @@ export fn entry4() void {
2121
22// error22// error
23// backend=selfhosted23// backend=selfhosted
24// target=spirv64-vulkan24// target=spirv32-vulkan
25//25//
26// :1:28: error: kernel workgroup dimensions must be at least 126// :1:28: error: kernel workgroup dimensions must be at least 1
27// :2:28: error: kernel workgroup dimensions must be at least 127// :2:28: error: kernel workgroup dimensions must be at least 1
test/cases/compile_errors/callconv_spirv_mesh_task_require_vulkan.zig deleted-17
...@@ -1,17 +0,0 @@
1const F1 = fn () callconv(.{ .spirv_task = .{ .x = 1, .y = 1, .z = 1 } }) void;
2const F2 = fn () callconv(.{ .spirv_mesh = .{} }) void;
3export fn entry1() void {
4 const a: F1 = undefined;
5 _ = a;
6}
7export fn entry2() void {
8 const a: F2 = undefined;
9 _ = a;
10}
11
12// error
13// backend=selfhosted
14// target=spirv64-opengl
15//
16// :1:28: error: calling convention 'spirv_task' not supported by compiler backend 'stage2_spirv'
17// :2:28: error: calling convention 'spirv_mesh' not supported by compiler backend 'stage2_spirv'
test/cases/compile_errors/callconv_spirv_on_unsupported_platform.zig+1
...@@ -22,6 +22,7 @@ export fn entry4() void {...@@ -22,6 +22,7 @@ export fn entry4() void {
22// error22// error
23// backend=selfhosted23// backend=selfhosted
24// target=spirv64-opencl24// target=spirv64-opencl
25// cpu_features=opencl_v2+mesh_shading_ext
25//26//
26// :1:28: error: calling convention 'spirv_fragment' not supported by compiler backend 'stage2_spirv'27// :1:28: error: calling convention 'spirv_fragment' not supported by compiler backend 'stage2_spirv'
27// :2:28: error: calling convention 'spirv_vertex' not supported by compiler backend 'stage2_spirv'28// :2:28: error: calling convention 'spirv_vertex' not supported by compiler backend 'stage2_spirv'
test/cases/compile_errors/directly_embedding_spirv_type_in_struct_and_union.zig+1-1
...@@ -25,7 +25,7 @@ export fn d() void {...@@ -25,7 +25,7 @@ export fn d() void {
2525
26// error26// error
27// backend=selfhosted27// backend=selfhosted
28// target=spirv64-vulkan28// target=spirv32-vulkan
29//29//
30// :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct30// :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct
31// :4:8: note: opaque types have unknown size31// :4:8: note: opaque types have unknown size
test/cases/compile_errors/extern_spirv_decoration_validation.zig+1-1
...@@ -8,6 +8,6 @@ comptime {...@@ -8,6 +8,6 @@ comptime {
88
9// error9// error
10// backend=selfhosted10// backend=selfhosted
11// target=spirv64-vulkan11// target=spirv32-vulkan
12//12//
13// :1:45: error: 'flat' decoration requires 'input' address space13// :1:45: error: 'flat' decoration requires 'input' address space
test/cases/compile_errors/spirv_merge_logical_pointers.zig+2-2
...@@ -11,8 +11,8 @@ export fn a() void {...@@ -11,8 +11,8 @@ export fn a() void {
11}11}
1212
13// error13// error
14// target=spirv64-vulkan14// target=spirv32-vulkan
15//15//
16// :9:13: error: value with non-mergable pointer type '*i32' depends on runtime control flow16// :9:13: error: value with non-mergable pointer type '*i32' depends on runtime control flow
17// :9:17: note: runtime control flow here17// :9:17: note: runtime control flow here
18// :9:13: note: pointers with address space 'generic' cannot be returned from a branch on target spirv-vulkan by compiler backend stage2_spirv18// :9:13: note: pointers with address space 'generic' cannot be returned from a branch on target 'spirv-vulkan' by compiler backend 'stage2_spirv'
test/cases/image_sampling_spirv.zig created+42
...@@ -0,0 +1,42 @@
1pub const Image = @SpirvType(.{ .image = .{
2 .usage = .{ .sampled = f32 },
3 .format = .unknown,
4 .dim = .@"2d",
5 .depth = .not_depth,
6 .arrayed = false,
7 .multisampled = false,
8 .access = .unknown,
9} });
10pub const SampledImage = @SpirvType(.{ .sampled_image = Image });
11
12const image_in = @extern(*addrspace(.constant) const SampledImage, .{
13 .name = "image_in",
14 .decoration = .{ .descriptor = .{ .set = 2, .binding = 0 } },
15});
16const uv_in = @extern(*addrspace(.input) @Vector(2, f32), .{ .name = "uv", .decoration = .{ .location = 0 } });
17const color_out = @extern(*addrspace(.output) @Vector(4, f32), .{ .name = "color", .decoration = .{ .location = 0 } });
18
19export fn main() callconv(.{ .spirv_fragment = .{} }) void {
20 color_out.* = imageSample(image_in, uv_in.*);
21}
22
23fn imageSample(
24 sampled_image: *addrspace(.constant) const SampledImage,
25 uv: @Vector(2, f32),
26) @Vector(4, f32) {
27 return asm volatile (
28 \\%loaded_sampler = OpLoad %SampledImage %sampled_image
29 \\%ret = OpImageSampleImplicitLod %Result %loaded_sampler %uv
30 : [ret] "" (-> @Vector(4, f32)),
31 : [SampledImage] "t" (SampledImage),
32 [sampled_image] "" (sampled_image),
33 [Result] "t" (@Vector(4, f32)),
34 [uv] "" (uv),
35 );
36}
37
38// compile
39// output_mode=Exe
40// backend=selfhosted
41// target=spirv32-vulkan
42// emit_bin=true
test/cases/spirv_mergable_pointers.zig+2-2
...@@ -13,5 +13,5 @@ export fn a() void {...@@ -13,5 +13,5 @@ export fn a() void {
13// compile13// compile
14// output_mode=Obj14// output_mode=Obj
15// backend=selfhosted15// backend=selfhosted
16// target=spirv64-vulkan16// target=spirv32-vulkan
17// emit_bin=false17// emit_bin=true
test/src/Cases.zig+12-1
...@@ -357,7 +357,15 @@ fn addFromDirInner(...@@ -357,7 +357,15 @@ fn addFromDirInner(
357 var manifest = try TestManifest.parse(ctx.arena, src);357 var manifest = try TestManifest.parse(ctx.arena, src);
358358
359 const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend);359 const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend);
360 const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", std.Target.Query);360 const target_strs = try manifest.getConfigForKeyAlloc(ctx.arena, "target", []const u8);
361 const cpu_features_str = manifest.config_map.get("cpu_features") orelse "";
362 const targets = try ctx.arena.alloc(std.Target.Query, target_strs.len);
363 for (targets, target_strs) |*query, target_str| {
364 query.* = try std.Target.Query.parse(.{
365 .arch_os_abi = target_str,
366 .cpu_features = if (cpu_features_str.len == 0) null else cpu_features_str,
367 });
368 }
361 const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);369 const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);
362 const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);370 const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);
363 const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);371 const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);
...@@ -707,6 +715,8 @@ const TestManifestConfigDefaults = struct {...@@ -707,6 +715,8 @@ const TestManifestConfigDefaults = struct {
707 return "null";715 return "null";
708 } else if (std.mem.eql(u8, key, "imports")) {716 } else if (std.mem.eql(u8, key, "imports")) {
709 return "";717 return "";
718 } else if (std.mem.eql(u8, key, "cpu_features")) {
719 return "";
710 } else unreachable;720 } else unreachable;
711 }721 }
712};722};
...@@ -739,6 +749,7 @@ const TestManifest = struct {...@@ -739,6 +749,7 @@ const TestManifest = struct {
739 .{ "is_test", {} },749 .{ "is_test", {} },
740 .{ "output_mode", {} },750 .{ "output_mode", {} },
741 .{ "target", {} },751 .{ "target", {} },
752 .{ "cpu_features", {} },
742 .{ "c_frontend", {} },753 .{ "c_frontend", {} },
743 .{ "link_libc", {} },754 .{ "link_libc", {} },
744 .{ "backend", {} },755 .{ "backend", {} },