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) {
838838 pub const Usage = union(enum(u2)) {
839839 unknown: type,
840840 sampled: type,
841 storage,
841 storage: type,
842842 };
843843
844844 pub const Format = enum(u4) {
src/Sema.zig+92-48
......@@ -8694,15 +8694,26 @@ fn checkReturnTypeAndCallConv(
86948694 return sema.fail(block, callconv_src, "'pixel_centered_integer' is not supported on this target", .{});
86958695 }
86968696 },
8697 .spirv_kernel, .spirv_task => |kernel| {
8697 .spirv_kernel => |kernel| {
86988698 if (kernel.x == 0 or kernel.y == 0 or kernel.z == 0) {
86998699 return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{});
87008700 }
87018701 },
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 },
87028710 .spirv_mesh => |mesh| {
87038711 if (mesh.max_vertices == 0 or mesh.max_primitives == 0) {
87048712 return sema.fail(block, callconv_src, "mesh shader 'max_vertices' and 'max_primitives' must be at least 1", .{});
87058713 }
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 }
87068717 },
87078718 else => {},
87088719 }
......@@ -8844,7 +8855,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type)
88448855 try sema.errNote(runtime_src, msg, "runtime control flow here", .{});
88458856
88468857 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}'", .{
88488859 @tagName(as),
88498860 @tagName(target.cpu.arch.family()),
88508861 @tagName(target.os.tag),
......@@ -16793,7 +16804,43 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1679316804 .val = (try pt.aggregateValue(type_opaque_ty, &field_values)).toIntern(),
1679416805 })));
1679516806 },
16796 .spirv => unreachable, // TODO: ALI
16807 .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 },
1679716844 .frame => return sema.failWithUseOfAsync(block, src),
1679816845 .@"anyframe" => return sema.failWithUseOfAsync(block, src),
1679916846 }
......@@ -20594,62 +20641,59 @@ fn zirReifySpirvType(
2059420641 break :ip_data .{
2059520642 .name = name,
2059620643 .zir_index = tracked_inst,
20597 .ty = switch (usage_tag) {
20598 .sampled, .unknown => blk: {
20599 const sampled_type = usage_val.unionPayload(zcu).toType();
20600 std.hash.autoHash(&hasher, sampled_type.toIntern());
20644 .ty = blk: {
20645 const sampled_type = usage_val.unionPayload(zcu).toType();
20646 std.hash.autoHash(&hasher, sampled_type.toIntern());
2060120647
20602 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});
20604 }
20605 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});
20607 }
20648 if (target.os.tag != .opencl and sampled_type.toIntern() == .void_type) {
20649 return sema.fail(block, operand_src, "'void' type for '{t}' field is only valid under the 'opencl' os", .{usage_tag});
20650 }
20651 if (target.os.tag == .opencl and sampled_type.toIntern() != .void_type) {
20652 return sema.fail(block, operand_src, "'{t}' field type must be 'void' under the 'opencl' os", .{usage_tag});
20653 }
2060820654
20609 if (sampled_type.toIntern() != .void_type and
20610 (!sampled_type.hasRuntimeBits(zcu) or (!sampled_type.isRuntimeFloat() and !sampled_type.isInt(zcu))))
20611 {
20612 return sema.fail(block, operand_src, "invalid '{t}' field value '{f}'", .{ usage_tag, sampled_type.fmt(pt) });
20655 if (sampled_type.toIntern() != .void_type and
20656 (!sampled_type.hasRuntimeBits(zcu) or (!sampled_type.isRuntimeFloat() and !sampled_type.isInt(zcu))))
20657 {
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 );
2061320671 }
2061420672
20615 if (target.os.tag == .vulkan) {
20616 const ok = (sampled_type.isRuntimeFloat() and sampled_type.bitSize(zcu) == 32) or
20617 (sampled_type.isInt(zcu) and (sampled_type.bitSize(zcu) == 32 or sampled_type.bitSize(zcu) == 64));
20618 if (!ok) {
20673 if (format != .unknown) {
20674 const format_kind: enum { float, sint, uint } = switch (format) {
20675 .rgba32f, .rgba16f, .rgba8unorm, .rgba8snorm, .r32f => .float,
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) {
2061920686 return sema.fail(
2062020687 block,
2062120688 operand_src,
20622 "'{t}' field value must be a 32-bit int, 64-bit int or 32-bit float under the 'vulkan' os",
20623 .{usage_tag},
20689 "image 'format' '.{t}' does not match '{t}' type '{f}' under the 'vulkan' os",
20690 .{ format, usage_tag, sampled_type.fmt(pt) },
2062420691 );
2062520692 }
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 }
2064820693 }
20694 }
2064920695
20650 break :blk sampled_type.toIntern();
20651 },
20652 .storage => .none,
20696 break :blk sampled_type.toIntern();
2065320697 },
2065420698 .flags = .{
2065520699 .tag = .image,
src/Zcu.zig+13-1
......@@ -469,6 +469,12 @@ pub const StdLangDecl = enum {
469469 @"Type.ContainerLayout",
470470 @"Type.Opaque",
471471 @"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
473479 panic,
474480 @"panic.call",
......@@ -550,6 +556,12 @@ pub const StdLangDecl = enum {
550556 .@"Type.ContainerLayout",
551557 .@"Type.Opaque",
552558 .@"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",
553565 => .type,
554566
555567 .panic => .type,
......@@ -603,7 +615,7 @@ pub const StdLangDecl = enum {
603615 .VaList => .va_list,
604616 .assembly, .@"assembly.Clobbers" => .assembly,
605617 else => {
606 if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Spirv")) {
618 if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Spirv.Image.Access")) {
607619 return .main;
608620 } else {
609621 return .panic;
src/codegen/spirv/Assembler.zig+74-85
......@@ -3,7 +3,7 @@ const Allocator = std.mem.Allocator;
33const assert = std.debug.assert;
44
55const CodeGen = @import("CodeGen.zig");
6const Decl = @import("Module.zig").Decl;
6const Decl = @import("CodeGen.zig").Decl;
77
88const spec = @import("spec.zig");
99const Opcode = spec.Opcode;
......@@ -56,7 +56,7 @@ const Operand = union(enum) {
5656};
5757
5858pub fn deinit(ass: *Assembler) void {
59 const gpa = ass.cg.module.gpa;
59 const gpa = ass.cg.gpa;
6060 for (ass.errors.items) |err| gpa.free(err.msg);
6161 ass.tokens.deinit(gpa);
6262 ass.errors.deinit(gpa);
......@@ -69,7 +69,7 @@ pub fn deinit(ass: *Assembler) void {
6969const Error = error{ AssembleFail, OutOfMemory };
7070
7171pub fn assemble(ass: *Assembler, src: []const u8) Error!void {
72 const gpa = ass.cg.module.gpa;
72 const gpa = ass.cg.gpa;
7373
7474 ass.src = src;
7575 ass.errors.clearRetainingCapacity();
......@@ -100,7 +100,7 @@ const ErrorMsg = struct {
100100};
101101
102102fn addError(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytype) !void {
103 const gpa = ass.cg.module.gpa;
103 const gpa = ass.cg.gpa;
104104 const msg = try std.fmt.allocPrint(gpa, fmt, args);
105105 errdefer gpa.free(msg);
106106 try ass.errors.append(gpa, .{
......@@ -159,7 +159,7 @@ const AsmValue = union(enum) {
159159/// If this function returns `error.AssembleFail`, an explanatory
160160/// error message has already been emitted into `ass.errors`.
161161fn processInstruction(ass: *Assembler) !void {
162 const module = ass.cg.module;
162 const cg = ass.cg;
163163 const result: AsmValue = switch (ass.inst.opcode) {
164164 .OpEntryPoint => {
165165 return ass.fail(ass.currentToken().start, "cannot export entry points in assembly", .{});
......@@ -176,7 +176,7 @@ fn processInstruction(ass: *Assembler) !void {
176176 const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse {
177177 return ass.fail(set_name_offset, "unknown instruction set: {s}", .{set_name});
178178 };
179 break :blk .{ .value = try module.importInstructionSet(set_tag) };
179 break :blk .{ .value = try cg.importInstructionSet(set_tag) };
180180 },
181181 else => switch (ass.inst.opcode.class()) {
182182 .type_declaration => try ass.processTypeInstruction(),
......@@ -197,13 +197,12 @@ fn processInstruction(ass: *Assembler) !void {
197197
198198fn processTypeInstruction(ass: *Assembler) !AsmValue {
199199 const cg = ass.cg;
200 const gpa = cg.module.gpa;
201 const module = cg.module;
200 const gpa = cg.gpa;
202201 const operands = ass.inst.operands.items;
203 const section = &module.sections.globals;
202 const section = &cg.sections.globals;
204203 const id = switch (ass.inst.opcode) {
205 .OpTypeVoid => try module.voidType(),
206 .OpTypeBool => try module.boolType(),
204 .OpTypeVoid => try cg.voidType(),
205 .OpTypeBool => try cg.boolType(),
207206 .OpTypeInt => blk: {
208207 const signedness: std.lang.Signedness = switch (operands[2].literal32) {
209208 0 => .unsigned,
......@@ -216,7 +215,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
216215 const width = std.math.cast(u16, operands[1].literal32) orelse {
217216 return ass.fail(0, "int type of {} bits is too large", .{operands[1].literal32});
218217 };
219 break :blk try module.intType(signedness, width);
218 break :blk try cg.intType(signedness, width);
220219 },
221220 .OpTypeFloat => blk: {
222221 const bits = operands[1].literal32;
......@@ -226,11 +225,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
226225 return ass.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});
227226 },
228227 }
229 break :blk try module.floatType(@intCast(bits));
228 break :blk try cg.floatType(@intCast(bits));
230229 },
231230 .OpTypeVector => blk: {
232231 const child_type = try ass.resolveRefId(operands[1].ref_id);
233 break :blk try module.vectorType(operands[2].literal32, child_type);
232 break :blk try cg.vectorType(operands[2].literal32, child_type);
234233 },
235234 .OpTypeArray => {
236235 // TODO: The length of an OpTypeArray is determined by a constant (which may be a spec constant),
......@@ -239,8 +238,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
239238 },
240239 .OpTypeRuntimeArray => blk: {
241240 const element_type = try ass.resolveRefId(operands[1].ref_id);
242 const result_id = module.allocId();
243 try section.emit(module.gpa, .OpTypeRuntimeArray, .{
241 const result_id = cg.allocId();
242 try section.emit(cg.gpa, .OpTypeRuntimeArray, .{
244243 .id_result = result_id,
245244 .element_type = element_type,
246245 });
......@@ -249,8 +248,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
249248 .OpTypePointer => blk: {
250249 const storage_class: StorageClass = @enumFromInt(operands[1].value);
251250 const child_type = try ass.resolveRefId(operands[2].ref_id);
252 const result_id = module.allocId();
253 try section.emit(module.gpa, .OpTypePointer, .{
251 const result_id = cg.allocId();
252 try section.emit(cg.gpa, .OpTypePointer, .{
254253 .id_result = result_id,
255254 .storage_class = storage_class,
256255 .type = child_type,
......@@ -262,11 +261,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
262261 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
263262 const ids = try cg.id_scratch.addManyAsSlice(gpa, operands[1..].len);
264263 for (operands[1..], ids) |op, *id| id.* = try ass.resolveRefId(op.ref_id);
265 break :blk try module.structType(ids, null, .none);
264 break :blk try cg.structType(ids, null, .none);
266265 },
267266 .OpTypeImage => blk: {
268267 const sampled_type = try ass.resolveRefId(operands[1].ref_id);
269 const result_id = module.allocId();
268 const result_id = cg.allocId();
270269 try section.emit(gpa, .OpTypeImage, .{
271270 .id_result = result_id,
272271 .sampled_type = sampled_type,
......@@ -280,13 +279,13 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
280279 break :blk result_id;
281280 },
282281 .OpTypeSampler => blk: {
283 const result_id = module.allocId();
282 const result_id = cg.allocId();
284283 try section.emit(gpa, .OpTypeSampler, .{ .id_result = result_id });
285284 break :blk result_id;
286285 },
287286 .OpTypeSampledImage => blk: {
288287 const image_type = try ass.resolveRefId(operands[1].ref_id);
289 const result_id = module.allocId();
288 const result_id = cg.allocId();
290289 try section.emit(gpa, .OpTypeSampledImage, .{ .id_result = result_id, .image_type = image_type });
291290 break :blk result_id;
292291 },
......@@ -301,8 +300,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
301300 for (param_types, param_operands) |*param, operand| {
302301 param.* = try ass.resolveRefId(operand.ref_id);
303302 }
304 const result_id = module.allocId();
305 try section.emit(module.gpa, .OpTypeFunction, .{
303 const result_id = cg.allocId();
304 try section.emit(cg.gpa, .OpTypeFunction, .{
306305 .id_result = result_id,
307306 .return_type = return_type,
308307 .id_ref_2 = param_types,
......@@ -318,27 +317,27 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
318317/// - No forward references are allowed in operands.
319318/// - Target section is determined from instruction type.
320319fn processGenericInstruction(ass: *Assembler) !?AsmValue {
321 const module = ass.cg.module;
322 const target = module.zcu.getTarget();
320 const cg = ass.cg;
321 const target = cg.zcu.getTarget();
323322 const operands = ass.inst.operands.items;
324323 var maybe_spv_decl_index: ?Decl.Index = null;
325324 const section = switch (ass.inst.opcode.class()) {
326 .constant_creation => &module.sections.globals,
327 .annotation => &module.sections.annotations,
325 .constant_creation => &cg.sections.globals,
326 .annotation => &cg.sections.annotations,
328327 .type_declaration => unreachable, // Handled elsewhere.
329328 else => switch (ass.inst.opcode) {
330329 .OpEntryPoint => unreachable,
331 .OpExecutionMode, .OpExecutionModeId => &module.sections.execution_modes,
330 .OpExecutionMode, .OpExecutionModeId => &cg.sections.execution_modes,
332331 .OpVariable => section: {
333332 const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);
334333 if (storage_class == .function) break :section &ass.cg.prologue;
335 maybe_spv_decl_index = try module.allocDecl(.global);
334 maybe_spv_decl_index = try cg.allocDecl(.global);
336335 if (!target.cpu.has(.spirv, .v1_4) and storage_class != .input and storage_class != .output) {
337336 // Before version 1.4, the interface’s storage classes are limited to the Input and Output
338 break :section &module.sections.globals;
337 break :section &cg.sections.globals;
339338 }
340 try ass.cg.module.decl_deps.append(module.gpa, maybe_spv_decl_index.?);
341 break :section &module.sections.globals;
339 try ass.cg.decl_deps.append(cg.gpa, maybe_spv_decl_index.?);
340 break :section &cg.sections.globals;
342341 },
343342 else => &ass.cg.body,
344343 },
......@@ -348,36 +347,36 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue {
348347 const first_word = section.instructions.items.len;
349348 // At this point we're not quite sure how many operands this instruction is
350349 // going to have, so insert 0 and patch up the actual opcode word later.
351 try section.ensureUnusedCapacity(module.gpa, 1);
350 try section.ensureUnusedCapacity(cg.gpa, 1);
352351 section.writeWord(0);
353352
354353 for (operands) |operand| {
355354 switch (operand) {
356355 .value, .literal32 => |word| {
357 try section.ensureUnusedCapacity(module.gpa, 1);
356 try section.ensureUnusedCapacity(cg.gpa, 1);
358357 section.writeWord(word);
359358 },
360359 .literal64 => |dword| {
361 try section.ensureUnusedCapacity(module.gpa, 2);
360 try section.ensureUnusedCapacity(cg.gpa, 2);
362361 section.writeDoubleWord(dword);
363362 },
364363 .result_id => {
365364 maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index|
366 module.declPtr(spv_decl_index).result_id
365 cg.declPtr(spv_decl_index).result_id
367366 else
368 module.allocId();
369 try section.ensureUnusedCapacity(module.gpa, 1);
367 cg.allocId();
368 try section.ensureUnusedCapacity(cg.gpa, 1);
370369 section.writeOperand(Id, maybe_result_id.?);
371370 },
372371 .ref_id => |index| {
373372 const result = try ass.resolveRef(index);
374 try section.ensureUnusedCapacity(module.gpa, 1);
373 try section.ensureUnusedCapacity(cg.gpa, 1);
375374 section.writeOperand(spec.Id, result.resultId());
376375 },
377376 .string => |offset| {
378377 const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0);
379378 const size = std.math.divCeil(usize, text.len + 1, @sizeOf(Word)) catch unreachable;
380 try section.ensureUnusedCapacity(module.gpa, size);
379 try section.ensureUnusedCapacity(cg.gpa, size);
381380 section.writeOperand(spec.LiteralString, text);
382381 },
383382 }
......@@ -430,7 +429,7 @@ fn resolveRefId(ass: *Assembler, ref: AsmValue.Ref) !Id {
430429}
431430
432431fn parseInstruction(ass: *Assembler) !void {
433 const gpa = ass.cg.module.gpa;
432 const gpa = ass.cg.gpa;
434433
435434 ass.inst.opcode = undefined;
436435 ass.inst.operands.clearRetainingCapacity();
......@@ -522,7 +521,7 @@ fn parseOperand(ass: *Assembler, kind: spec.OperandKind) Error!void {
522521
523522/// Also handles parsing any required extra operands.
524523fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {
525 const gpa = ass.cg.module.gpa;
524 const gpa = ass.cg.gpa;
526525
527526 var tok = ass.currentToken();
528527 try ass.expectToken(.value);
......@@ -571,7 +570,7 @@ fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void {
571570
572571/// Also handles parsing any required extra operands.
573572fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {
574 const gpa = ass.cg.module.gpa;
573 const gpa = ass.cg.gpa;
575574
576575 const tok = ass.currentToken();
577576 if (ass.eatToken(.placeholder)) {
......@@ -622,7 +621,7 @@ fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void {
622621}
623622
624623fn parseRefId(ass: *Assembler) !void {
625 const gpa = ass.cg.module.gpa;
624 const gpa = ass.cg.gpa;
626625
627626 const tok = ass.currentToken();
628627 try ass.expectToken(.result_id);
......@@ -638,7 +637,7 @@ fn parseRefId(ass: *Assembler) !void {
638637}
639638
640639fn parseLiteralInteger(ass: *Assembler) !void {
641 const gpa = ass.cg.module.gpa;
640 const gpa = ass.cg.gpa;
642641
643642 const tok = ass.currentToken();
644643 if (ass.eatToken(.placeholder)) {
......@@ -671,7 +670,7 @@ fn parseLiteralInteger(ass: *Assembler) !void {
671670}
672671
673672fn parseLiteralExtInstInteger(ass: *Assembler) !void {
674 const gpa = ass.cg.module.gpa;
673 const gpa = ass.cg.gpa;
675674
676675 const tok = ass.currentToken();
677676 if (ass.eatToken(.placeholder)) {
......@@ -699,7 +698,7 @@ fn parseLiteralExtInstInteger(ass: *Assembler) !void {
699698}
700699
701700fn parseString(ass: *Assembler) !void {
702 const gpa = ass.cg.module.gpa;
701 const gpa = ass.cg.gpa;
703702
704703 const tok = ass.currentToken();
705704 try ass.expectToken(.string);
......@@ -722,46 +721,36 @@ fn parseString(ass: *Assembler) !void {
722721}
723722
724723fn parseContextDependentNumber(ass: *Assembler) !void {
725 const module = ass.cg.module;
726
727 // For context dependent numbers, the actual type to parse is determined by the instruction.
728 // Currently, this operand appears in OpConstant and OpSpecConstant, where the too-be-parsed type
729 // is determined by the result type. That means that in this instructions we have to resolve the
730 // operand type early and look at the result to see how we need to proceed.
724 const cg = ass.cg;
731725 assert(ass.inst.opcode == .OpConstant or ass.inst.opcode == .OpSpecConstant);
732726
733727 const tok = ass.currentToken();
734728 const result = try ass.resolveRef(ass.inst.operands.items[0].ref_id);
735729 const result_id = result.resultId();
736 // We are going to cheat a little bit: The types we are interested in, int and float,
737 // are added to the module and cached via module.intType and module.floatType. Therefore,
738 // we can determine the width of these types by directly checking the cache.
739 // This only works if the Assembler and codegen both use spv.intType and spv.floatType though.
740 // We don't expect there to be many of these types, so just look it up every time.
741 // TODO: Count be improved to be a little bit more efficent.
742
743 {
744 var it = module.cache.int_types.iterator();
745 while (it.next()) |entry| {
746 const id = entry.value_ptr.*;
747 if (id != result_id) continue;
748 const info = entry.key_ptr.*;
749 return try ass.parseContextDependentInt(info.signedness, info.bits);
750 }
751 }
752730
753 {
754 var it = module.cache.float_types.iterator();
755 while (it.next()) |entry| {
756 const id = entry.value_ptr.*;
757 if (id != result_id) continue;
758 const info = entry.key_ptr.*;
759 switch (info.bits) {
760 16 => try ass.parseContextDependentFloat(16),
761 32 => try ass.parseContextDependentFloat(32),
762 64 => try ass.parseContextDependentFloat(64),
763 else => return ass.fail(tok.start, "cannot parse {}-bit info literal", .{info.bits}),
764 }
731 const words = cg.sections.globals.instructions.items;
732 var offset: usize = 0;
733 while (offset < words.len) {
734 const word_count = words[offset] >> 16;
735 const opcode: Opcode = @enumFromInt(words[offset] & 0xFFFF);
736 defer offset += word_count;
737 if (word_count == 0) break;
738 switch (opcode) {
739 .OpTypeInt => if (word_count >= 4 and @as(Id, @enumFromInt(words[offset + 1])) == result_id) {
740 const width: u16 = @intCast(words[offset + 2]);
741 const signedness: std.lang.Signedness = if (words[offset + 3] == 0) .unsigned else .signed;
742 return ass.parseContextDependentInt(signedness, width);
743 },
744 .OpTypeFloat => if (word_count >= 3 and @as(Id, @enumFromInt(words[offset + 1])) == result_id) {
745 const bits = words[offset + 2];
746 return switch (bits) {
747 16 => ass.parseContextDependentFloat(16),
748 32 => ass.parseContextDependentFloat(32),
749 64 => ass.parseContextDependentFloat(64),
750 else => ass.fail(tok.start, "cannot parse {}-bit info literal", .{bits}),
751 };
752 },
753 else => {},
765754 }
766755 }
767756
......@@ -769,7 +758,7 @@ fn parseContextDependentNumber(ass: *Assembler) !void {
769758}
770759
771760fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, width: u32) !void {
772 const gpa = ass.cg.module.gpa;
761 const gpa = ass.cg.gpa;
773762
774763 const tok = ass.currentToken();
775764 if (ass.eatToken(.placeholder)) {
......@@ -820,7 +809,7 @@ fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, wi
820809}
821810
822811fn parseContextDependentFloat(ass: *Assembler, comptime width: u16) !void {
823 const gpa = ass.cg.module.gpa;
812 const gpa = ass.cg.gpa;
824813
825814 const Float = std.meta.Float(width);
826815 const Int = @Int(.unsigned, width);
......@@ -893,7 +882,7 @@ fn tokenText(ass: Assembler, tok: Token) []const u8 {
893882/// Tokenize `ass.src` and put the tokens in `ass.tokens`.
894883/// Any errors encountered are appended to `ass.errors`.
895884fn tokenize(ass: *Assembler) !void {
896 const gpa = ass.cg.module.gpa;
885 const gpa = ass.cg.gpa;
897886
898887 ass.tokens.clearRetainingCapacity();
899888
src/codegen/spirv/CodeGen.zig+1720-1273
......@@ -1,36 +1,103 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const Target = std.Target;
4const Signedness = std.lang.Signedness;
5const assert = std.debug.assert;
6const log = std.log.scoped(.codegen);
1// Compilation
2pt: Zcu.PerThread,
3zcu: *Zcu,
4gpa: Allocator,
5arena: Allocator,
6air: Air,
7liveness: Air.Liveness,
8owner_nav: InternPool.Nav.Index,
9base_line: u32,
710
8const builtin = @import("builtin");
9const link = @import("../../link.zig");
10const codegen = @import("../../codegen.zig");
11const Zcu = @import("../../Zcu.zig");
12const Type = @import("../../Type.zig");
13const Value = @import("../../Value.zig");
14const Air = @import("../../Air.zig");
15const InternPool = @import("../../InternPool.zig");
16const Section = @import("Section.zig");
17const Assembler = @import("Assembler.zig");
18const Mir = @import("Mir.zig");
11// Module-level output (accumulated across the nav's codegen)
12next_result_id: Word = 1,
13decls: std.ArrayList(Decl) = .empty,
14decl_deps: std.ArrayList(Decl.Index) = .empty,
15nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty,
16uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty,
17entry_points: std.array_hash_map.Auto(Id, EntryPoint) = .empty,
18error_buffer: ?Decl.Index = null,
19struct_types: std.array_hash_map.Custom(StructType, Id, StructType.HashContext, true) = .empty,
20builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty,
21sections: struct {
22 // Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".
23 extended_instruction_set: Section = .{},
24 memory_model: Section = .{},
25 execution_modes: Section = .{},
26 debug_strings: Section = .{},
27 debug_names: Section = .{},
28 annotations: Section = .{},
29 globals: Section = .{},
30 functions: Section = .{},
31} = .{},
32
33// Per-function state (reset between top-level genNav calls)
34prologue: Section = .{},
35body: Section = .{},
36args: std.ArrayList(Id) = .empty,
37next_arg_index: u32 = 0,
38block_stack: std.ArrayList(*Block) = .empty,
39block_label: Id = .none,
40/// Whether the current block has been terminated by a terminator
41/// instruction (e.g. OpKill from inline assembly). When true, no further
42/// branch instructions should be emitted for the current block.
43block_terminated: bool = false,
44block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
45inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
46tracked_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,
47loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty,
48id_scratch: std.ArrayList(Id) = .empty,
1949
20const spec = @import("spec.zig");
21const Opcode = spec.Opcode;
22const Word = spec.Word;
23const Id = spec.Id;
24const IdRange = spec.IdRange;
25const StorageClass = spec.StorageClass;
50const big_int_bits = @bitSizeOf(u32);
2651
27const Module = @import("Module.zig");
28const Decl = Module.Decl;
29const Repr = Module.Repr;
30const InternMap = Module.InternMap;
31const PtrTypeMap = Module.PtrTypeMap;
52/// Data can be lowered into in two basic representations: indirect, which is when
53/// a type is stored in memory, and direct, which is how a type is stored when its
54/// a direct SPIR-V value.
55pub const Repr = enum {
56 /// A SPIR-V value as it would be used in operations.
57 direct,
58 /// A SPIR-V value as it is stored in memory.
59 indirect,
60};
3261
33const CodeGen = @This();
62/// A function or global, tracked here so the linker can order globals and build
63/// per-entry-point interface lists.
64pub const Decl = struct {
65 pub const Index = enum(u32) { _ };
66 pub const Kind = enum { func, global, invocation_global };
67
68 kind: Kind,
69 /// Result-id of the associated OpFunction / OpVariable / InvocationGlobal.
70 result_id: Id,
71 /// Range into `decl_deps` for this decl's dependencies.
72 begin_dep: usize = 0,
73 end_dep: usize = 0,
74 /// Whether an extern-function stub has been emitted.
75 has_extern_stub: bool = false,
76};
77
78pub const EntryPoint = struct {
79 decl_index: Decl.Index,
80 name: []const u8,
81 cc: std.builtin.CallingConvention,
82};
83
84const StructType = struct {
85 fields: []const Id,
86 ip_index: InternPool.Index,
87
88 const HashContext = struct {
89 pub fn hash(_: @This(), ty: StructType) u32 {
90 var hasher = std.hash.Wyhash.init(0);
91 hasher.update(std.mem.sliceAsBytes(ty.fields));
92 hasher.update(std.mem.asBytes(&ty.ip_index));
93 return @truncate(hasher.final());
94 }
95
96 pub fn eql(_: @This(), a: StructType, b: StructType, _: usize) bool {
97 return a.ip_index == b.ip_index and std.mem.eql(Id, a.fields, b.fields);
98 }
99 };
100};
34101
35102pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
36103 return comptime &.initMany(&.{
......@@ -43,60 +110,40 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
43110 });
44111}
45112
46pub const zig_call_abi_ver = 3;
47
48113const LoopSwitch = struct { cond_var: Id, continue_label: Id };
49114
50/// This type indicates the way that a block is terminated. The
51/// state of a particular block is used to track how a jump from
52/// inside the block must reach the outside.
115/// Pointer-typed AIR refs should resolve through `resolvePtr` to handle the
116/// `tracked_allocas` case explicitly at every use site.
117const Ptr = union(enum) {
118 id: Id,
119 /// Function-local pointer whose value lives in `tracked_allocas` rather
120 /// than a real OpVariable. `slot` is the current pointee value.
121 tracked: struct { id: Id, slot: *?Id },
122};
123
124/// Tracks how control flow leaves a Zig `block` under SPIR-V's structured
125/// control flow rules.
53126const Block = union(enum) {
54127 const Incoming = struct {
55128 src_label: Id,
56 /// Instruction that returns an u32 value of the
57 /// `Air.Inst.Index` that control flow should jump to.
129 /// Block index (u32) that control flow should jump to next.
58130 next_block: Id,
59131 };
60132
61133 const SelectionMerge = struct {
62 /// Incoming block from the `then` label.
63 /// Note that the incoming block from the `else` label is
64 /// either given by the next element in the stack.
65134 incoming: Incoming,
66 /// The label id of the cond_br's merge block.
67 /// For the top-most element in the stack, this
68 /// value is undefined.
135 /// Label of the cond_br's merge block (undefined for top-of-stack).
69136 merge_block: Id,
70137 };
71138
72 /// For a `selection` type block, we cannot use early exits, and we
73 /// must generate a 'merge ladder' of OpSelection instructions. To that end,
74 /// we keep a stack of the merges that still must be closed at the end of
75 /// a block.
76 ///
77 /// This entire structure basically just resembles a tree like
78 /// a x
79 /// \ /
80 /// b o merge
81 /// \ /
82 /// c o merge
83 /// \ /
84 /// o merge
85 /// /
86 /// o jump to next block
139 /// Selection blocks can't use early exits. Closing requires a "merge ladder"
140 /// of nested OpSelectionMerge instructions, one per pending merge.
87141 selection: struct {
88 /// In order to know which merges we still need to do, we need to keep
89 /// a stack of those.
90142 merge_stack: std.ArrayList(SelectionMerge) = .empty,
91143 },
92 /// For a `loop` type block, we can early-exit the block by
93 /// jumping to the loop exit node, and we don't need to generate
94 /// an entire stack of merges.
144 /// Loop blocks early-exit by jumping to the loop merge label.
95145 loop: struct {
96 /// The next block to jump to can be determined from any number
97 /// of conditions that jump to the loop exit.
98146 merges: std.ArrayList(Incoming) = .empty,
99 /// The label id of the loop's merge block.
100147 merge_block: Id,
101148 },
102149
......@@ -109,39 +156,36 @@ const Block = union(enum) {
109156 }
110157};
111158
112pt: Zcu.PerThread,
113air: Air,
114liveness: Air.Liveness,
115owner_nav: InternPool.Nav.Index,
116module: *Module,
117block_stack: std.ArrayList(*Block) = .empty,
118block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
119base_line: u32,
120block_label: Id = .none,
121/// Whether the current block has been terminated by a terminator
122/// instruction (e.g. OpKill from inline assembly). When true, no further
123/// branch instructions should be emitted for the current block.
124block_terminated: bool = false,
125next_arg_index: u32 = 0,
126args: std.ArrayList(Id) = .empty,
127virtual_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,
128inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
129loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty,
130id_scratch: std.ArrayList(Id) = .empty,
131prologue: Section = .{},
132body: Section = .{},
133
134159pub fn deinit(cg: *CodeGen) void {
135 const gpa = cg.module.gpa;
160 const gpa = cg.gpa;
136161 cg.block_stack.deinit(gpa);
137162 cg.block_results.deinit(gpa);
138163 cg.args.deinit(gpa);
139 cg.virtual_allocas.deinit(gpa);
164 cg.tracked_allocas.deinit(gpa);
140165 cg.inst_results.deinit(gpa);
141166 cg.loop_switches.deinit(gpa);
142167 cg.id_scratch.deinit(gpa);
143168 cg.prologue.deinit(gpa);
144169 cg.body.deinit(gpa);
170
171 cg.nav_link.deinit(gpa);
172 cg.uav_link.deinit(gpa);
173
174 cg.sections.extended_instruction_set.deinit(gpa);
175 cg.sections.memory_model.deinit(gpa);
176 cg.sections.execution_modes.deinit(gpa);
177 cg.sections.debug_strings.deinit(gpa);
178 cg.sections.debug_names.deinit(gpa);
179 cg.sections.annotations.deinit(gpa);
180 cg.sections.globals.deinit(gpa);
181 cg.sections.functions.deinit(gpa);
182
183 cg.struct_types.deinit(gpa);
184 cg.builtins.deinit(gpa);
185
186 cg.decls.deinit(gpa);
187 cg.decl_deps.deinit(gpa);
188 cg.entry_points.deinit(gpa);
145189}
146190
147191pub fn generate(
......@@ -157,19 +201,15 @@ pub fn generate(
157201
158202 var arena = std.heap.ArenaAllocator.init(gpa);
159203 defer arena.deinit();
160 var module: Module = .{
161 .gpa = gpa,
162 .arena = arena.allocator(),
163 .zcu = zcu,
164 };
165 defer module.deinit();
166204
167205 var cg: CodeGen = .{
168206 .pt = pt,
207 .gpa = gpa,
208 .arena = arena.allocator(),
209 .zcu = zcu,
169210 .air = air.*,
170211 .liveness = liveness.*.?,
171212 .owner_nav = nav,
172 .module = &module,
173213 .base_line = zcu.navSrcLine(nav),
174214 };
175215 defer cg.deinit();
......@@ -191,19 +231,15 @@ pub fn generateNav(
191231
192232 var arena = std.heap.ArenaAllocator.init(gpa);
193233 defer arena.deinit();
194 var module: Module = .{
195 .gpa = gpa,
196 .arena = arena.allocator(),
197 .zcu = zcu,
198 };
199 defer module.deinit();
200234
201235 var cg: CodeGen = .{
202236 .pt = pt,
237 .gpa = gpa,
238 .arena = arena.allocator(),
239 .zcu = zcu,
203240 .air = undefined,
204241 .liveness = undefined,
205242 .owner_nav = nav_index,
206 .module = &module,
207243 .base_line = zcu.navSrcLine(nav_index),
208244 };
209245 defer cg.deinit();
......@@ -217,11 +253,9 @@ pub fn generateNav(
217253}
218254
219255fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
220 const module = cg.module;
221
222 const owner_entry = module.nav_link.get(cg.owner_nav);
256 const owner_entry = cg.nav_link.get(cg.owner_nav);
223257 const owner_decl_index = owner_entry orelse return .{
224 .id_bound = module.next_result_id,
258 .id_bound = cg.next_result_id,
225259 .owner_nav = cg.owner_nav,
226260 .kind = .func,
227261 .decl_result_id = .none,
......@@ -239,14 +273,14 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
239273 .entry_points = &.{},
240274 };
241275
242 const owner_decl = module.declPtr(owner_decl_index);
276 const owner_decl = cg.declPtr(owner_decl_index);
243277
244278 var nav_refs: std.ArrayList(Mir.NavRef) = .empty;
245279 defer nav_refs.deinit(gpa);
246 var nav_it = module.nav_link.iterator();
280 var nav_it = cg.nav_link.iterator();
247281 while (nav_it.next()) |entry| {
248282 if (entry.key_ptr.* == cg.owner_nav) continue;
249 const decl = module.declPtr(entry.value_ptr.*);
283 const decl = cg.declPtr(entry.value_ptr.*);
250284 try nav_refs.append(gpa, .{
251285 .local_id = decl.result_id,
252286 .nav = entry.key_ptr.*,
......@@ -256,9 +290,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
256290
257291 var uav_refs: std.ArrayList(Mir.UavRef) = .empty;
258292 defer uav_refs.deinit(gpa);
259 var uav_it = module.uav_link.iterator();
293 var uav_it = cg.uav_link.iterator();
260294 while (uav_it.next()) |entry| {
261 const decl = module.declPtr(entry.value_ptr.*);
295 const decl = cg.declPtr(entry.value_ptr.*);
262296 try uav_refs.append(gpa, .{
263297 .local_id = decl.result_id,
264298 .val = entry.key_ptr.*[0],
......@@ -272,9 +306,9 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
272306 var internal_globals: std.ArrayList(Id) = .empty;
273307 defer internal_globals.deinit(gpa);
274308
275 const deps = module.decl_deps.items[owner_decl.begin_dep..owner_decl.end_dep];
309 const deps = cg.decl_deps.items[owner_decl.begin_dep..owner_decl.end_dep];
276310 for (deps) |dep_index| {
277 const dep_decl = module.declPtr(dep_index);
311 const dep_decl = cg.declPtr(dep_index);
278312 var found = false;
279313 nav_it.index = 0;
280314 while (nav_it.next()) |entry| {
......@@ -294,10 +328,10 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
294328
295329 var ep_list: std.ArrayList(Mir.EntryPoint) = .empty;
296330 defer ep_list.deinit(gpa);
297 var ep_it = module.entry_points.iterator();
331 var ep_it = cg.entry_points.iterator();
298332 while (ep_it.next()) |entry| {
299333 const ep = entry.value_ptr;
300 const ep_decl = module.declPtr(ep.decl_index);
334 const ep_decl = cg.declPtr(ep.decl_index);
301335 try ep_list.append(gpa, .{
302336 .local_id = ep_decl.result_id,
303337 .name = try gpa.dupe(u8, ep.name),
......@@ -306,17 +340,17 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
306340 }
307341
308342 return .{
309 .id_bound = module.next_result_id,
343 .id_bound = cg.next_result_id,
310344 .owner_nav = cg.owner_nav,
311345 .kind = owner_decl.kind,
312346 .decl_result_id = owner_decl.result_id,
313 .extended_instruction_set = try module.sections.extended_instruction_set.instructions.toOwnedSlice(gpa),
314 .globals = try module.sections.globals.instructions.toOwnedSlice(gpa),
315 .functions = try module.sections.functions.instructions.toOwnedSlice(gpa),
316 .annotations = try module.sections.annotations.instructions.toOwnedSlice(gpa),
317 .debug_names = try module.sections.debug_names.instructions.toOwnedSlice(gpa),
318 .debug_strings = try module.sections.debug_strings.instructions.toOwnedSlice(gpa),
319 .execution_modes = try module.sections.execution_modes.instructions.toOwnedSlice(gpa),
347 .extended_instruction_set = try cg.sections.extended_instruction_set.instructions.toOwnedSlice(gpa),
348 .globals = try cg.sections.globals.instructions.toOwnedSlice(gpa),
349 .functions = try cg.sections.functions.instructions.toOwnedSlice(gpa),
350 .annotations = try cg.sections.annotations.instructions.toOwnedSlice(gpa),
351 .debug_names = try cg.sections.debug_names.instructions.toOwnedSlice(gpa),
352 .debug_strings = try cg.sections.debug_strings.instructions.toOwnedSlice(gpa),
353 .execution_modes = try cg.sections.execution_modes.instructions.toOwnedSlice(gpa),
320354 .nav_refs = try nav_refs.toOwnedSlice(gpa),
321355 .uav_refs = try uav_refs.toOwnedSlice(gpa),
322356 .decl_deps = try decl_deps.toOwnedSlice(gpa),
......@@ -325,11 +359,365 @@ fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir {
325359 };
326360}
327361
362fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
363 const zcu = cg.zcu;
364 return cg.air.typeOf(inst, &zcu.intern_pool);
365}
366
367fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
368 const zcu = cg.zcu;
369 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
370}
371
372/// Does not generate the nav.
373pub fn resolveNav(cg: *CodeGen, ip: *InternPool, nav_index: InternPool.Nav.Index) !Decl.Index {
374 const entry = try cg.nav_link.getOrPut(cg.gpa, nav_index);
375 if (!entry.found_existing) {
376 const nav = ip.getNav(nav_index);
377 // TODO: Extern fn?
378 const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type))
379 .func
380 else switch (nav.resolved.?.@"addrspace") {
381 .generic => .invocation_global,
382 else => .global,
383 };
384 entry.value_ptr.* = try cg.allocDecl(kind);
385 }
386
387 return entry.value_ptr.*;
388}
389
390pub fn allocIds(cg: *CodeGen, n: u32) spec.IdRange {
391 defer cg.next_result_id += n;
392 return .{ .base = cg.next_result_id, .len = n };
393}
394
395pub fn allocId(cg: *CodeGen) Id {
396 return cg.allocIds(1).at(0);
397}
398
399pub fn idBound(cg: *const CodeGen) Word {
400 return cg.next_result_id;
401}
402
403pub fn addEntryPointDeps(
404 cg: *CodeGen,
405 decl_index: Decl.Index,
406 seen: *std.bit_set.Dynamic,
407 interface: *std.array_list.Managed(Id),
408) !void {
409 const decl = cg.declPtr(decl_index);
410 const deps = cg.decl_deps.items[decl.begin_dep..decl.end_dep];
411
412 if (seen.isSet(@intFromEnum(decl_index))) {
413 return;
414 }
415
416 seen.set(@intFromEnum(decl_index));
417
418 if (decl.kind == .global) {
419 try interface.append(decl.result_id);
420 }
421
422 for (deps) |dep| {
423 try cg.addEntryPointDeps(dep, seen, interface);
424 }
425}
426
427pub fn importInstructionSet(cg: *CodeGen, set: spec.InstructionSet) !Id {
428 assert(set != .core);
429 const result_id = cg.allocId();
430 try cg.sections.extended_instruction_set.emit(cg.gpa, .OpExtInstImport, .{
431 .id_result = result_id,
432 .name = @tagName(set),
433 });
434 return result_id;
435}
436
437pub fn boolType(cg: *CodeGen) !Id {
438 const result_id = cg.allocId();
439 try cg.sections.globals.emit(cg.gpa, .OpTypeBool, .{
440 .id_result = result_id,
441 });
442 return result_id;
443}
444
445pub fn voidType(cg: *CodeGen) !Id {
446 const result_id = cg.allocId();
447 try cg.sections.globals.emit(cg.gpa, .OpTypeVoid, .{
448 .id_result = result_id,
449 });
450 try cg.debugName(result_id, "void");
451 return result_id;
452}
453
454pub fn opaqueType(cg: *CodeGen, name: []const u8) !Id {
455 const result_id = cg.allocId();
456 try cg.sections.globals.emit(cg.gpa, .OpTypeOpaque, .{
457 .id_result = result_id,
458 .literal_string = name,
459 });
460 try cg.debugName(result_id, name);
461 return result_id;
462}
463
464pub fn backingIntBits(cg: *const CodeGen, bits: u16) struct { u16, bool } {
465 assert(bits != 0);
466 const target = cg.zcu.getTarget();
467 const ints = [_]struct { bits: u16, enabled: bool }{
468 .{ .bits = 8, .enabled = target.cpu.has(.spirv, .int8) },
469 .{ .bits = 16, .enabled = target.cpu.has(.spirv, .int16) },
470 .{ .bits = 32, .enabled = true },
471 .{ .bits = 64, .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64 },
472 };
473
474 for (ints) |int| {
475 if (bits <= int.bits and int.enabled) return .{ int.bits, false };
476 }
477
478 return .{ std.mem.alignForward(u16, bits, big_int_bits), true };
479}
480
481pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id {
482 assert(bits > 0);
483
484 const target = cg.zcu.getTarget();
485 const actual_signedness = switch (target.os.tag) {
486 // Kernel only supports unsigned ints.
487 .opencl, .amdhsa => .unsigned,
488 else => signedness,
489 };
490 const backing_bits, const big_int = cg.backingIntBits(bits);
491 if (big_int) {
492 const u32_ty = try cg.intType(.unsigned, 32);
493 const len_id = cg.allocId();
494 try cg.sections.globals.emit(cg.gpa, .OpConstant, .{
495 .id_result_type = u32_ty,
496 .id_result = len_id,
497 .value = .{ .uint32 = backing_bits / big_int_bits },
498 });
499 return cg.arrayType(len_id, u32_ty);
500 }
501
502 const result_id = cg.allocId();
503 try cg.sections.globals.emit(cg.gpa, .OpTypeInt, .{
504 .id_result = result_id,
505 .width = backing_bits,
506 .signedness = switch (actual_signedness) {
507 .signed => 1,
508 .unsigned => 0,
509 },
510 });
511 switch (actual_signedness) {
512 .signed => try cg.debugNameFmt(result_id, "i{}", .{backing_bits}),
513 .unsigned => try cg.debugNameFmt(result_id, "u{}", .{backing_bits}),
514 }
515 return result_id;
516}
517
518pub fn floatType(cg: *CodeGen, bits: u16) !Id {
519 assert(bits > 0);
520 const result_id = cg.allocId();
521 try cg.sections.globals.emit(cg.gpa, .OpTypeFloat, .{
522 .id_result = result_id,
523 .width = bits,
524 });
525 try cg.debugNameFmt(result_id, "f{}", .{bits});
526 return result_id;
527}
528
529pub fn vectorType(cg: *CodeGen, len: u32, child_ty_id: Id) !Id {
530 const result_id = cg.allocId();
531 try cg.sections.globals.emit(cg.gpa, .OpTypeVector, .{
532 .id_result = result_id,
533 .component_type = child_ty_id,
534 .component_count = len,
535 });
536 return result_id;
537}
538
539pub fn arrayType(cg: *CodeGen, len_id: Id, child_ty_id: Id) !Id {
540 const result_id = cg.allocId();
541 try cg.sections.globals.emit(cg.gpa, .OpTypeArray, .{
542 .id_result = result_id,
543 .element_type = child_ty_id,
544 .length = len_id,
545 });
546 return result_id;
547}
548
549pub fn ptrType(cg: *CodeGen, child_ty_id: Id, storage_class: spec.StorageClass) !Id {
550 const result_id = cg.allocId();
551 try cg.sections.globals.emit(cg.gpa, .OpTypePointer, .{
552 .id_result = result_id,
553 .storage_class = storage_class,
554 .type = child_ty_id,
555 });
556 return result_id;
557}
558
559pub fn structType(
560 cg: *CodeGen,
561 types: []const Id,
562 maybe_names: ?[]const []const u8,
563 ip_index: InternPool.Index,
564) !Id {
565 const actual_ip_index = if (cg.zcu.comp.config.root_strip) .none else ip_index;
566
567 if (cg.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id;
568 const result_id = cg.allocId();
569 const types_dup = try cg.arena.dupe(Id, types);
570 try cg.sections.globals.emit(cg.gpa, .OpTypeStruct, .{
571 .id_result = result_id,
572 .id_ref = types_dup,
573 });
574
575 if (maybe_names) |names| {
576 assert(names.len == types.len);
577 for (names, 0..) |name, i| {
578 try cg.memberDebugName(result_id, @intCast(i), name);
579 }
580 }
581
582 try cg.struct_types.put(
583 cg.gpa,
584 .{ .fields = types_dup, .ip_index = actual_ip_index },
585 result_id,
586 );
587 return result_id;
588}
589
590pub fn functionType(cg: *CodeGen, return_ty_id: Id, param_type_ids: []const Id) !Id {
591 const result_id = cg.allocId();
592 try cg.sections.globals.emit(cg.gpa, .OpTypeFunction, .{
593 .id_result = result_id,
594 .return_type = return_ty_id,
595 .id_ref_2 = param_type_ids,
596 });
597 return result_id;
598}
599
600pub fn constUndef(cg: *CodeGen, ty_id: Id) !Id {
601 const result_id = cg.allocId();
602 try cg.sections.globals.emit(cg.gpa, .OpUndef, .{
603 .id_result_type = ty_id,
604 .id_result = result_id,
605 });
606 return result_id;
607}
608
609pub fn constNull(cg: *CodeGen, ty_id: Id) !Id {
610 const result_id = cg.allocId();
611 try cg.sections.globals.emit(cg.gpa, .OpConstantNull, .{
612 .id_result_type = ty_id,
613 .id_result = result_id,
614 });
615 return result_id;
616}
617
618pub fn decorate(
619 cg: *CodeGen,
620 target: Id,
621 decoration: spec.Decoration.Extended,
622) !void {
623 try cg.sections.annotations.emit(cg.gpa, .OpDecorate, .{
624 .target = target,
625 .decoration = decoration,
626 });
627}
628
629pub fn decorateMember(
630 cg: *CodeGen,
631 structure_type: Id,
632 member: u32,
633 decoration: spec.Decoration.Extended,
634) !void {
635 try cg.sections.annotations.emit(cg.gpa, .OpMemberDecorate, .{
636 .structure_type = structure_type,
637 .member = member,
638 .decoration = decoration,
639 });
640}
641
642pub fn allocDecl(cg: *CodeGen, kind: Decl.Kind) !Decl.Index {
643 try cg.decls.append(cg.gpa, .{
644 .kind = kind,
645 .result_id = cg.allocId(),
646 });
647
648 return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(cg.decls.items.len - 1))));
649}
650
651pub fn declPtr(cg: *CodeGen, index: Decl.Index) *Decl {
652 return &cg.decls.items[@intFromEnum(index)];
653}
654
655pub fn debugName(cg: *CodeGen, target: Id, name: []const u8) !void {
656 if (cg.zcu.comp.config.root_strip) return;
657 try cg.sections.debug_names.emit(cg.gpa, .OpName, .{
658 .target = target,
659 .name = name,
660 });
661}
662
663pub fn debugNameFmt(cg: *CodeGen, target: Id, comptime fmt: []const u8, args: anytype) !void {
664 if (cg.zcu.comp.config.root_strip) return;
665 const name = try std.fmt.allocPrint(cg.gpa, fmt, args);
666 defer cg.gpa.free(name);
667 try cg.debugName(target, name);
668}
669
670pub fn memberDebugName(cg: *CodeGen, target: Id, member: u32, name: []const u8) !void {
671 if (cg.zcu.comp.config.root_strip) return;
672 try cg.sections.debug_names.emit(cg.gpa, .OpMemberName, .{
673 .type = target,
674 .member = member,
675 .name = name,
676 });
677}
678
679pub fn storageClass(cg: *const CodeGen, as: std.lang.AddressSpace) spec.StorageClass {
680 const target = cg.zcu.getTarget();
681 return switch (as) {
682 .generic => .function,
683 .global => switch (target.os.tag) {
684 .opencl, .amdhsa => .cross_workgroup,
685 else => .storage_buffer,
686 },
687 .push_constant => .push_constant,
688 .output => .output,
689 .uniform => .uniform,
690 .storage_buffer => .storage_buffer,
691 .physical_storage_buffer => .physical_storage_buffer,
692 .constant => .uniform_constant,
693 .shared => .workgroup,
694 .local => .function,
695 .input => .input,
696 .gs,
697 .fs,
698 .ss,
699 .far,
700 .param,
701 .flash,
702 .flash1,
703 .flash2,
704 .flash3,
705 .flash4,
706 .flash5,
707 .cog,
708 .lut,
709 .hub,
710 .externref,
711 .funcref,
712 => unreachable,
713 };
714}
715
328716const Error = error{ AlreadyReported, OutOfMemory };
329717
330718pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
331 const gpa = cg.module.gpa;
332 const zcu = cg.module.zcu;
719 const gpa = cg.gpa;
720 const zcu = cg.zcu;
333721 const ip = &zcu.intern_pool;
334722 const target = zcu.getTarget();
335723
......@@ -337,19 +725,22 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
337725 const val = zcu.navValue(cg.owner_nav);
338726 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);
343 const decl = cg.module.declPtr(spv_decl_index);
733 const spv_decl_index = try cg.resolveNav(ip, cg.owner_nav);
734 const decl = cg.declPtr(spv_decl_index);
344735 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
347738 switch (decl.kind) {
348739 .func => {
349740 if (nav.resolved.?.is_extern_decl) {
350741 _ = try cg.resolveType(ty, .direct);
351742 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;
353744 return;
354745 }
355746
......@@ -357,7 +748,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
357748 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
358749 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;
361752 const prototype_ty_id = try cg.resolveType(ty, .direct);
362753 try cg.prologue.emit(gpa, .OpFunction, .{
363754 .id_result_type = return_ty_id,
......@@ -368,14 +759,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
368759 .function_control = .{},
369760 });
370761
371 comptime assert(zig_call_abi_ver == 3);
372762 try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len);
373763 for (fn_info.param_types.get(ip)) |param_ty_index| {
374764 const param_ty: Type = .fromInterned(param_ty_index);
375765 if (!param_ty.hasRuntimeBits(zcu)) continue;
376766
377767 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();
379769 try cg.prologue.emit(gpa, .OpFunctionParameter, .{
380770 .id_result_type = param_type_id,
381771 .id_result = arg_result_id,
......@@ -384,7 +774,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
384774 }
385775
386776 // 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
389779 // The root block of a function declaration should appear before OpVariable instructions,
390780 // so it is generated into the function's prologue.
......@@ -400,26 +790,26 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
400790 try cg.body.emit(gpa, .OpUnreachable, {});
401791 try cg.body.emit(gpa, .OpFunctionEnd, {});
402792 // Append the actual code into the functions section.
403 try cg.module.sections.functions.append(gpa, cg.prologue);
404 try cg.module.sections.functions.append(gpa, cg.body);
793 try cg.sections.functions.append(gpa, cg.prologue);
794 try cg.sections.functions.append(gpa, cg.body);
405795
406796 // Temporarily generate a test kernel declaration if this is a test function.
407797 if (is_test) {
408798 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);
409799 }
410800
411 try cg.module.debugName(func_result_id, nav.fqn.toSlice(ip));
801 try cg.debugName(func_result_id, nav.fqn.toSlice(ip));
412802 },
413803 .global => {
414804 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");
417807 assert(storage_class != .generic); // These should be instance globals
418808
419809 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, .{
423813 .id_result_type = ptr_ty_id,
424814 .id_result = result_id,
425815 .storage_class = storage_class,
......@@ -430,11 +820,11 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
430820 switch (storage_class) {
431821 .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => {
432822 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);
434824 }
435825
436826 if (ty.hasRuntimeBits(zcu)) {
437 try cg.module.decorate(ptr_ty_id, .{
827 try cg.decorate(ptr_ty_id, .{
438828 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },
439829 });
440830 try cg.decorateLayout(ty, ty_id);
......@@ -448,23 +838,23 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
448838 if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) {
449839 return cg.fail("storage class must be one of (output, input, uniform_constant) but is {s}", .{@tagName(storage_class)});
450840 }
451 try cg.module.decorate(result_id, .{
841 try cg.decorate(result_id, .{
452842 .location = .{ .location = location },
453843 });
454844 },
455845 .flat => |location| {
456 try cg.module.decorate(result_id, .{ .location = .{ .location = location } });
457 try cg.module.decorate(result_id, .flat);
846 try cg.decorate(result_id, .{ .location = .{ .location = location } });
847 try cg.decorate(result_id, .flat);
458848 },
459849 .descriptor => |descriptor| {
460850 if (storage_class != .storage_buffer and storage_class != .uniform and storage_class != .uniform_constant) {
461851 return cg.fail("storage class must be one of (storage_buffer, uniform, uniform_constant) but is {s}", .{@tagName(storage_class)});
462852 }
463 try cg.module.decorate(result_id, .{
853 try cg.decorate(result_id, .{
464854 .binding = .{ .binding_point = descriptor.binding },
465855 });
466856
467 try cg.module.decorate(result_id, .{
857 try cg.decorate(result_id, .{
468858 .descriptor_set = .{ .descriptor_set = descriptor.set },
469859 });
470860 },
......@@ -474,10 +864,10 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
474864 }
475865
476866 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 } });
478868 }
479869
480 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
870 try cg.debugName(result_id, nav.fqn.toSlice(ip));
481871 },
482872 .invocation_global => {
483873 // `@extern()` produces an invocation_global whose value is a
......@@ -488,18 +878,18 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
488878 if (ptr_key.base_addr != .nav or ptr_key.byte_offset != 0) break :alias;
489879 const underlying_nav = ip.getNav(ptr_key.base_addr.nav);
490880 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;
492882 return;
493883 }
494884
495885 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
498888 // TODO: Combine with resolveAnonDecl?
499889 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();
503893 try cg.prologue.emit(gpa, .OpFunction, .{
504894 .id_result_type = try cg.resolveType(.void, .direct),
505895 .id_result = initializer_id,
......@@ -507,7 +897,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
507897 .function_type = initializer_proto_ty_id,
508898 });
509899
510 const root_block_id = cg.module.allocId();
900 const root_block_id = cg.allocId();
511901 try cg.prologue.emit(gpa, .OpLabel, .{
512902 .id_result = root_block_id,
513903 });
......@@ -521,33 +911,33 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
521911
522912 try cg.body.emit(gpa, .OpReturn, {});
523913 try cg.body.emit(gpa, .OpFunctionEnd, {});
524 try cg.module.sections.functions.append(gpa, cg.prologue);
525 try cg.module.sections.functions.append(gpa, cg.body);
914 try cg.sections.functions.append(gpa, cg.prologue);
915 try cg.sections.functions.append(gpa, cg.body);
526916
527 try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
528 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
917 try cg.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(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, .{
531921 .id_result_type = ptr_ty_id,
532922 .id_result = result_id,
533 .set = try cg.module.importInstructionSet(.zig),
923 .set = try cg.importInstructionSet(.zig),
534924 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
535925 .id_ref_4 = &.{initializer_id},
536926 });
537927 },
538928 }
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;
541931}
542932
543933fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
544 const zcu = cg.module.zcu;
934 const zcu = cg.zcu;
545935 const ip = &zcu.intern_pool;
546936 switch (ty.zigTypeTag(zcu)) {
547937 .array => {
548938 const elem_ty = ty.childType(zcu);
549939 if (!elem_ty.hasRuntimeBits(zcu)) return;
550 try cg.module.decorate(ty_id, .{
940 try cg.decorate(ty_id, .{
551941 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
552942 });
553943 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 {
556946 const elem_ty = ty.childType(zcu);
557947 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
558948 if (cg.isSpvVector(ty)) return;
559 try cg.module.decorate(ty_id, .{
949 try cg.decorate(ty_id, .{
560950 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
561951 });
562952 },
......@@ -570,7 +960,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
570960 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
571961 if (!field_ty.hasRuntimeBits(zcu)) continue;
572962 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 } });
574964 try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect));
575965 member += 1;
576966 }
......@@ -598,13 +988,13 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
598988 const u8_id = try cg.resolveType(.u8, .direct);
599989 if (layout.payload_padding_size != 0) {
600990 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
601 const arr_id = try cg.module.arrayType(len_id, u8_id);
602 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
991 const arr_id = try cg.arrayType(len_id, u8_id);
992 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
603993 }
604994 if (layout.padding_size != 0) {
605995 const len_id = try cg.constInt(.u32, layout.padding_size);
606 const arr_id = try cg.module.arrayType(len_id, u8_id);
607 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
996 const arr_id = try cg.arrayType(len_id, u8_id);
997 try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
608998 }
609999 },
6101000 .optional => {
......@@ -621,7 +1011,7 @@ fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
6211011
6221012pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
6231013 @branchHint(.cold);
624 return cg.module.zcu.codegenFail(cg.owner_nav, format, args);
1014 return cg.zcu.codegenFail(cg.owner_nav, format, args);
6251015}
6261016
6271017pub 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 {
6311021/// This imports the "default" extended instruction set for the target
6321022/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.
6331023fn importExtendedSet(cg: *CodeGen) !Id {
634 const target = cg.module.zcu.getTarget();
1024 const target = cg.zcu.getTarget();
6351025 return switch (target.os.tag) {
636 .opencl, .amdhsa => try cg.module.importInstructionSet(.@"OpenCL.std"),
637 .vulkan, .opengl => try cg.module.importInstructionSet(.@"GLSL.std.450"),
1026 .opencl, .amdhsa => try cg.importInstructionSet(.@"OpenCL.std"),
1027 .vulkan, .opengl => try cg.importInstructionSet(.@"GLSL.std.450"),
6381028 else => unreachable,
6391029 };
6401030}
6411031
6421032/// Fetch the result-id for a previously generated instruction or constant.
6431033fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
644 const zcu = cg.module.zcu;
1034 const zcu = cg.zcu;
6451035 const ip = &zcu.intern_pool;
6461036 if (inst.toInterned()) |val_ip_index| {
6471037 const ty = cg.typeOf(inst);
......@@ -652,9 +1042,9 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
6521042 .func => |func| func.owner_nav,
6531043 else => unreachable,
6541044 };
655 const spv_decl_index = try cg.module.resolveNav(ip, fn_nav);
656 try cg.module.decl_deps.append(cg.module.gpa, spv_decl_index);
657 const decl = cg.module.declPtr(spv_decl_index);
1045 const spv_decl_index = try cg.resolveNav(ip, fn_nav);
1046 try cg.decl_deps.append(cg.gpa, spv_decl_index);
1047 const decl = cg.declPtr(spv_decl_index);
6581048 if (val_key == .@"extern") {
6591049 const nav = ip.getNav(fn_nav);
6601050 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
......@@ -670,22 +1060,22 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
6701060}
6711061
6721062fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
673 const gpa = cg.module.gpa;
1063 const gpa = cg.gpa;
6741064
6751065 // 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;
6781068 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
6791069 const ty_id = try cg.resolveType(ty, .indirect);
6801070
6811071 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 });
6831073 if (entry.found_existing) {
6841074 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;
6861076 }
6871077
688 const spv_decl_index = try cg.module.allocDecl(.invocation_global);
1078 const spv_decl_index = try cg.allocDecl(.invocation_global);
6891079 try cg.addFunctionDep(spv_decl_index, .function);
6901080 entry.value_ptr.* = spv_decl_index;
6911081 break :blk spv_decl_index;
......@@ -697,7 +1087,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
6971087 // constant lowering of this value will need to be deferred to an initializer similar to
6981088 // 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
7021092 {
7031093 // 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 {
7191109 }
7201110
7211111 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();
7251115 try cg.prologue.emit(gpa, .OpFunction, .{
7261116 .id_result_type = try cg.resolveType(.void, .direct),
7271117 .id_result = initializer_id,
7281118 .function_control = .{},
7291119 .function_type = initializer_proto_ty_id,
7301120 });
731 const root_block_id = cg.module.allocId();
1121 const root_block_id = cg.allocId();
7321122 try cg.prologue.emit(gpa, .OpLabel, .{
7331123 .id_result = root_block_id,
7341124 });
......@@ -743,16 +1133,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
7431133 try cg.body.emit(gpa, .OpReturn, {});
7441134 try cg.body.emit(gpa, .OpFunctionEnd, {});
7451135
746 try cg.module.sections.functions.append(gpa, cg.prologue);
747 try cg.module.sections.functions.append(gpa, cg.body);
1136 try cg.sections.functions.append(gpa, cg.prologue);
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);
752 try cg.module.sections.globals.emit(gpa, .OpExtInst, .{
1141 const fn_decl_ptr_ty_id = try cg.ptrType(ty_id, .function);
1142 try cg.sections.globals.emit(gpa, .OpExtInst, .{
7531143 .id_result_type = fn_decl_ptr_ty_id,
7541144 .id_result = result_id,
755 .set = try cg.module.importInstructionSet(.zig),
1145 .set = try cg.importInstructionSet(.zig),
7561146 .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
7571147 .id_ref_4 = &.{initializer_id},
7581148 });
......@@ -761,15 +1151,21 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
7611151 return result_id;
7621152}
7631153
764fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void {
765 const gpa = cg.module.gpa;
766 const target = cg.module.zcu.getTarget();
1154fn resolvePtr(cg: *CodeGen, ref: Air.Inst.Ref) !Ptr {
1155 const id = try cg.resolve(ref);
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();
7671163 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);
7691165 } else {
7701166 // Before version 1.4, the interface’s storage classes are limited to the Input and Output
7711167 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);
7731169 }
7741170 }
7751171}
......@@ -779,25 +1175,11 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St
7791175/// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to
7801176/// keep track of the previous block.
7811177fn 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 });
7831179 cg.block_label = label;
7841180 cg.block_terminated = false;
7851181}
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
8011183const ArithmeticTypeInfo = struct {
8021184 const Class = enum {
8031185 bool,
......@@ -835,8 +1217,8 @@ const ArithmeticTypeInfo = struct {
8351217};
8361218
8371219fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
838 const zcu = cg.module.zcu;
839 const target = cg.module.zcu.getTarget();
1220 const zcu = cg.zcu;
1221 const target = cg.zcu.getTarget();
8401222 var scalar_ty = ty.scalarType(zcu);
8411223 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {
8421224 scalar_ty = scalar_ty.intTagType(zcu);
......@@ -845,7 +1227,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8451227 return switch (scalar_ty.zigTypeTag(zcu)) {
8461228 .bool => .{
8471229 .bits = 1, // Doesn't matter for this class.
848 .backing_bits = cg.module.backingIntBits(1).@"0",
1230 .backing_bits = cg.backingIntBits(1).@"0",
8491231 .vector_len = vector_len,
8501232 .signedness = .unsigned, // Technically, but doesn't matter for this class.
8511233 .class = .bool,
......@@ -860,7 +1242,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8601242 .int => blk: {
8611243 const int_info = scalar_ty.intInfo(zcu);
8621244 // 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);
8641246 break :blk .{
8651247 .bits = int_info.bits,
8661248 .backing_bits = backing_bits,
......@@ -880,8 +1262,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
8801262
8811263/// Checks whether the type can be directly translated to SPIR-V vectors
8821264fn isSpvVector(cg: *CodeGen, ty: Type) bool {
883 const zcu = cg.module.zcu;
884 const target = cg.module.zcu.getTarget();
1265 const zcu = cg.zcu;
1266 const target = cg.zcu.getTarget();
8851267 if (ty.zigTypeTag(zcu) != .vector) return false;
8861268
8871269 // TODO: This check must be expanded for types that can be represented
......@@ -909,23 +1291,34 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {
9091291
9101292/// Emits a bool constant in a particular representation.
9111293fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {
912 return switch (repr) {
913 .indirect => cg.constInt(.u1, @intFromBool(value)),
914 .direct => cg.module.constBool(value),
915 };
1294 switch (repr) {
1295 .indirect => return cg.constInt(.u1, @intFromBool(value)),
1296 .direct => {
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 }
9161309}
9171310
9181311/// Emits an integer constant.
919/// This function, unlike Module.constInt, takes care to bitcast
1312/// This function, unlike cg.constInt, takes care to bitcast
9201313/// the value to an unsigned int first for Kernels.
9211314fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
922 const gpa = cg.module.gpa;
923 const zcu = cg.module.zcu;
924 const target = cg.module.zcu.getTarget();
1315 const gpa = cg.gpa;
1316 const zcu = cg.zcu;
1317 const target = cg.zcu.getTarget();
9251318 const scalar_ty = ty.scalarType(zcu);
9261319 const int_info = scalar_ty.intInfo(zcu);
9271320 // 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);
9291322 assert(backing_bits != 0); // u0 is comptime
9301323
9311324 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);
......@@ -939,7 +1332,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
9391332 .signed => @bitCast(@as(i64, @intCast(value))),
9401333 .unsigned => @as(u64, @intCast(value)),
9411334 };
942 const n_limbs = backing_bits / Module.big_int_bits;
1335 const n_limbs = backing_bits / big_int_bits;
9431336 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;
9441337 const scratch_top = cg.id_scratch.items.len;
9451338 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
......@@ -979,61 +1372,45 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
9791372 },
9801373 };
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
9841382 if (!ty.isVector(zcu)) return result_id;
9851383 return cg.constructCompositeSplat(ty, result_id);
9861384}
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
10171386/// Construct a composite value from its constituents.
10181387/// In logical addressing mode (Vulkan/OpenGL), OpCompositeConstruct cannot accept
10191388/// pointer operands, so for struct types we use alloc, store for each field and load instead.
10201389pub 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| {
10241396 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);
10261398 const var_id = try cg.alloc(result_ty_id, null);
10271399 for (fields, constituents, 0..) |field_ty_id, constituent, i| {
1028 const field_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);
1029 const index_id = try cg.module.constant(u32_ty_id, .{ .uint32 = @intCast(i) });
1400 const field_ptr_ty_id = try cg.ptrType(field_ty_id, .function);
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 });
10301407 const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id});
10311408 try cg.body.emit(gpa, .OpStore, .{
10321409 .pointer = field_ptr,
10331410 .object = constituent,
10341411 });
10351412 }
1036 const result_id = cg.module.allocId();
1413 const result_id = cg.allocId();
10371414 try cg.body.emit(gpa, .OpLoad, .{
10381415 .id_result_type = result_ty_id,
10391416 .id_result = result_id,
......@@ -1042,7 +1419,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
10421419 return result_id;
10431420 }
10441421
1045 const result_id = cg.module.allocId();
1422 const result_id = cg.allocId();
10461423 try cg.body.emit(gpa, .OpCompositeConstruct, .{
10471424 .id_result_type = result_ty_id,
10481425 .id_result = result_id,
......@@ -1054,8 +1431,8 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
10541431/// Construct a composite at runtime with all lanes set to the same value.
10551432/// ty must be an aggregate type.
10561433fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
1057 const gpa = cg.module.gpa;
1058 const zcu = cg.module.zcu;
1434 const gpa = cg.gpa;
1435 const zcu = cg.zcu;
10591436 const n: usize = @intCast(ty.arrayLen(zcu));
10601437
10611438 const scratch_top = cg.id_scratch.items.len;
......@@ -1075,24 +1452,17 @@ fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
10751452//
10761453/// This function should only be called during function code generation.
10771454fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1078 const gpa = cg.module.gpa;
1079
1080 // Note: Using intern_map can only be used with constants that DO NOT generate any runtime code!!
1081 // Ideally that should be all constants in the future, or it should be cleaned up somehow. For
1082 // now, only use the intern_map on case-by-case basis by breaking to :cache.
1083 if (cg.module.intern_map.get(.{ val.toIntern(), repr })) |id| {
1084 return id;
1085 }
1455 const gpa = cg.gpa;
10861456
10871457 const pt = cg.pt;
1088 const zcu = cg.module.zcu;
1089 const target = cg.module.zcu.getTarget();
1458 const zcu = cg.zcu;
1459 const target = cg.zcu.getTarget();
10901460 const result_ty_id = try cg.resolveType(ty, repr);
10911461 const ip = &zcu.intern_pool;
10921462
10931463 log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });
10941464 if (val.isUndef(zcu)) {
1095 return cg.module.constUndef(result_ty_id);
1465 return cg.constUndef(result_ty_id);
10961466 }
10971467
10981468 const cacheable_id = cache: {
......@@ -1133,9 +1503,25 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
11331503 },
11341504 .int => {
11351505 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);
11371507 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);
11391525 }
11401526 if (ty.isSignedInt(zcu)) {
11411527 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 {
11511537 80, 128 => unreachable, // TODO
11521538 else => unreachable,
11531539 };
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;
11551547 },
11561548 .err => |err| {
11571549 const value = try pt.getErrorValue(err.name);
......@@ -1218,7 +1610,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
12181610 if (maybe_payload_val) |payload_val| {
12191611 return try cg.constant(payload_ty, payload_val, .indirect);
12201612 } else {
1221 break :cache try cg.module.constNull(result_ty_id);
1613 break :cache try cg.constNull(result_ty_id);
12221614 }
12231615 }
12241616
......@@ -1229,7 +1621,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
12291621 const payload_id = if (maybe_payload_val) |payload_val|
12301622 try cg.constant(payload_ty, payload_val, .indirect)
12311623 else
1232 try cg.module.constUndef(try cg.resolveType(payload_ty, .indirect));
1624 try cg.constUndef(try cg.resolveType(payload_ty, .indirect));
12331625
12341626 const comp_ty_id = try cg.resolveType(ty, .direct);
12351627 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 {
13391731 .memoized_call => unreachable,
13401732 }
13411733 };
1342
1343 try cg.module.intern_map.putNoClobber(gpa, .{ val.toIntern(), repr }, cacheable_id);
1344
13451734 return cacheable_id;
13461735}
13471736
13481737fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
13491738 const pt = cg.pt;
1350 const zcu = cg.module.zcu;
1351 const gpa = cg.module.gpa;
1739 const zcu = cg.zcu;
1740 const gpa = cg.gpa;
13521741
13531742 if (ptr_val.isUndef(zcu)) {
13541743 const result_ty = ptr_val.typeOf(zcu);
13551744 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);
13571746 }
13581747
13591748 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -1364,9 +1753,9 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
13641753}
13651754
13661755fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1367 const gpa = cg.module.gpa;
1756 const gpa = cg.gpa;
13681757 const pt = cg.pt;
1369 const zcu = cg.module.zcu;
1758 const zcu = cg.zcu;
13701759 const target = zcu.getTarget();
13711760 switch (derivation) {
13721761 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
......@@ -1383,7 +1772,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
13831772 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
13841773 // that is not implemented by Mesa yet. Therefore, just generate it
13851774 // as a runtime operation.
1386 const result_ptr_id = cg.module.allocId();
1775 const result_ptr_id = cg.allocId();
13871776 const value_id = try cg.constInt(.usize, int.addr);
13881777 try cg.body.emit(gpa, .OpConvertUToPtr, .{
13891778 .id_result_type = result_ty_id,
......@@ -1392,13 +1781,87 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
13921781 });
13931782 return result_ptr_id;
13941783 },
1395 .nav_ptr => |nav| {
1396 const result_ptr_ty = try pt.navPtrType(nav);
1397 return cg.constantNavRef(result_ptr_ty, nav);
1784 .nav_ptr => |nav_index| {
1785 const ip = &zcu.intern_pool;
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;
13981830 },
13991831 .uav_ptr => |uav| {
1832 const ip = &zcu.intern_pool;
14001833 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;
14021865 },
14031866 .eu_payload_ptr => @panic("TODO"),
14041867 .opt_payload_ptr => @panic("TODO"),
......@@ -1450,7 +1913,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
14501913 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);
14511914 }
14521915 if (target.os.tag == .opencl) {
1453 const result_ptr_id = cg.module.allocId();
1916 const result_ptr_id = cg.allocId();
14541917 try cg.body.emit(gpa, .OpBitcast, .{
14551918 .id_result_type = result_ty_id,
14561919 .id_result = result_ptr_id,
......@@ -1468,59 +1931,15 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
14681931 }
14691932}
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
15151934/// Emit a stub OpFunction/OpFunctionEnd + Import linkage decoration for an
15161935/// extern function so the module is structurally valid. The stub will be
15171936/// 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 {
15191938 if (decl.has_extern_stub) return;
15201939 decl.has_extern_stub = true;
15211940
1522 const gpa = cg.module.gpa;
1523 const zcu = cg.module.zcu;
1941 const gpa = cg.gpa;
1942 const zcu = cg.zcu;
15241943 const ip = &zcu.intern_pool;
15251944 const fn_info = zcu.typeToFunc(fn_ty).?;
15261945 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
15401959 const param_type_id = try cg.resolveType(param_ty, .direct);
15411960 try stub.emit(gpa, .OpFunctionParameter, .{
15421961 .id_result_type = param_type_id,
1543 .id_result = cg.module.allocId(),
1962 .id_result = cg.allocId(),
15441963 });
15451964 }
15461965 try stub.emit(gpa, .OpFunctionEnd, {});
1547 try cg.module.sections.functions.append(gpa, stub);
1966 try cg.sections.functions.append(gpa, stub);
15481967
15491968 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, .{
15511970 .target = decl.result_id,
15521971 .decoration = .{ .linkage_attributes = .{
15531972 .name = extern_name,
15541973 .linkage_type = .import,
15551974 } },
15561975 });
1557 try cg.module.debugName(decl.result_id, extern_name);
1976 try cg.debugName(decl.result_id, extern_name);
15581977}
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.
16161979fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1617 const gpa = cg.module.gpa;
1980 const gpa = cg.gpa;
16181981 var aw: std.Io.Writer.Allocating = .init(gpa);
16191982 defer aw.deinit();
16201983 ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) {
......@@ -1641,67 +2004,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
16412004/// padding: [padding_size]u8,
16422005/// }
16432006/// 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
17032007fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1704 const zcu = cg.module.zcu;
2008 const zcu = cg.zcu;
17052009 if (!ret_ty.hasRuntimeBits(zcu)) {
17062010 // If the return type is an error set or an error union, then we make this
17072011 // 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 {
17172021}
17182022
17192023fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1720 const gpa = cg.module.gpa;
2024 const gpa = cg.gpa;
17212025 const pt = cg.pt;
1722 const zcu = cg.module.zcu;
2026 const zcu = cg.zcu;
17232027 const ip = &zcu.intern_pool;
1724 const target = cg.module.zcu.getTarget();
2028 const target = cg.zcu.getTarget();
17252029
17262030 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});
17272031
17282032 switch (ty.zigTypeTag(zcu)) {
17292033 .noreturn => {
17302034 assert(repr == .direct);
1731 return try cg.module.voidType();
2035 return try cg.voidType();
17322036 },
17332037 .void => switch (repr) {
1734 .direct => return try cg.module.voidType(),
2038 .direct => return try cg.voidType(),
17352039 .indirect => {
17362040 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");
17382042 },
17392043 },
17402044 .bool => switch (repr) {
1741 .direct => return try cg.module.boolType(),
2045 .direct => return try cg.boolType(),
17422046 .indirect => return try cg.resolveType(.u1, .indirect),
17432047 },
17442048 .int => {
17452049 if (ty.toIntern() == .u0_type) {
17462050 assert(repr == .indirect);
17472051 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");
17492053 }
17502054 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);
17522056 },
17532057 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
17542058 .float => {
......@@ -1767,7 +2071,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
17672071 );
17682072 }
17692073
1770 return try cg.module.floatType(bits);
2074 return try cg.floatType(bits);
17712075 },
17722076 .array => {
17732077 const elem_ty = ty.childType(zcu);
......@@ -1779,7 +2083,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
17792083 if (!elem_ty.hasRuntimeBits(zcu)) {
17802084 assert(repr == .indirect);
17812085 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");
17832087 } else if (total_len == 0) {
17842088 // The size of the array would be 0, but that is not allowed in SPIR-V.
17852089 // 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 {
17902094 // generate an array of 1 element instead, so that ptr_elem_ptr instructions
17912095 // can be lowered to ptrAccessChain instead of manually performing the math.
17922096 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);
17942098 } else {
17952099 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);
17972101 }
17982102 },
17992103 .vector => {
18002104 const elem_ty = ty.childType(zcu);
18012105 const elem_ty_id = try cg.resolveType(elem_ty, repr);
18022106 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);
18042108 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);
18062110 },
18072111 .@"fn" => switch (repr) {
18082112 .direct => {
18092113 const fn_info = zcu.typeToFunc(ty).?;
18102114
1811 comptime assert(zig_call_abi_ver == 3);
18122115 assert(!fn_info.is_var_args);
18132116 switch (fn_info.cc) {
18142117 .auto,
......@@ -1837,7 +2140,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
18372140 param_index += 1;
18382141 }
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]);
18412144 },
18422145 .indirect => {
18432146 // TODO: Represent function pointers properly.
......@@ -1860,15 +2163,15 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
18602163 },
18612164 };
18622165 const child_ty_id = try cg.resolveType(child_ty, .indirect);
1863 const storage_class = cg.module.storageClass(ptr_info.flags.address_space);
1864 const ptr_ty_id = try cg.module.ptrType(child_ty_id, storage_class);
2166 const storage_class = cg.storageClass(ptr_info.flags.address_space);
2167 const ptr_ty_id = try cg.ptrType(child_ty_id, storage_class);
18652168
18662169 if (ptr_info.flags.size != .slice) {
18672170 return ptr_ty_id;
18682171 }
18692172
18702173 const size_ty_id = try cg.resolveType(.usize, .direct);
1871 return try cg.module.structType(
2174 return try cg.structType(
18722175 &.{ ptr_ty_id, size_ty_id },
18732176 &.{ "ptr", "len" },
18742177 .none,
......@@ -1889,14 +2192,14 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
18892192 member_index += 1;
18902193 }
18912194
1892 const result_id = try cg.module.structType(
2195 const result_id = try cg.structType(
18932196 member_types[0..member_index],
18942197 null,
18952198 .none,
18962199 );
18972200 const type_name = try cg.resolveTypeName(ty);
18982201 defer gpa.free(type_name);
1899 try cg.module.debugName(result_id, type_name);
2202 try cg.debugName(result_id, type_name);
19002203 return result_id;
19012204 },
19022205 .struct_type => ip.loadStructType(ty.toIntern()),
......@@ -1923,7 +2226,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19232226 try member_names.append(field_name.toSlice(ip));
19242227 }
19252228
1926 const result_id = try cg.module.structType(
2229 const result_id = try cg.structType(
19272230 member_types.items,
19282231 member_names.items,
19292232 ty.toIntern(),
......@@ -1931,7 +2234,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19312234
19322235 const type_name = try cg.resolveTypeName(ty);
19332236 defer gpa.free(type_name);
1934 try cg.module.debugName(result_id, type_name);
2237 try cg.debugName(result_id, type_name);
19352238
19362239 return result_id;
19372240 },
......@@ -1952,13 +2255,52 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19522255
19532256 const bool_ty_id = try cg.resolveType(.bool, .indirect);
19542257
1955 return try cg.module.structType(
2258 return try cg.structType(
19562259 &.{ payload_ty_id, bool_ty_id },
19572260 &.{ "payload", "valid" },
19582261 .none,
19592262 );
19602263 },
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 },
19622304 .error_set => {
19632305 const err_int_ty = try pt.errorIntType();
19642306 return try cg.resolveType(err_int_ty, repr);
......@@ -1989,46 +2331,43 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
19892331 // TODO: ABI padding?
19902332 }
19912333
1992 return try cg.module.structType(&member_types, &member_names, .none);
2334 return try cg.structType(&member_types, &member_names, .none);
19932335 },
19942336 .@"opaque" => {
19952337 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
19962338 const type_name = try cg.resolveTypeName(ty);
19972339 defer gpa.free(type_name);
1998 return try cg.module.opaqueType(type_name);
2340 return try cg.opaqueType(type_name);
19992341 },
20002342 .spirv => {
2001 const ip_index = ty.toIntern();
2002 const spirv_type = ip.loadSpirvType(ip_index);
2343 const spirv_type = ip.loadSpirvType(ty.toIntern());
2344 const result_id = cg.allocId();
20032345 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 }),
20052347 .image => {
2006 const sampled_type_id = blk: {
2007 if (spirv_type.ty == .none) break :blk try cg.module.intType(.unsigned, 32);
2008 break :blk try cg.resolveType(Type.fromInterned(spirv_type.ty), .direct);
2009 };
2010 return try cg.module.imageType(
2011 ip_index,
2012 sampled_type_id,
2013 switch (spirv_type.flags.dim) {
2348 const sampled_type_id = try cg.resolveType(.fromInterned(spirv_type.ty), .direct);
2349 try cg.sections.globals.emit(gpa, .OpTypeImage, .{
2350 .id_result = result_id,
2351 .sampled_type = sampled_type_id,
2352 .dim = switch (spirv_type.flags.dim) {
20142353 .@"1d" => .@"1d",
20152354 .@"2d" => .@"2d",
20162355 .@"3d" => .@"3d",
20172356 .cube => .cube,
20182357 },
2019 switch (spirv_type.flags.depth) {
2358 .depth = switch (spirv_type.flags.depth) {
20202359 .not_depth => 0,
20212360 .depth => 1,
20222361 .unknown => 2,
20232362 },
2024 @intFromBool(spirv_type.flags.is_arrayed),
2025 @intFromBool(spirv_type.flags.is_multisampled),
2026 switch (spirv_type.flags.usage) {
2027 .unknown => 1,
2363 .arrayed = @intFromBool(spirv_type.flags.is_arrayed),
2364 .ms = @intFromBool(spirv_type.flags.is_multisampled),
2365 .sampled = switch (spirv_type.flags.usage) {
2366 .unknown => 0,
20282367 .sampled => 1,
20292368 .storage => 2,
20302369 },
2031 switch (spirv_type.flags.format) {
2370 .image_format = switch (spirv_type.flags.format) {
20322371 .unknown => .unknown,
20332372 .rgba32f => .rgba32f,
20342373 .rgba32i => .rgba32i,
......@@ -2044,31 +2383,36 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
20442383 .r32i => .r32i,
20452384 .r32u => .r32ui,
20462385 },
2047 switch (spirv_type.flags.access) {
2386 .access_qualifier = switch (spirv_type.flags.access) {
20482387 .unknown => null,
20492388 .read_only => .read_only,
20502389 .write_only => .write_only,
20512390 .read_write => .read_write,
20522391 },
2053 );
2392 });
20542393 },
20552394 .sampled_image => {
20562395 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 });
20582400 },
20592401 .runtime_array => {
20602402 const elem_ty: Type = .fromInterned(spirv_type.ty);
20612403 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
2062 const result_id = try cg.module.runtimeArrayType(ip_index, elem_ty_id);
2063
2404 try cg.sections.globals.emit(gpa, .OpTypeRuntimeArray, .{
2405 .id_result = result_id,
2406 .element_type = elem_ty_id,
2407 });
20642408 if (elem_ty.hasRuntimeBits(zcu)) {
2065 try cg.module.decorate(result_id, .{ .array_stride = .{
2409 try cg.decorate(result_id, .{ .array_stride = .{
20662410 .array_stride = @intCast(elem_ty.abiSize(zcu)),
20672411 } });
20682412 }
2069 return result_id;
20702413 },
20712414 }
2415 return result_id;
20722416 },
20732417
20742418 .null,
......@@ -2099,7 +2443,7 @@ const ErrorUnionLayout = struct {
20992443};
21002444
21012445fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {
2102 const zcu = cg.module.zcu;
2446 const zcu = cg.zcu;
21032447
21042448 const error_align = Type.abiAlignment(.anyerror, zcu);
21052449 const payload_align = payload_ty.abiAlignment(zcu);
......@@ -2130,7 +2474,7 @@ const UnionLayout = struct {
21302474};
21312475
21322476fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {
2133 const zcu = cg.module.zcu;
2477 const zcu = cg.zcu;
21342478 const ip = &zcu.intern_pool;
21352479 const layout = ty.unionGetLayout(zcu);
21362480 const union_obj = zcu.typeToUnion(ty).?;
......@@ -2220,8 +2564,8 @@ const Temporary = struct {
22202564 }
22212565
22222566 fn materialize(temp: Temporary, cg: *CodeGen) !Id {
2223 const gpa = cg.module.gpa;
2224 const zcu = cg.module.zcu;
2567 const gpa = cg.gpa;
2568 const zcu = cg.zcu;
22252569 switch (temp.value) {
22262570 .singleton => |id| return id,
22272571 .exploded_vector => |range| {
......@@ -2255,7 +2599,7 @@ const Temporary = struct {
22552599 /// 'Explode' a temporary into separate elements. This turns a vector
22562600 /// into a bag of elements.
22572601 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {
2258 const zcu = cg.module.zcu;
2602 const zcu = cg.zcu;
22592603
22602604 // If the value is a scalar, then this is a no-op.
22612605 if (!temp.ty.isVector(zcu)) {
......@@ -2267,7 +2611,7 @@ const Temporary = struct {
22672611
22682612 const ty_id = try cg.resolveType(temp.ty.scalarType(zcu), .direct);
22692613 const n = temp.ty.vectorLen(zcu);
2270 const results = cg.module.allocIds(n);
2614 const results = cg.allocIds(n);
22712615
22722616 const id = switch (temp.value) {
22732617 .singleton => |id| id,
......@@ -2276,7 +2620,7 @@ const Temporary = struct {
22762620
22772621 for (0..n) |i| {
22782622 const indexes = [_]u32{@intCast(i)};
2279 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
2623 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
22802624 .id_result_type = ty_id,
22812625 .id_result = results.at(i),
22822626 .composite = id,
......@@ -2296,12 +2640,12 @@ const CompositeInt = struct {
22962640 info: ArithmeticTypeInfo,
22972641
22982642 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {
2299 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;
2300 const gpa = cg.module.gpa;
2643 const n_limbs: u16 = info.backing_bits / big_int_bits;
2644 const gpa = cg.gpa;
23012645 const u32_ty_id = try cg.resolveType(.u32, .direct);
23022646 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
23032647 for (limbs, 0..) |*limb, i| {
2304 const result_id = cg.module.allocId();
2648 const result_id = cg.allocId();
23052649 try cg.body.emit(gpa, .OpCompositeExtract, .{
23062650 .id_result_type = u32_ty_id,
23072651 .id_result = result_id,
......@@ -2323,8 +2667,8 @@ const CompositeInt = struct {
23232667 }
23242668
23252669 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {
2326 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;
2327 const limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, n_limbs);
2670 const n_limbs: u16 = info.backing_bits / big_int_bits;
2671 const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs);
23282672 const zero_id = try cg.constInt(.u32, @as(u32, 0));
23292673 for (limbs) |*limb| limb.* = zero_id;
23302674 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
......@@ -2337,9 +2681,9 @@ const CompositeInt = struct {
23372681
23382682 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {
23392683 const cg = ci.cg;
2340 const gpa = cg.module.gpa;
2684 const gpa = cg.gpa;
23412685 const u32_ty_id = try cg.resolveType(.u32, .direct);
2342 const result_id = cg.module.allocId();
2686 const result_id = cg.allocId();
23432687 try cg.body.emitRaw(gpa, opcode, 4);
23442688 cg.body.writeOperand(Id, u32_ty_id);
23452689 cg.body.writeOperand(Id, result_id);
......@@ -2350,9 +2694,9 @@ const CompositeInt = struct {
23502694
23512695 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {
23522696 const cg = ci.cg;
2353 const gpa = cg.module.gpa;
2697 const gpa = cg.gpa;
23542698 const u32_ty_id = try cg.resolveType(.u32, .direct);
2355 const result_id = cg.module.allocId();
2699 const result_id = cg.allocId();
23562700 try cg.body.emitRaw(gpa, opcode, 3);
23572701 cg.body.writeOperand(Id, u32_ty_id);
23582702 cg.body.writeOperand(Id, result_id);
......@@ -2362,7 +2706,7 @@ const CompositeInt = struct {
23622706
23632707 fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt {
23642708 const cg = ci.cg;
2365 const gpa = cg.module.gpa;
2709 const gpa = cg.gpa;
23662710 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
23672711 for (result_limbs, 0..) |*r, i| {
23682712 r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]);
......@@ -2372,7 +2716,7 @@ const CompositeInt = struct {
23722716
23732717 fn bitwiseNot(ci: CompositeInt) !CompositeInt {
23742718 const cg = ci.cg;
2375 const gpa = cg.module.gpa;
2719 const gpa = cg.gpa;
23762720 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
23772721 for (result_limbs, 0..) |*r, i| {
23782722 r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]);
......@@ -2382,41 +2726,45 @@ const CompositeInt = struct {
23822726
23832727 fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id {
23842728 const cg = ci.cg;
2385 const gpa = cg.module.gpa;
2729 const gpa = cg.gpa;
23862730 const bool_ty_id = try cg.resolveType(.bool, .direct);
23872731
23882732 switch (op) {
23892733 .eq, .neq => {
23902734 var result = blk: {
2391 const r = cg.module.allocId();
2392 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2393 cg.body.writeOperand(Id, bool_ty_id);
2394 cg.body.writeOperand(Id, r);
2395 cg.body.writeOperand(Id, ci.limbs[0]);
2396 cg.body.writeOperand(Id, other.limbs[0]);
2735 const r = cg.allocId();
2736 try cg.body.emit(gpa, .OpIEqual, .{
2737 .id_result_type = bool_ty_id,
2738 .id_result = r,
2739 .operand_1 = ci.limbs[0],
2740 .operand_2 = other.limbs[0],
2741 });
23972742 break :blk r;
23982743 };
23992744 for (1..ci.n_limbs) |i| {
2400 const limb_eq = cg.module.allocId();
2401 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2402 cg.body.writeOperand(Id, bool_ty_id);
2403 cg.body.writeOperand(Id, limb_eq);
2404 cg.body.writeOperand(Id, ci.limbs[i]);
2405 cg.body.writeOperand(Id, other.limbs[i]);
2406 const combined = cg.module.allocId();
2407 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
2408 cg.body.writeOperand(Id, bool_ty_id);
2409 cg.body.writeOperand(Id, combined);
2410 cg.body.writeOperand(Id, result);
2411 cg.body.writeOperand(Id, limb_eq);
2745 const limb_eq = cg.allocId();
2746 try cg.body.emit(gpa, .OpIEqual, .{
2747 .id_result_type = bool_ty_id,
2748 .id_result = limb_eq,
2749 .operand_1 = ci.limbs[i],
2750 .operand_2 = other.limbs[i],
2751 });
2752 const combined = cg.allocId();
2753 try cg.body.emit(gpa, .OpLogicalAnd, .{
2754 .id_result_type = bool_ty_id,
2755 .id_result = combined,
2756 .operand_1 = result,
2757 .operand_2 = limb_eq,
2758 });
24122759 result = combined;
24132760 }
24142761 if (op == .neq) {
2415 const negated = cg.module.allocId();
2416 try cg.body.emitRaw(gpa, .OpLogicalNot, 3);
2417 cg.body.writeOperand(Id, bool_ty_id);
2418 cg.body.writeOperand(Id, negated);
2419 cg.body.writeOperand(Id, result);
2762 const negated = cg.allocId();
2763 try cg.body.emit(gpa, .OpLogicalNot, .{
2764 .id_result_type = bool_ty_id,
2765 .id_result = negated,
2766 .operand = result,
2767 });
24202768 result = negated;
24212769 }
24222770 return result;
......@@ -2429,12 +2777,13 @@ const CompositeInt = struct {
24292777 for (0..ci.n_limbs) |i| {
24302778 const l = ci.limbs[i];
24312779 const r = other.limbs[i];
2432 const limb_ne = cg.module.allocId();
2433 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
2434 cg.body.writeOperand(Id, bool_ty_id);
2435 cg.body.writeOperand(Id, limb_ne);
2436 cg.body.writeOperand(Id, l);
2437 cg.body.writeOperand(Id, r);
2780 const limb_ne = cg.allocId();
2781 try cg.body.emit(gpa, .OpINotEqual, .{
2782 .id_result_type = bool_ty_id,
2783 .id_result = limb_ne,
2784 .operand_1 = l,
2785 .operand_2 = r,
2786 });
24382787
24392788 const is_top = (i == ci.n_limbs - 1);
24402789 const use_signed = is_top and ci.info.signedness == .signed;
......@@ -2442,13 +2791,13 @@ const CompositeInt = struct {
24422791 var cmp_r = r;
24432792 if (use_signed) {
24442793 const i32_ty_id = try cg.resolveType(.i32, .direct);
2445 const sl = cg.module.allocId();
2794 const sl = cg.allocId();
24462795 try cg.body.emit(gpa, .OpBitcast, .{
24472796 .id_result_type = i32_ty_id,
24482797 .id_result = sl,
24492798 .operand = l,
24502799 });
2451 const sr = cg.module.allocId();
2800 const sr = cg.allocId();
24522801 try cg.body.emit(gpa, .OpBitcast, .{
24532802 .id_result_type = i32_ty_id,
24542803 .id_result = sr,
......@@ -2463,14 +2812,14 @@ const CompositeInt = struct {
24632812 else
24642813 (if (use_signed) .OpSGreaterThan else .OpUGreaterThan);
24652814
2466 const limb_cmp = cg.module.allocId();
2815 const limb_cmp = cg.allocId();
24672816 try cg.body.emitRaw(gpa, cmp_opcode, 4);
24682817 cg.body.writeOperand(Id, bool_ty_id);
24692818 cg.body.writeOperand(Id, limb_cmp);
24702819 cg.body.writeOperand(Id, cmp_l);
24712820 cg.body.writeOperand(Id, cmp_r);
24722821
2473 const selected = cg.module.allocId();
2822 const selected = cg.allocId();
24742823 try cg.body.emit(gpa, .OpSelect, .{
24752824 .id_result_type = bool_ty_id,
24762825 .id_result = selected,
......@@ -2487,9 +2836,9 @@ const CompositeInt = struct {
24872836
24882837 fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt {
24892838 const cg = ci.cg;
2490 const gpa = cg.module.gpa;
2839 const gpa = cg.gpa;
24912840 const pt = cg.pt;
2492 const zcu = cg.module.zcu;
2841 const zcu = cg.zcu;
24932842 const ip = &zcu.intern_pool;
24942843 const comp = zcu.comp;
24952844 const io = comp.io;
......@@ -2508,21 +2857,21 @@ const CompositeInt = struct {
25082857 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;
25092858
25102859 for (0..ci.n_limbs) |i| {
2511 const op1 = cg.module.allocId();
2860 const op1 = cg.allocId();
25122861 try cg.body.emitRaw(gpa, opcode, 4);
25132862 cg.body.writeOperand(Id, carry_struct_ty_id);
25142863 cg.body.writeOperand(Id, op1);
25152864 cg.body.writeOperand(Id, ci.limbs[i]);
25162865 cg.body.writeOperand(Id, other.limbs[i]);
25172866
2518 const sum1 = cg.module.allocId();
2867 const sum1 = cg.allocId();
25192868 try cg.body.emit(gpa, .OpCompositeExtract, .{
25202869 .id_result_type = u32_ty_id,
25212870 .id_result = sum1,
25222871 .composite = op1,
25232872 .indexes = &.{0},
25242873 });
2525 const carry1 = cg.module.allocId();
2874 const carry1 = cg.allocId();
25262875 try cg.body.emit(gpa, .OpCompositeExtract, .{
25272876 .id_result_type = u32_ty_id,
25282877 .id_result = carry1,
......@@ -2530,21 +2879,21 @@ const CompositeInt = struct {
25302879 .indexes = &.{1},
25312880 });
25322881
2533 const op2 = cg.module.allocId();
2882 const op2 = cg.allocId();
25342883 try cg.body.emitRaw(gpa, opcode, 4);
25352884 cg.body.writeOperand(Id, carry_struct_ty_id);
25362885 cg.body.writeOperand(Id, op2);
25372886 cg.body.writeOperand(Id, sum1);
25382887 cg.body.writeOperand(Id, carry_id);
25392888
2540 result_limbs[i] = cg.module.allocId();
2889 result_limbs[i] = cg.allocId();
25412890 try cg.body.emit(gpa, .OpCompositeExtract, .{
25422891 .id_result_type = u32_ty_id,
25432892 .id_result = result_limbs[i],
25442893 .composite = op2,
25452894 .indexes = &.{0},
25462895 });
2547 const carry2 = cg.module.allocId();
2896 const carry2 = cg.allocId();
25482897 try cg.body.emit(gpa, .OpCompositeExtract, .{
25492898 .id_result_type = u32_ty_id,
25502899 .id_result = carry2,
......@@ -2560,7 +2909,7 @@ const CompositeInt = struct {
25602909
25612910 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {
25622911 const cg = ci.cg;
2563 const gpa = cg.module.gpa;
2912 const gpa = cg.gpa;
25642913 const u32_ty_id = try cg.resolveType(.u32, .direct);
25652914 const bool_ty_id = try cg.resolveType(.bool, .direct);
25662915 const zero_id = try cg.constInt(.u32, @as(u32, 0));
......@@ -2572,12 +2921,13 @@ const CompositeInt = struct {
25722921 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
25732922 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
25742923 const frac_is_zero = blk: {
2575 const r = cg.module.allocId();
2576 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2577 cg.body.writeOperand(Id, bool_ty_id);
2578 cg.body.writeOperand(Id, r);
2579 cg.body.writeOperand(Id, frac);
2580 cg.body.writeOperand(Id, zero_id);
2924 const r = cg.allocId();
2925 try cg.body.emit(gpa, .OpIEqual, .{
2926 .id_result_type = bool_ty_id,
2927 .id_result = r,
2928 .operand_1 = frac,
2929 .operand_2 = zero_id,
2930 });
25812931 break :blk r;
25822932 };
25832933
......@@ -2593,17 +2943,18 @@ const CompositeInt = struct {
25932943 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);
25942944
25952945 const is_main = blk: {
2596 const r = cg.module.allocId();
2597 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2598 cg.body.writeOperand(Id, bool_ty_id);
2599 cg.body.writeOperand(Id, r);
2600 cg.body.writeOperand(Id, j_plus_whole);
2601 cg.body.writeOperand(Id, i_id);
2946 const r = cg.allocId();
2947 try cg.body.emit(gpa, .OpIEqual, .{
2948 .id_result_type = bool_ty_id,
2949 .id_result = r,
2950 .operand_1 = j_plus_whole,
2951 .operand_2 = i_id,
2952 });
26022953 break :blk r;
26032954 };
26042955 const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac);
26052956 main_val = blk: {
2606 const r = cg.module.allocId();
2957 const r = cg.allocId();
26072958 try cg.body.emit(gpa, .OpSelect, .{
26082959 .id_result_type = u32_ty_id,
26092960 .id_result = r,
......@@ -2617,17 +2968,18 @@ const CompositeInt = struct {
26172968 const one_id = try cg.constInt(.u32, @as(u32, 1));
26182969 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);
26192970 const is_carry = blk: {
2620 const r = cg.module.allocId();
2621 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2622 cg.body.writeOperand(Id, bool_ty_id);
2623 cg.body.writeOperand(Id, r);
2624 cg.body.writeOperand(Id, j_plus_whole_plus_1);
2625 cg.body.writeOperand(Id, i_id);
2971 const r = cg.allocId();
2972 try cg.body.emit(gpa, .OpIEqual, .{
2973 .id_result_type = bool_ty_id,
2974 .id_result = r,
2975 .operand_1 = j_plus_whole_plus_1,
2976 .operand_2 = i_id,
2977 });
26262978 break :blk r;
26272979 };
26282980 const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac);
26292981 const guarded_carry = blk: {
2630 const r = cg.module.allocId();
2982 const r = cg.allocId();
26312983 try cg.body.emit(gpa, .OpSelect, .{
26322984 .id_result_type = u32_ty_id,
26332985 .id_result = r,
......@@ -2638,7 +2990,7 @@ const CompositeInt = struct {
26382990 break :blk r;
26392991 };
26402992 carry_val = blk: {
2641 const r = cg.module.allocId();
2993 const r = cg.allocId();
26422994 try cg.body.emit(gpa, .OpSelect, .{
26432995 .id_result_type = u32_ty_id,
26442996 .id_result = r,
......@@ -2658,7 +3010,7 @@ const CompositeInt = struct {
26583010
26593011 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {
26603012 const cg = ci.cg;
2661 const gpa = cg.module.gpa;
3013 const gpa = cg.gpa;
26623014 const u32_ty_id = try cg.resolveType(.u32, .direct);
26633015 const bool_ty_id = try cg.resolveType(.bool, .direct);
26643016 const zero_id = try cg.constInt(.u32, @as(u32, 0));
......@@ -2670,31 +3022,33 @@ const CompositeInt = struct {
26703022 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
26713023 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
26723024 const frac_is_zero = blk: {
2673 const r = cg.module.allocId();
2674 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2675 cg.body.writeOperand(Id, bool_ty_id);
2676 cg.body.writeOperand(Id, r);
2677 cg.body.writeOperand(Id, frac);
2678 cg.body.writeOperand(Id, zero_id);
3025 const r = cg.allocId();
3026 try cg.body.emit(gpa, .OpIEqual, .{
3027 .id_result_type = bool_ty_id,
3028 .id_result = r,
3029 .operand_1 = frac,
3030 .operand_2 = zero_id,
3031 });
26793032 break :blk r;
26803033 };
26813034
26823035 const fill_id = if (is_arithmetic) blk: {
26833036 const i32_ty_id = try cg.resolveType(.i32, .direct);
2684 const msb_signed = cg.module.allocId();
3037 const msb_signed = cg.allocId();
26853038 try cg.body.emit(gpa, .OpBitcast, .{
26863039 .id_result_type = i32_ty_id,
26873040 .id_result = msb_signed,
26883041 .operand = ci.limbs[ci.n_limbs - 1],
26893042 });
26903043 const shift31 = try cg.constInt(.i32, @as(i32, 31));
2691 const sign_ext = cg.module.allocId();
2692 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
2693 cg.body.writeOperand(Id, i32_ty_id);
2694 cg.body.writeOperand(Id, sign_ext);
2695 cg.body.writeOperand(Id, msb_signed);
2696 cg.body.writeOperand(Id, shift31);
2697 const back = cg.module.allocId();
3044 const sign_ext = cg.allocId();
3045 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
3046 .id_result_type = i32_ty_id,
3047 .id_result = sign_ext,
3048 .base = msb_signed,
3049 .shift = shift31,
3050 });
3051 const back = cg.allocId();
26983052 try cg.body.emit(gpa, .OpBitcast, .{
26993053 .id_result_type = u32_ty_id,
27003054 .id_result = back,
......@@ -2707,7 +3061,7 @@ const CompositeInt = struct {
27073061
27083062 const arith_carry_init = if (is_arithmetic) blk: {
27093063 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);
2710 const guarded = cg.module.allocId();
3064 const guarded = cg.allocId();
27113065 try cg.body.emit(gpa, .OpSelect, .{
27123066 .id_result_type = u32_ty_id,
27133067 .id_result = guarded,
......@@ -2727,17 +3081,18 @@ const CompositeInt = struct {
27273081 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));
27283082 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);
27293083 const is_main = blk: {
2730 const r = cg.module.allocId();
2731 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2732 cg.body.writeOperand(Id, bool_ty_id);
2733 cg.body.writeOperand(Id, r);
2734 cg.body.writeOperand(Id, j_id);
2735 cg.body.writeOperand(Id, i_plus_whole);
3084 const r = cg.allocId();
3085 try cg.body.emit(gpa, .OpIEqual, .{
3086 .id_result_type = bool_ty_id,
3087 .id_result = r,
3088 .operand_1 = j_id,
3089 .operand_2 = i_plus_whole,
3090 });
27363091 break :blk r;
27373092 };
27383093 const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac);
27393094 main_val = blk: {
2740 const r = cg.module.allocId();
3095 const r = cg.allocId();
27413096 try cg.body.emit(gpa, .OpSelect, .{
27423097 .id_result_type = u32_ty_id,
27433098 .id_result = r,
......@@ -2751,17 +3106,18 @@ const CompositeInt = struct {
27513106 const one_id = try cg.constInt(.u32, @as(u32, 1));
27523107 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);
27533108 const is_carry = blk: {
2754 const r = cg.module.allocId();
2755 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2756 cg.body.writeOperand(Id, bool_ty_id);
2757 cg.body.writeOperand(Id, r);
2758 cg.body.writeOperand(Id, j_id);
2759 cg.body.writeOperand(Id, i_plus_whole_plus_1);
3109 const r = cg.allocId();
3110 try cg.body.emit(gpa, .OpIEqual, .{
3111 .id_result_type = bool_ty_id,
3112 .id_result = r,
3113 .operand_1 = j_id,
3114 .operand_2 = i_plus_whole_plus_1,
3115 });
27603116 break :blk r;
27613117 };
27623118 const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac);
27633119 const guarded_carry = blk: {
2764 const r = cg.module.allocId();
3120 const r = cg.allocId();
27653121 try cg.body.emit(gpa, .OpSelect, .{
27663122 .id_result_type = u32_ty_id,
27673123 .id_result = r,
......@@ -2772,7 +3128,7 @@ const CompositeInt = struct {
27723128 break :blk r;
27733129 };
27743130 carry_val = blk: {
2775 const r = cg.module.allocId();
3131 const r = cg.allocId();
27763132 try cg.body.emit(gpa, .OpSelect, .{
27773133 .id_result_type = u32_ty_id,
27783134 .id_result = r,
......@@ -2792,9 +3148,9 @@ const CompositeInt = struct {
27923148
27933149 fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id {
27943150 const cg = ci.cg;
2795 const gpa = cg.module.gpa;
3151 const gpa = cg.gpa;
27963152 const pt = cg.pt;
2797 const zcu = cg.module.zcu;
3153 const zcu = cg.zcu;
27983154 const ip = &zcu.intern_pool;
27993155 const comp = zcu.comp;
28003156 const io = comp.io;
......@@ -2825,15 +3181,16 @@ const CompositeInt = struct {
28253181 var hi: Id = undefined;
28263182 switch (target.os.tag) {
28273183 .opencl => {
2828 lo = cg.module.allocId();
2829 try cg.body.emitRaw(gpa, .OpIMul, 4);
2830 cg.body.writeOperand(Id, u32_ty_id);
2831 cg.body.writeOperand(Id, lo);
2832 cg.body.writeOperand(Id, ci.limbs[i]);
2833 cg.body.writeOperand(Id, other.limbs[j]);
3184 lo = cg.allocId();
3185 try cg.body.emit(gpa, .OpIMul, .{
3186 .id_result_type = u32_ty_id,
3187 .id_result = lo,
3188 .operand_1 = ci.limbs[i],
3189 .operand_2 = other.limbs[j],
3190 });
28343191
28353192 const set = try cg.importExtendedSet();
2836 hi = cg.module.allocId();
3193 hi = cg.allocId();
28373194 try cg.body.emit(gpa, .OpExtInst, .{
28383195 .id_result_type = u32_ty_id,
28393196 .id_result = hi,
......@@ -2843,21 +3200,22 @@ const CompositeInt = struct {
28433200 });
28443201 },
28453202 else => {
2846 const mul_result = cg.module.allocId();
2847 try cg.body.emitRaw(gpa, .OpUMulExtended, 4);
2848 cg.body.writeOperand(Id, pair_struct_ty_id);
2849 cg.body.writeOperand(Id, mul_result);
2850 cg.body.writeOperand(Id, ci.limbs[i]);
2851 cg.body.writeOperand(Id, other.limbs[j]);
2852
2853 lo = cg.module.allocId();
3203 const mul_result = cg.allocId();
3204 try cg.body.emit(gpa, .OpUMulExtended, .{
3205 .id_result_type = pair_struct_ty_id,
3206 .id_result = mul_result,
3207 .operand_1 = ci.limbs[i],
3208 .operand_2 = other.limbs[j],
3209 });
3210
3211 lo = cg.allocId();
28543212 try cg.body.emit(gpa, .OpCompositeExtract, .{
28553213 .id_result_type = u32_ty_id,
28563214 .id_result = lo,
28573215 .composite = mul_result,
28583216 .indexes = &.{0},
28593217 });
2860 hi = cg.module.allocId();
3218 hi = cg.allocId();
28613219 try cg.body.emit(gpa, .OpCompositeExtract, .{
28623220 .id_result_type = u32_ty_id,
28633221 .id_result = hi,
......@@ -2867,21 +3225,22 @@ const CompositeInt = struct {
28673225 },
28683226 }
28693227
2870 const add1 = cg.module.allocId();
2871 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);
2872 cg.body.writeOperand(Id, pair_struct_ty_id);
2873 cg.body.writeOperand(Id, add1);
2874 cg.body.writeOperand(Id, result_limbs[k]);
2875 cg.body.writeOperand(Id, lo);
3228 const add1 = cg.allocId();
3229 try cg.body.emit(gpa, .OpIAddCarry, .{
3230 .id_result_type = pair_struct_ty_id,
3231 .id_result = add1,
3232 .operand_1 = result_limbs[k],
3233 .operand_2 = lo,
3234 });
28763235
2877 const sum1 = cg.module.allocId();
3236 const sum1 = cg.allocId();
28783237 try cg.body.emit(gpa, .OpCompositeExtract, .{
28793238 .id_result_type = u32_ty_id,
28803239 .id_result = sum1,
28813240 .composite = add1,
28823241 .indexes = &.{0},
28833242 });
2884 const c1 = cg.module.allocId();
3243 const c1 = cg.allocId();
28853244 try cg.body.emit(gpa, .OpCompositeExtract, .{
28863245 .id_result_type = u32_ty_id,
28873246 .id_result = c1,
......@@ -2889,21 +3248,22 @@ const CompositeInt = struct {
28893248 .indexes = &.{1},
28903249 });
28913250
2892 const add2 = cg.module.allocId();
2893 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);
2894 cg.body.writeOperand(Id, pair_struct_ty_id);
2895 cg.body.writeOperand(Id, add2);
2896 cg.body.writeOperand(Id, sum1);
2897 cg.body.writeOperand(Id, carry_id);
3251 const add2 = cg.allocId();
3252 try cg.body.emit(gpa, .OpIAddCarry, .{
3253 .id_result_type = pair_struct_ty_id,
3254 .id_result = add2,
3255 .operand_1 = sum1,
3256 .operand_2 = carry_id,
3257 });
28983258
2899 result_limbs[k] = cg.module.allocId();
3259 result_limbs[k] = cg.allocId();
29003260 try cg.body.emit(gpa, .OpCompositeExtract, .{
29013261 .id_result_type = u32_ty_id,
29023262 .id_result = result_limbs[k],
29033263 .composite = add2,
29043264 .indexes = &.{0},
29053265 });
2906 const c2 = cg.module.allocId();
3266 const c2 = cg.allocId();
29073267 try cg.body.emit(gpa, .OpCompositeExtract, .{
29083268 .id_result_type = u32_ty_id,
29093269 .id_result = c2,
......@@ -2925,8 +3285,8 @@ const CompositeInt = struct {
29253285 fn normalize(ci: CompositeInt) !CompositeInt {
29263286 if (ci.info.bits == ci.info.backing_bits) return ci;
29273287 const cg = ci.cg;
2928 const gpa = cg.module.gpa;
2929 const top_bits: u16 = ci.info.bits % Module.big_int_bits;
3288 const gpa = cg.gpa;
3289 const top_bits: u16 = ci.info.bits % big_int_bits;
29303290 assert(top_bits != 0);
29313291
29323292 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
......@@ -2947,25 +3307,27 @@ const CompositeInt = struct {
29473307 const shift_amt: u32 = 32 - top_bits;
29483308 const shift_id = try cg.constInt(.u32, shift_amt);
29493309
2950 const as_signed = cg.module.allocId();
3310 const as_signed = cg.allocId();
29513311 try cg.body.emit(gpa, .OpBitcast, .{
29523312 .id_result_type = i32_ty_id,
29533313 .id_result = as_signed,
29543314 .operand = top_limb,
29553315 });
2956 const shifted_left = cg.module.allocId();
2957 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);
2958 cg.body.writeOperand(Id, i32_ty_id);
2959 cg.body.writeOperand(Id, shifted_left);
2960 cg.body.writeOperand(Id, as_signed);
2961 cg.body.writeOperand(Id, shift_id);
2962 const shifted_right = cg.module.allocId();
2963 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
2964 cg.body.writeOperand(Id, i32_ty_id);
2965 cg.body.writeOperand(Id, shifted_right);
2966 cg.body.writeOperand(Id, shifted_left);
2967 cg.body.writeOperand(Id, shift_id);
2968 const back = cg.module.allocId();
3316 const shifted_left = cg.allocId();
3317 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
3318 .id_result_type = i32_ty_id,
3319 .id_result = shifted_left,
3320 .base = as_signed,
3321 .shift = shift_id,
3322 });
3323 const shifted_right = cg.allocId();
3324 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
3325 .id_result_type = i32_ty_id,
3326 .id_result = shifted_right,
3327 .base = shifted_left,
3328 .shift = shift_id,
3329 });
3330 const back = cg.allocId();
29693331 try cg.body.emit(gpa, .OpBitcast, .{
29703332 .id_result_type = u32_ty_id,
29713333 .id_result = back,
......@@ -3000,7 +3362,7 @@ const Vectorization = union(enum) {
30003362
30013363 /// Derive a vectorization from a particular type
30023364 fn fromType(ty: Type, cg: *CodeGen) Vectorization {
3003 const zcu = cg.module.zcu;
3365 const zcu = cg.zcu;
30043366 if (!ty.isVector(zcu)) return .scalar;
30053367 return .{ .unrolled = ty.vectorLen(zcu) };
30063368 }
......@@ -3034,7 +3396,7 @@ const Vectorization = union(enum) {
30343396 /// `ty` may be a scalar or vector, it doesn't matter.
30353397 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {
30363398 const pt = cg.pt;
3037 const zcu = cg.module.zcu;
3399 const zcu = cg.zcu;
30383400 const scalar_ty = ty.scalarType(zcu);
30393401 return switch (vec) {
30403402 .scalar => scalar_ty,
......@@ -3046,7 +3408,7 @@ const Vectorization = union(enum) {
30463408 /// this setup, and returns a new type that holds the relevant information on how to access
30473409 /// elements of the input.
30483410 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {
3049 const zcu = cg.module.zcu;
3411 const zcu = cg.zcu;
30503412 const is_vector = tmp.ty.isVector(zcu);
30513413 const value: PreparedOperand.Value = switch (tmp.value) {
30523414 .singleton => |id| switch (vec) {
......@@ -3146,26 +3508,28 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {
31463508/// This function builds an OpSConvert of OpUConvert depending on the
31473509/// signedness of the types.
31483510fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
3149 const zcu = cg.module.zcu;
3150
3151 const dst_ty_id = try cg.resolveType(dst_ty.scalarType(zcu), .direct);
3152 const src_ty_id = try cg.resolveType(src.ty.scalarType(zcu), .direct);
3511 const zcu = cg.zcu;
31533512
31543513 const v = cg.vectorization(.{ dst_ty, src });
31553514 const result_ty = try v.resultType(cg, dst_ty);
31563515
3157 // We can directly compare integers, because those type-IDs are cached.
3158 if (dst_ty_id == src_ty_id) {
3159 // Nothing to do, type-pun to the right value.
3160 // Note, Caller guarantees that the types fit (or caller will normalize after),
3161 // so we don't have to normalize here.
3162 // Note, dst_ty may be a scalar type even if we expect a vector, so we have to
3163 // convert to the right type here.
3516 const dst_scalar = dst_ty.scalarType(zcu);
3517 const src_scalar = src.ty.scalarType(zcu);
3518 if (dst_scalar.toIntern() == src_scalar.toIntern()) {
31643519 return src.pun(result_ty);
31653520 }
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
31673531 const ops = v.components();
3168 const results = cg.module.allocIds(ops);
3532 const results = cg.allocIds(ops);
31693533
31703534 const op_result_ty = dst_ty.scalarType(zcu);
31713535 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 {
31793543 const op_src = try v.prepare(cg, src);
31803544
31813545 for (0..ops) |i| {
3182 try cg.body.emitRaw(cg.module.gpa, opcode, 3);
3546 try cg.body.emitRaw(cg.gpa, opcode, 3);
31833547 cg.body.writeOperand(Id, op_result_ty_id);
31843548 cg.body.writeOperand(Id, results.at(i));
31853549 cg.body.writeOperand(Id, op_src.at(i));
......@@ -3188,51 +3552,12 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
31883552 return v.finalize(result_ty, results);
31893553}
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
32303555fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary {
3231 const zcu = cg.module.zcu;
3556 const zcu = cg.zcu;
32323557
32333558 const v = cg.vectorization(.{ condition, lhs, rhs });
32343559 const ops = v.components();
3235 const results = cg.module.allocIds(ops);
3560 const results = cg.allocIds(ops);
32363561
32373562 const op_result_ty = lhs.ty.scalarType(zcu);
32383563 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
32453570 const object_2 = try v.prepare(cg, rhs);
32463571
32473572 for (0..ops) |i| {
3248 try cg.body.emit(cg.module.gpa, .OpSelect, .{
3573 try cg.body.emit(cg.gpa, .OpSelect, .{
32493574 .id_result_type = op_result_ty_id,
32503575 .id_result = results.at(i),
32513576 .condition = cond.at(i),
......@@ -3260,7 +3585,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar
32603585fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
32613586 const v = cg.vectorization(.{ lhs, rhs });
32623587 const ops = v.components();
3263 const results = cg.module.allocIds(ops);
3588 const results = cg.allocIds(ops);
32643589
32653590 const op_result_ty: Type = .bool;
32663591 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
32703595 const op_rhs = try v.prepare(cg, rhs);
32713596
32723597 for (0..ops) |i| {
3273 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
3598 try cg.body.emitRaw(cg.gpa, opcode, 4);
32743599 cg.body.writeOperand(Id, op_result_ty_id);
32753600 cg.body.writeOperand(Id, results.at(i));
32763601 cg.body.writeOperand(Id, op_lhs.at(i));
......@@ -3351,11 +3676,11 @@ const UnaryOp = enum {
33513676};
33523677
33533678fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
3354 const zcu = cg.module.zcu;
3355 const target = cg.module.zcu.getTarget();
3679 const zcu = cg.zcu;
3680 const target = cg.zcu.getTarget();
33563681 const v = cg.vectorization(.{operand});
33573682 const ops = v.components();
3358 const results = cg.module.allocIds(ops);
3683 const results = cg.allocIds(ops);
33593684 const op_result_ty = operand.ty.scalarType(zcu);
33603685 const op_result_ty_id = try cg.resolveType(op_result_ty, .direct);
33613686 const result_ty = try v.resultType(cg, operand.ty);
......@@ -3364,7 +3689,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
33643689 if (op.extInstOpcode(target)) |opcode| {
33653690 const set = try cg.importExtendedSet();
33663691 for (0..ops) |i| {
3367 try cg.body.emit(cg.module.gpa, .OpExtInst, .{
3692 try cg.body.emit(cg.gpa, .OpExtInst, .{
33683693 .id_result_type = op_result_ty_id,
33693694 .id_result = results.at(i),
33703695 .set = set,
......@@ -3384,7 +3709,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
33843709 ),
33853710 };
33863711 for (0..ops) |i| {
3387 try cg.body.emitRaw(cg.module.gpa, opcode, 3);
3712 try cg.body.emitRaw(cg.gpa, opcode, 3);
33883713 cg.body.writeOperand(Id, op_result_ty_id);
33893714 cg.body.writeOperand(Id, results.at(i));
33903715 cg.body.writeOperand(Id, op_operand.at(i));
......@@ -3395,11 +3720,11 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
33953720}
33963721
33973722fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary {
3398 const zcu = cg.module.zcu;
3723 const zcu = cg.zcu;
33993724
34003725 const v = cg.vectorization(.{ lhs, rhs });
34013726 const ops = v.components();
3402 const results = cg.module.allocIds(ops);
3727 const results = cg.allocIds(ops);
34033728
34043729 const op_result_ty = lhs.ty.scalarType(zcu);
34053730 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
34093734 const op_rhs = try v.prepare(cg, rhs);
34103735
34113736 for (0..ops) |i| {
3412 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
3737 try cg.body.emitRaw(cg.gpa, opcode, 4);
34133738 cg.body.writeOperand(Id, op_result_ty_id);
34143739 cg.body.writeOperand(Id, results.at(i));
34153740 cg.body.writeOperand(Id, op_lhs.at(i));
......@@ -3428,11 +3753,11 @@ fn buildWideMul(
34283753 rhs: Temporary,
34293754) !struct { Temporary, Temporary } {
34303755 const pt = cg.pt;
3431 const zcu = cg.module.zcu;
3756 const zcu = cg.zcu;
34323757 const comp = zcu.comp;
34333758 const gpa = comp.gpa;
34343759 const io = comp.io;
3435 const target = cg.module.zcu.getTarget();
3760 const target = cg.zcu.getTarget();
34363761 const ip = &zcu.intern_pool;
34373762
34383763 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));
......@@ -3444,8 +3769,8 @@ fn buildWideMul(
34443769 const lhs_op = try v.prepare(cg, lhs);
34453770 const rhs_op = try v.prepare(cg, rhs);
34463771
3447 const value_results = cg.module.allocIds(ops);
3448 const overflow_results = cg.module.allocIds(ops);
3772 const value_results = cg.allocIds(ops);
3773 const overflow_results = cg.allocIds(ops);
34493774
34503775 switch (target.os.tag) {
34513776 .opencl => {
......@@ -3490,7 +3815,7 @@ fn buildWideMul(
34903815 };
34913816
34923817 for (0..ops) |i| {
3493 const op_result = cg.module.allocId();
3818 const op_result = cg.allocId();
34943819
34953820 try cg.body.emitRaw(gpa, opcode, 4);
34963821 cg.body.writeOperand(Id, op_result_ty_id);
......@@ -3550,12 +3875,12 @@ fn buildWideMul(
35503875fn generateTestEntryPoint(
35513876 cg: *CodeGen,
35523877 name: []const u8,
3553 spv_decl_index: Module.Decl.Index,
3878 spv_decl_index: Decl.Index,
35543879 test_id: Id,
35553880) !void {
3556 const gpa = cg.module.gpa;
3557 const zcu = cg.module.zcu;
3558 const target = cg.module.zcu.getTarget();
3881 const gpa = cg.gpa;
3882 const zcu = cg.zcu;
3883 const target = cg.zcu.getTarget();
35593884
35603885 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);
35613886 const ptr_anyerror_ty = try cg.pt.ptrType(.{
......@@ -3564,15 +3889,15 @@ fn generateTestEntryPoint(
35643889 });
35653890 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();
35723897 switch (target.os.tag) {
35733898 .opencl, .amdhsa => {
35743899 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
35773902 try section.emit(gpa, .OpFunction, .{
35783903 .id_result_type = try cg.resolveType(.void, .direct),
......@@ -3587,43 +3912,43 @@ fn generateTestEntryPoint(
35873912 });
35883913
35893914 try section.emit(gpa, .OpLabel, .{
3590 .id_result = cg.module.allocId(),
3915 .id_result = cg.allocId(),
35913916 });
35923917 },
35933918 .vulkan, .opengl => {
3594 if (cg.module.error_buffer == null) {
3595 const spv_err_decl_index = try cg.module.allocDecl(.global);
3596 const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id;
3919 if (cg.error_buffer == null) {
3920 const spv_err_decl_index = try cg.allocDecl(.global);
3921 const err_buf_result_id = cg.declPtr(spv_err_decl_index).result_id;
35973922
3598 const buffer_struct_ty_id = cg.module.allocId();
3599 try cg.module.sections.globals.emit(gpa, .OpTypeStruct, .{
3923 const buffer_struct_ty_id = cg.allocId();
3924 try cg.sections.globals.emit(gpa, .OpTypeStruct, .{
36003925 .id_result = buffer_struct_ty_id,
36013926 .id_ref = &.{anyerror_ty_id},
36023927 });
3603 try cg.module.memberDebugName(buffer_struct_ty_id, 0, "error_out");
3604 try cg.module.decorate(buffer_struct_ty_id, .block);
3605 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
3928 try cg.memberDebugName(buffer_struct_ty_id, 0, "error_out");
3929 try cg.decorate(buffer_struct_ty_id, .block);
3930 try cg.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
36063931
3607 const ptr_buffer_struct_ty_id = cg.module.allocId();
3608 try cg.module.sections.globals.emit(gpa, .OpTypePointer, .{
3932 const ptr_buffer_struct_ty_id = cg.allocId();
3933 try cg.sections.globals.emit(gpa, .OpTypePointer, .{
36093934 .id_result = ptr_buffer_struct_ty_id,
3610 .storage_class = cg.module.storageClass(.global),
3935 .storage_class = cg.storageClass(.global),
36113936 .type = buffer_struct_ty_id,
36123937 });
36133938
3614 try cg.module.sections.globals.emit(gpa, .OpVariable, .{
3939 try cg.sections.globals.emit(gpa, .OpVariable, .{
36153940 .id_result_type = ptr_buffer_struct_ty_id,
36163941 .id_result = err_buf_result_id,
3617 .storage_class = cg.module.storageClass(.global),
3942 .storage_class = cg.storageClass(.global),
36183943 });
3619 try cg.module.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } });
3620 try cg.module.decorate(err_buf_result_id, .{ .binding = .{ .binding_point = 0 } });
3944 try cg.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 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;
36233948 }
36243949
36253950 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, &.{});
36273952 try section.emit(gpa, .OpFunction, .{
36283953 .id_result_type = try cg.resolveType(.void, .direct),
36293954 .id_result = kernel_id,
......@@ -3631,12 +3956,12 @@ fn generateTestEntryPoint(
36313956 .function_type = kernel_proto_ty_id,
36323957 });
36333958 try section.emit(gpa, .OpLabel, .{
3634 .id_result = cg.module.allocId(),
3959 .id_result = cg.allocId(),
36353960 });
36363961
3637 const spv_err_decl_index = cg.module.error_buffer.?;
3638 const buffer_id = cg.module.declPtr(spv_err_decl_index).result_id;
3639 try cg.module.decl_deps.append(gpa, spv_err_decl_index);
3962 const spv_err_decl_index = cg.error_buffer.?;
3963 const buffer_id = cg.declPtr(spv_err_decl_index).result_id;
3964 try cg.decl_deps.append(gpa, spv_err_decl_index);
36403965
36413966 const zero_id = try cg.constInt(.u32, 0);
36423967 try section.emit(gpa, .OpInBoundsAccessChain, .{
......@@ -3649,7 +3974,7 @@ fn generateTestEntryPoint(
36493974 else => unreachable,
36503975 }
36513976
3652 const error_id = cg.module.allocId();
3977 const error_id = cg.allocId();
36533978 try section.emit(gpa, .OpFunctionCall, .{
36543979 .id_result_type = anyerror_ty_id,
36553980 .id_result = error_id,
......@@ -3668,9 +3993,14 @@ fn generateTestEntryPoint(
36683993
36693994 // Just generate a quick other name because the intel runtime crashes when the entry-
36703995 // 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 };
36744004}
36754005
36764006fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
......@@ -3688,7 +4018,7 @@ fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
36884018/// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct).
36894019fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
36904020 const pt = cg.pt;
3691 const zcu = cg.module.zcu;
4021 const zcu = cg.zcu;
36924022 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
36934023 .bool => {
36944024 const false_id = try cg.constBool(false, .indirect);
......@@ -3714,7 +4044,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
37144044/// Convert representation from direct (in 'register) to direct (in memory)
37154045/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).
37164046fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
3717 const zcu = cg.module.zcu;
4047 const zcu = cg.zcu;
37184048 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
37194049 .bool => {
37204050 const result = try cg.intFromBool(.init(ty, operand_id), .u1);
......@@ -3726,9 +4056,9 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
37264056
37274057fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
37284058 const result_ty_id = try cg.resolveType(result_ty, .indirect);
3729 const result_id = cg.module.allocId();
4059 const result_id = cg.allocId();
37304060 const indexes = [_]u32{field};
3731 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
4061 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
37324062 .id_result_type = result_ty_id,
37334063 .id_result = result_id,
37344064 .composite = object,
......@@ -3740,9 +4070,9 @@ fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id {
37404070
37414071fn extractVectorComponent(cg: *CodeGen, result_ty: Type, vector_id: Id, field: u32) !Id {
37424072 const result_ty_id = try cg.resolveType(result_ty, .direct);
3743 const result_id = cg.module.allocId();
4073 const result_id = cg.allocId();
37444074 const indexes = [_]u32{field};
3745 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
4075 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
37464076 .id_result_type = result_ty_id,
37474077 .id_result = result_id,
37484078 .composite = vector_id,
......@@ -3757,15 +4087,15 @@ const MemoryOptions = struct {
37574087};
37584088
37594089fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
3760 const zcu = cg.module.zcu;
4090 const zcu = cg.zcu;
37614091 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);
37624092 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);
3763 const result_id = cg.module.allocId();
4093 const result_id = cg.allocId();
37644094 const access: spec.MemoryAccess.Extended = .{
37654095 .@"volatile" = options.is_volatile,
37664096 .aligned = .{ .literal_integer = alignment },
37674097 };
3768 try cg.body.emit(cg.module.gpa, .OpLoad, .{
4098 try cg.body.emit(cg.gpa, .OpLoad, .{
37694099 .id_result_type = indirect_value_ty_id,
37704100 .id_result = result_id,
37714101 .pointer = ptr_id,
......@@ -3777,7 +4107,7 @@ fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
37774107fn store(cg: *CodeGen, value_ty: Type, ptr_id: Id, value_id: Id, options: MemoryOptions) !void {
37784108 const indirect_value_id = try cg.convertToIndirect(value_ty, value_id);
37794109 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, .{
37814111 .pointer = ptr_id,
37824112 .object = indirect_value_id,
37834113 .memory_access = access,
......@@ -3791,8 +4121,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {
37914121}
37924122
37934123fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
3794 const gpa = cg.module.gpa;
3795 const zcu = cg.module.zcu;
4124 const gpa = cg.gpa;
4125 const zcu = cg.zcu;
37964126 const ip = &zcu.intern_pool;
37974127 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))
37984128 return;
......@@ -4028,7 +4358,7 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {
40284358}
40294359
40304360fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id {
4031 const zcu = cg.module.zcu;
4361 const zcu = cg.zcu;
40324362 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
40334363
40344364 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
40484378 .composite_integer => blk: {
40494379 const shift_id = try shift.materialize(cg);
40504380 const u32_ty_id = try cg.resolveType(.u32, .direct);
4051 const result_id = cg.module.allocId();
4052 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
4381 const result_id = cg.allocId();
4382 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
40534383 .id_result_type = u32_ty_id,
40544384 .id_result = result_id,
40554385 .composite = shift_id,
......@@ -4156,13 +4486,13 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id {
41564486}
41574487
41584488fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
4159 const zcu = cg.module.zcu;
4489 const zcu = cg.zcu;
41604490 const target = zcu.getTarget();
41614491 const info = cg.arithmeticTypeInfo(lhs.ty);
41624492
41634493 const v = cg.vectorization(.{ lhs, rhs });
41644494 const ops = v.components();
4165 const results = cg.module.allocIds(ops);
4495 const results = cg.allocIds(ops);
41664496
41674497 const op_result_ty = lhs.ty.scalarType(zcu);
41684498 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 {
41744504 const set = try cg.importExtendedSet();
41754505 const opcode = op.extInstOpcode(target, info);
41764506 for (0..ops) |i| {
4177 try cg.body.emit(cg.module.gpa, .OpExtInst, .{
4507 try cg.body.emit(cg.gpa, .OpExtInst, .{
41784508 .id_result_type = op_result_ty_id,
41794509 .id_result = results.at(i),
41804510 .set = set,
......@@ -4195,7 +4525,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
41954525/// All other values are returned unmodified (this makes strange integer
41964526/// wrapping easier to use in generic operations).
41974527fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {
4198 const zcu = cg.module.zcu;
4528 const zcu = cg.zcu;
41994529 const ty = value.ty;
42004530 switch (info.class) {
42014531 .integer, .bool, .float => return value,
......@@ -4341,29 +4671,24 @@ fn airArithOp(
43414671}
43424672
43434673fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4674 const zcu = cg.zcu;
4675 const target = zcu.getTarget();
43444676 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4345 const operand = try cg.temporary(ty_op.operand);
4346 // Note: operand_ty may be signed, while ty is always unsigned!
4677 const value = try cg.temporary(ty_op.operand);
4678 // Note: operand_ty may be signed, while ty is always unsigned.
43474679 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();
43554680 const operand_info = cg.arithmeticTypeInfo(value.ty);
4356 switch (operand_info.class) {
4357 .float => return try cg.buildUnary(.f_abs, value),
4358 .integer, .strange_integer => {
4681 const result: Temporary = switch (operand_info.class) {
4682 .float => try cg.buildUnary(.f_abs, value),
4683 .integer, .strange_integer => abs: {
43594684 var abs_value = try cg.buildUnary(.i_abs, value);
43604685 switch (target.os.tag) {
43614686 .vulkan, .opengl => {
43624687 if (value.ty.intInfo(zcu).signedness == .signed) {
43634688 const abs_id = try abs_value.materialize(cg);
43644689 const dst_ty_id = try cg.resolveType(result_ty, .direct);
4365 const cast_id = cg.module.allocId();
4366 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
4690 const cast_id = cg.allocId();
4691 try cg.body.emit(cg.gpa, .OpBitcast, .{
43674692 .id_result_type = dst_ty_id,
43684693 .id_result = cast_id,
43694694 .operand = abs_id,
......@@ -4373,9 +4698,9 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
43734698 },
43744699 else => {},
43754700 }
4376 return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
4701 break :abs try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
43774702 },
4378 .composite_integer => {
4703 .composite_integer => abs: {
43794704 const val_id = try value.materialize(cg);
43804705 const scratch_top = cg.id_scratch.items.len;
43814706 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
......@@ -4385,10 +4710,10 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
43854710 const ci_neg = try ci_z.addSub(ci, false);
43864711 const result_info = cg.arithmeticTypeInfo(result_ty);
43874712 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);
43894714 for (0..ci.n_limbs) |i| {
4390 result_limbs[i] = cg.module.allocId();
4391 try cg.body.emit(cg.module.gpa, .OpSelect, .{
4715 result_limbs[i] = cg.allocId();
4716 try cg.body.emit(cg.gpa, .OpSelect, .{
43924717 .id_result_type = u32_ty_id,
43934718 .id_result = result_limbs[i],
43944719 .condition = is_neg,
......@@ -4398,10 +4723,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
43984723 }
43994724 const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info);
44004725 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));
44024727 },
44034728 .bool => unreachable,
4404 }
4729 };
4730 return try result.materialize(cg);
44054731}
44064732
44074733fn airAddSubOverflow(
......@@ -4457,32 +4783,36 @@ fn airAddSubOverflow(
44574783 const res_neg = try ci_res2.cmp(ci_z, .lt);
44584784
44594785 const bool_ty_id = try cg.resolveType(.bool, .direct);
4460 const signs_match = cg.module.allocId();
4461 try cg.body.emitRaw(cg.module.gpa, .OpLogicalEqual, 4);
4462 cg.body.writeOperand(Id, bool_ty_id);
4463 cg.body.writeOperand(Id, signs_match);
4464 cg.body.writeOperand(Id, lhs_neg);
4465 cg.body.writeOperand(Id, rhs_neg);
4466 const res_sign_diff = cg.module.allocId();
4467 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNotEqual, 4);
4468 cg.body.writeOperand(Id, bool_ty_id);
4469 cg.body.writeOperand(Id, res_sign_diff);
4470 cg.body.writeOperand(Id, lhs_neg);
4471 cg.body.writeOperand(Id, res_neg);
4786 const signs_match = cg.allocId();
4787 try cg.body.emit(cg.gpa, .OpLogicalEqual, .{
4788 .id_result_type = bool_ty_id,
4789 .id_result = signs_match,
4790 .operand_1 = lhs_neg,
4791 .operand_2 = rhs_neg,
4792 });
4793 const res_sign_diff = cg.allocId();
4794 try cg.body.emit(cg.gpa, .OpLogicalNotEqual, .{
4795 .id_result_type = bool_ty_id,
4796 .id_result = res_sign_diff,
4797 .operand_1 = lhs_neg,
4798 .operand_2 = res_neg,
4799 });
44724800 const ov_cond = if (add == .OpIAdd) signs_match else blk2: {
4473 const not_match = cg.module.allocId();
4474 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNot, 3);
4475 cg.body.writeOperand(Id, bool_ty_id);
4476 cg.body.writeOperand(Id, not_match);
4477 cg.body.writeOperand(Id, signs_match);
4801 const not_match = cg.allocId();
4802 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
4803 .id_result_type = bool_ty_id,
4804 .id_result = not_match,
4805 .operand = signs_match,
4806 });
44784807 break :blk2 not_match;
44794808 };
4480 const ov_result = cg.module.allocId();
4481 try cg.body.emitRaw(cg.module.gpa, .OpLogicalAnd, 4);
4482 cg.body.writeOperand(Id, bool_ty_id);
4483 cg.body.writeOperand(Id, ov_result);
4484 cg.body.writeOperand(Id, ov_cond);
4485 cg.body.writeOperand(Id, res_sign_diff);
4809 const ov_result = cg.allocId();
4810 try cg.body.emit(cg.gpa, .OpLogicalAnd, .{
4811 .id_result_type = bool_ty_id,
4812 .id_result = ov_result,
4813 .operand_1 = ov_cond,
4814 .operand_2 = res_sign_diff,
4815 });
44864816 break :blk ov_result;
44874817 },
44884818 };
......@@ -4531,7 +4861,7 @@ fn airAddSubOverflow(
45314861
45324862fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45334863 const pt = cg.pt;
4534 const gpa = cg.module.gpa;
4864 const gpa = cg.gpa;
45354865 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
45364866 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
45374867 const lhs = try cg.temporary(extra.lhs);
......@@ -4559,32 +4889,35 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45594889
45604890 const bool_ty_id = try cg.resolveType(.bool, .direct);
45614891 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
45644894 const ov_bool = switch (info.signedness) {
45654895 .unsigned => blk: {
45664896 const zero_id = try cg.constInt(.u32, @as(u32, 0));
4567 var any_nonzero = cg.module.allocId();
4568 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4569 cg.body.writeOperand(Id, bool_ty_id);
4570 cg.body.writeOperand(Id, any_nonzero);
4571 cg.body.writeOperand(Id, high_limbs[0]);
4572 cg.body.writeOperand(Id, zero_id);
4897 var any_nonzero = cg.allocId();
4898 try cg.body.emit(gpa, .OpINotEqual, .{
4899 .id_result_type = bool_ty_id,
4900 .id_result = any_nonzero,
4901 .operand_1 = high_limbs[0],
4902 .operand_2 = zero_id,
4903 });
45734904
45744905 for (1..n) |i| {
4575 const limb_nz = cg.module.allocId();
4576 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4577 cg.body.writeOperand(Id, bool_ty_id);
4578 cg.body.writeOperand(Id, limb_nz);
4579 cg.body.writeOperand(Id, high_limbs[i]);
4580 cg.body.writeOperand(Id, zero_id);
4581
4582 const combined = cg.module.allocId();
4583 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4584 cg.body.writeOperand(Id, bool_ty_id);
4585 cg.body.writeOperand(Id, combined);
4586 cg.body.writeOperand(Id, any_nonzero);
4587 cg.body.writeOperand(Id, limb_nz);
4906 const limb_nz = cg.allocId();
4907 try cg.body.emit(gpa, .OpINotEqual, .{
4908 .id_result_type = bool_ty_id,
4909 .id_result = limb_nz,
4910 .operand_1 = high_limbs[i],
4911 .operand_2 = zero_id,
4912 });
4913
4914 const combined = cg.allocId();
4915 try cg.body.emit(gpa, .OpLogicalOr, .{
4916 .id_result_type = bool_ty_id,
4917 .id_result = combined,
4918 .operand_1 = any_nonzero,
4919 .operand_2 = limb_nz,
4920 });
45884921 any_nonzero = combined;
45894922 }
45904923
......@@ -4595,92 +4928,99 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45954928 const top_limb = ci_res.limbs[n - 1];
45964929 const i32_ty_id = try cg.resolveType(.i32, .direct);
45974930
4598 const top_bits: u16 = if (info.bits % Module.big_int_bits == 0)
4599 Module.big_int_bits
4931 const top_bits: u16 = if (info.bits % big_int_bits == 0)
4932 big_int_bits
46004933 else
4601 info.bits % Module.big_int_bits;
4934 info.bits % big_int_bits;
46024935
46034936 const shift_amt: u32 = top_bits - 1;
46044937 const shift_id = try cg.constInt(.u32, shift_amt);
46054938
4606 const as_signed = cg.module.allocId();
4939 const as_signed = cg.allocId();
46074940 try cg.body.emit(gpa, .OpBitcast, .{
46084941 .id_result_type = i32_ty_id,
46094942 .id_result = as_signed,
46104943 .operand = top_limb,
46114944 });
4612 const sign_ext = cg.module.allocId();
4613 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
4614 cg.body.writeOperand(Id, i32_ty_id);
4615 cg.body.writeOperand(Id, sign_ext);
4616 cg.body.writeOperand(Id, as_signed);
4617 cg.body.writeOperand(Id, shift_id);
4618 const expected = cg.module.allocId();
4945 const sign_ext = cg.allocId();
4946 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4947 .id_result_type = i32_ty_id,
4948 .id_result = sign_ext,
4949 .base = as_signed,
4950 .shift = shift_id,
4951 });
4952 const expected = cg.allocId();
46194953 try cg.body.emit(gpa, .OpBitcast, .{
46204954 .id_result_type = u32_ty_id,
46214955 .id_result = expected,
46224956 .operand = sign_ext,
46234957 });
46244958
4625 var any_mismatch = cg.module.allocId();
4626 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4627 cg.body.writeOperand(Id, bool_ty_id);
4628 cg.body.writeOperand(Id, any_mismatch);
4629 cg.body.writeOperand(Id, high_limbs[0]);
4630 cg.body.writeOperand(Id, expected);
4959 var any_mismatch = cg.allocId();
4960 try cg.body.emit(gpa, .OpINotEqual, .{
4961 .id_result_type = bool_ty_id,
4962 .id_result = any_mismatch,
4963 .operand_1 = high_limbs[0],
4964 .operand_2 = expected,
4965 });
46314966
46324967 for (1..n) |i| {
4633 const limb_ne = cg.module.allocId();
4634 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4635 cg.body.writeOperand(Id, bool_ty_id);
4636 cg.body.writeOperand(Id, limb_ne);
4637 cg.body.writeOperand(Id, high_limbs[i]);
4638 cg.body.writeOperand(Id, expected);
4639
4640 const combined = cg.module.allocId();
4641 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4642 cg.body.writeOperand(Id, bool_ty_id);
4643 cg.body.writeOperand(Id, combined);
4644 cg.body.writeOperand(Id, any_mismatch);
4645 cg.body.writeOperand(Id, limb_ne);
4968 const limb_ne = cg.allocId();
4969 try cg.body.emit(gpa, .OpINotEqual, .{
4970 .id_result_type = bool_ty_id,
4971 .id_result = limb_ne,
4972 .operand_1 = high_limbs[i],
4973 .operand_2 = expected,
4974 });
4975
4976 const combined = cg.allocId();
4977 try cg.body.emit(gpa, .OpLogicalOr, .{
4978 .id_result_type = bool_ty_id,
4979 .id_result = combined,
4980 .operand_1 = any_mismatch,
4981 .operand_2 = limb_ne,
4982 });
46464983 any_mismatch = combined;
46474984 }
46484985
46494986 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;
46514988 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();
46544991 try cg.body.emit(gpa, .OpBitcast, .{
46554992 .id_result_type = i32_ty_id,
46564993 .id_result = top_as_signed,
46574994 .operand = top_limb,
46584995 });
4659 const top_sign_ext = cg.module.allocId();
4660 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
4661 cg.body.writeOperand(Id, i32_ty_id);
4662 cg.body.writeOperand(Id, top_sign_ext);
4663 cg.body.writeOperand(Id, top_as_signed);
4664 cg.body.writeOperand(Id, s_shift_id);
4665 const top_expected = cg.module.allocId();
4996 const top_sign_ext = cg.allocId();
4997 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
4998 .id_result_type = i32_ty_id,
4999 .id_result = top_sign_ext,
5000 .base = top_as_signed,
5001 .shift = s_shift_id,
5002 });
5003 const top_expected = cg.allocId();
46665004 try cg.body.emit(gpa, .OpBitcast, .{
46675005 .id_result_type = u32_ty_id,
46685006 .id_result = top_expected,
46695007 .operand = top_sign_ext,
46705008 });
4671 const top_mismatch = cg.module.allocId();
4672 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4673 cg.body.writeOperand(Id, bool_ty_id);
4674 cg.body.writeOperand(Id, top_mismatch);
4675 cg.body.writeOperand(Id, top_limb);
4676 cg.body.writeOperand(Id, top_expected);
4677
4678 const combined = cg.module.allocId();
4679 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4680 cg.body.writeOperand(Id, bool_ty_id);
4681 cg.body.writeOperand(Id, combined);
4682 cg.body.writeOperand(Id, any_mismatch);
4683 cg.body.writeOperand(Id, top_mismatch);
5009 const top_mismatch = cg.allocId();
5010 try cg.body.emit(gpa, .OpINotEqual, .{
5011 .id_result_type = bool_ty_id,
5012 .id_result = top_mismatch,
5013 .operand_1 = top_limb,
5014 .operand_2 = top_expected,
5015 });
5016
5017 const combined = cg.allocId();
5018 try cg.body.emit(gpa, .OpLogicalOr, .{
5019 .id_result_type = bool_ty_id,
5020 .id_result = combined,
5021 .operand_1 = any_mismatch,
5022 .operand_2 = top_mismatch,
5023 });
46845024 any_mismatch = combined;
46855025 }
46865026
......@@ -4702,7 +5042,8 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
47025042 // - Additionally, if info.bits != 32, we'll have to check the high bits
47035043 // 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;
47065047 // If non-null, the number of bits that the multiplication should be performed in. If
47075048 // null, we have to use wide multiplication.
47085049 const maybe_op_ty_bits: ?u16 = switch (info.bits) {
......@@ -4846,7 +5187,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
48465187}
48475188
48485189fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4849 const zcu = cg.module.zcu;
5190 const zcu = cg.zcu;
48505191
48515192 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
48525193 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -4898,14 +5239,48 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
48985239 const info = cg.arithmeticTypeInfo(result_ty);
48995240 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);
49025277 return try result.materialize(cg);
49035278}
49045279
49055280fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {
49065281 if (cg.liveness.isUnused(inst)) return null;
49075282
4908 const zcu = cg.module.zcu;
5283 const zcu = cg.zcu;
49095284 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
49105285 const operand = try cg.temporary(ty_op.operand);
49115286
......@@ -4948,7 +5323,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
49485323}
49495324
49505325fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4951 const zcu = cg.module.zcu;
5326 const zcu = cg.zcu;
49525327 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
49535328 const operand = try cg.resolve(reduce.operand);
49545329 const operand_ty = cg.typeOf(reduce.operand);
......@@ -5016,7 +5391,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
50165391}
50175392
50185393fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5019 const zcu = cg.module.zcu;
5394 const zcu = cg.zcu;
50205395 const gpa = zcu.gpa;
50215396
50225397 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);
......@@ -5041,7 +5416,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
50415416}
50425417
50435418fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5044 const zcu = cg.module.zcu;
5419 const zcu = cg.zcu;
50455420 const gpa = zcu.gpa;
50465421
50475422 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);
......@@ -5060,7 +5435,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
50605435 id.* = switch (mask_elem.unwrap()) {
50615436 .a_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_a, idx),
50625437 .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),
50645439 };
50655440 }
50665441
......@@ -5074,8 +5449,8 @@ fn accessChainId(
50745449 base: Id,
50755450 indices: []const Id,
50765451) !Id {
5077 const result_id = cg.module.allocId();
5078 try cg.body.emit(cg.module.gpa, .OpInBoundsAccessChain, .{
5452 const result_id = cg.allocId();
5453 try cg.body.emit(cg.gpa, .OpInBoundsAccessChain, .{
50795454 .id_result_type = result_ty_id,
50805455 .id_result = result_id,
50815456 .base = base,
......@@ -5094,7 +5469,7 @@ fn accessChain(
50945469 base: Id,
50955470 indices: []const u32,
50965471) !Id {
5097 const gpa = cg.module.gpa;
5472 const gpa = cg.gpa;
50985473 const scratch_top = cg.id_scratch.items.len;
50995474 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
51005475 const ids = try cg.id_scratch.addManyAsSlice(gpa, indices.len);
......@@ -5111,8 +5486,8 @@ fn ptrAccessChain(
51115486 element: Id,
51125487 indices: []const u32,
51135488) !Id {
5114 const gpa = cg.module.gpa;
5115 const target = cg.module.zcu.getTarget();
5489 const gpa = cg.gpa;
5490 const target = cg.zcu.getTarget();
51165491
51175492 const scratch_top = cg.id_scratch.items.len;
51185493 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
......@@ -5121,7 +5496,7 @@ fn ptrAccessChain(
51215496 id.* = try cg.constInt(.u32, index);
51225497 }
51235498
5124 const result_id = cg.module.allocId();
5499 const result_id = cg.allocId();
51255500 switch (target.os.tag) {
51265501 .opencl, .amdhsa => {
51275502 try cg.body.emit(gpa, .OpInBoundsPtrAccessChain, .{
......@@ -5147,7 +5522,7 @@ fn ptrAccessChain(
51475522}
51485523
51495524fn 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;
51515526 const result_ty_id = try cg.resolveType(result_ty, .direct);
51525527
51535528 switch (ptr_ty.ptrSize(zcu)) {
......@@ -5188,8 +5563,8 @@ fn airPtrSub(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
51885563 const offset_ty_id = try cg.resolveType(offset_ty, .direct);
51895564 const result_ty = cg.typeOfIndex(inst);
51905565
5191 const negative_offset_id = cg.module.allocId();
5192 try cg.body.emit(cg.module.gpa, .OpSNegate, .{
5566 const negative_offset_id = cg.allocId();
5567 try cg.body.emit(cg.gpa, .OpSNegate, .{
51935568 .id_result_type = offset_ty_id,
51945569 .id_result = negative_offset_id,
51955570 .operand = offset_id,
......@@ -5203,9 +5578,9 @@ fn cmp(
52035578 lhs: Temporary,
52045579 rhs: Temporary,
52055580) !Temporary {
5206 const gpa = cg.module.gpa;
5581 const gpa = cg.gpa;
52075582 const pt = cg.pt;
5208 const zcu = cg.module.zcu;
5583 const zcu = cg.zcu;
52095584 const scalar_ty = lhs.ty.scalarType(zcu);
52105585 const is_vector = lhs.ty.isVector(zcu);
52115586
......@@ -5234,14 +5609,14 @@ fn cmp(
52345609
52355610 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();
52385613 try cg.body.emit(gpa, .OpConvertPtrToU, .{
52395614 .id_result_type = usize_ty_id,
52405615 .id_result = lhs_int_id,
52415616 .pointer = try lhs.materialize(cg),
52425617 });
52435618
5244 const rhs_int_id = cg.module.allocId();
5619 const rhs_int_id = cg.allocId();
52455620 try cg.body.emit(gpa, .OpConvertPtrToU, .{
52465621 .id_result_type = usize_ty_id,
52475622 .id_result = rhs_int_id,
......@@ -5410,14 +5785,29 @@ fn bitCast(
54105785 src_ty: Type,
54115786 src_id: Id,
54125787) !Id {
5413 const gpa = cg.module.gpa;
5414 const zcu = cg.module.zcu;
5788 const gpa = cg.gpa;
5789 const zcu = cg.zcu;
54155790 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);
54195799 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
54225812 // TODO: Some more cases are missing here
54235813 // See fn bitCast in llvm.zig
......@@ -5432,7 +5822,7 @@ fn bitCast(
54325822 }
54335823 }
54345824
5435 const result_id = cg.module.allocId();
5825 const result_id = cg.allocId();
54365826 try cg.body.emit(gpa, .OpConvertUToPtr, .{
54375827 .id_result_type = dst_ty_id,
54385828 .id_result = result_id,
......@@ -5446,7 +5836,7 @@ fn bitCast(
54465836 // otherwise use a temporary and perform a pointer cast.
54475837 const can_bitcast = (src_ty.isNumeric(zcu) and dst_ty.isNumeric(zcu)) or (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu));
54485838 if (can_bitcast) {
5449 const result_id = cg.module.allocId();
5839 const result_id = cg.allocId();
54505840 try cg.body.emit(gpa, .OpBitcast, .{
54515841 .id_result_type = dst_ty_id,
54525842 .id_result = result_id,
......@@ -5456,12 +5846,24 @@ fn bitCast(
54565846 break :blk result_id;
54575847 }
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
54615863 const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect);
54625864 const tmp_id = try cg.alloc(src_ty_indirect_id, null);
54635865 try cg.store(src_ty, tmp_id, src_id, .{});
5464 const casted_ptr_id = cg.module.allocId();
5866 const casted_ptr_id = cg.allocId();
54655867 try cg.body.emit(gpa, .OpBitcast, .{
54665868 .id_result_type = dst_ptr_ty_id,
54675869 .id_result = casted_ptr_id,
......@@ -5492,8 +5894,13 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
54925894 const result = try cg.intFromBool(operand, .u1);
54935895 return try result.materialize(cg);
54945896 }
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 }
54955903 const operand_id = try cg.resolve(ty_op.operand);
5496 if (cg.virtual_allocas.contains(operand_id)) return operand_id;
54975904 return try cg.bitCast(result_ty, operand_ty, operand_id);
54985905}
54995906
......@@ -5509,19 +5916,19 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55095916 const dst_composite = dst_info.class == .composite_integer;
55105917
55115918 if (src_composite or dst_composite) {
5512 const gpa = cg.module.gpa;
5919 const gpa = cg.gpa;
55135920 const scratch_top = cg.id_scratch.items.len;
55145921 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
55155922
55165923 if (src_composite and dst_composite) {
55175924 const src_id = try src.materialize(cg);
5518 const src_n: u16 = src_info.backing_bits / Module.big_int_bits;
5519 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;
5925 const src_n: u16 = src_info.backing_bits / big_int_bits;
5926 const dst_n: u16 = dst_info.backing_bits / big_int_bits;
55205927 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
55215928 const min_n = @min(src_n, dst_n);
55225929 const u32_ty_id = try cg.resolveType(.u32, .direct);
55235930 for (0..min_n) |i| {
5524 result_limbs[i] = cg.module.allocId();
5931 result_limbs[i] = cg.allocId();
55255932 try cg.body.emit(gpa, .OpCompositeExtract, .{
55265933 .id_result_type = u32_ty_id,
55275934 .id_result = result_limbs[i],
......@@ -5533,20 +5940,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55335940 const fill = if (src_info.signedness == .signed) blk: {
55345941 const i32_ty_id = try cg.resolveType(.i32, .direct);
55355942 const msb = result_limbs[src_n - 1];
5536 const msb_signed = cg.module.allocId();
5943 const msb_signed = cg.allocId();
55375944 try cg.body.emit(gpa, .OpBitcast, .{
55385945 .id_result_type = i32_ty_id,
55395946 .id_result = msb_signed,
55405947 .operand = msb,
55415948 });
55425949 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5543 const sign_ext = cg.module.allocId();
5544 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
5545 cg.body.writeOperand(Id, i32_ty_id);
5546 cg.body.writeOperand(Id, sign_ext);
5547 cg.body.writeOperand(Id, msb_signed);
5548 cg.body.writeOperand(Id, shift31);
5549 const back = cg.module.allocId();
5950 const sign_ext = cg.allocId();
5951 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5952 .id_result_type = i32_ty_id,
5953 .id_result = sign_ext,
5954 .base = msb_signed,
5955 .shift = shift31,
5956 });
5957 const back = cg.allocId();
55505958 try cg.body.emit(gpa, .OpBitcast, .{
55515959 .id_result_type = u32_ty_id,
55525960 .id_result = back,
......@@ -5565,7 +5973,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55655973 const src_id = try src.materialize(cg);
55665974 const u32_ty_id = try cg.resolveType(.u32, .direct);
55675975 if (dst_info.backing_bits <= 32) {
5568 const limb0 = cg.module.allocId();
5976 const limb0 = cg.allocId();
55695977 try cg.body.emit(gpa, .OpCompositeExtract, .{
55705978 .id_result_type = u32_ty_id,
55715979 .id_result = limb0,
......@@ -5580,14 +5988,14 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55805988 converted;
55815989 return try result.materialize(cg);
55825990 } else {
5583 const limb0 = cg.module.allocId();
5991 const limb0 = cg.allocId();
55845992 try cg.body.emit(gpa, .OpCompositeExtract, .{
55855993 .id_result_type = u32_ty_id,
55865994 .id_result = limb0,
55875995 .composite = src_id,
55885996 .indexes = &.{@as(u32, 0)},
55895997 });
5590 const limb1 = cg.module.allocId();
5998 const limb1 = cg.allocId();
55915999 try cg.body.emit(gpa, .OpCompositeExtract, .{
55926000 .id_result_type = u32_ty_id,
55936001 .id_result = limb1,
......@@ -5595,29 +6003,33 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
55956003 .indexes = &.{@as(u32, 1)},
55966004 });
55976005 const u64_ty_id = try cg.resolveType(.u64, .direct);
5598 const lo = cg.module.allocId();
5599 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5600 cg.body.writeOperand(Id, u64_ty_id);
5601 cg.body.writeOperand(Id, lo);
5602 cg.body.writeOperand(Id, limb0);
5603 const hi = cg.module.allocId();
5604 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5605 cg.body.writeOperand(Id, u64_ty_id);
5606 cg.body.writeOperand(Id, hi);
5607 cg.body.writeOperand(Id, limb1);
6006 const lo = cg.allocId();
6007 try cg.body.emit(gpa, .OpUConvert, .{
6008 .id_result_type = u64_ty_id,
6009 .id_result = lo,
6010 .unsigned_value = limb0,
6011 });
6012 const hi = cg.allocId();
6013 try cg.body.emit(gpa, .OpUConvert, .{
6014 .id_result_type = u64_ty_id,
6015 .id_result = hi,
6016 .unsigned_value = limb1,
6017 });
56086018 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5609 const hi_shifted = cg.module.allocId();
5610 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);
5611 cg.body.writeOperand(Id, u64_ty_id);
5612 cg.body.writeOperand(Id, hi_shifted);
5613 cg.body.writeOperand(Id, hi);
5614 cg.body.writeOperand(Id, shift32);
5615 const combined = cg.module.allocId();
5616 try cg.body.emitRaw(gpa, .OpBitwiseOr, 4);
5617 cg.body.writeOperand(Id, u64_ty_id);
5618 cg.body.writeOperand(Id, combined);
5619 cg.body.writeOperand(Id, lo);
5620 cg.body.writeOperand(Id, hi_shifted);
6019 const hi_shifted = cg.allocId();
6020 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
6021 .id_result_type = u64_ty_id,
6022 .id_result = hi_shifted,
6023 .base = hi,
6024 .shift = shift32,
6025 });
6026 const combined = cg.allocId();
6027 try cg.body.emit(gpa, .OpBitwiseOr, .{
6028 .id_result_type = u64_ty_id,
6029 .id_result = combined,
6030 .operand_1 = lo,
6031 .operand_2 = hi_shifted,
6032 });
56216033 const tmp: Temporary = .init(.u64, combined);
56226034 const converted = try cg.buildConvert(dst_ty, tmp);
56236035 const result = if (dst_info.bits < src_info.bits)
......@@ -5627,7 +6039,7 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
56276039 return try result.materialize(cg);
56286040 }
56296041 } 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;
56316043 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
56326044 const u32_ty_id = try cg.resolveType(.u32, .direct);
56336045
......@@ -5637,44 +6049,48 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
56376049 } else {
56386050 const src_as_u64 = try cg.buildConvert(.u64, src);
56396051 const src_id = try src_as_u64.materialize(cg);
5640 result_limbs[0] = cg.module.allocId();
5641 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5642 cg.body.writeOperand(Id, u32_ty_id);
5643 cg.body.writeOperand(Id, result_limbs[0]);
5644 cg.body.writeOperand(Id, src_id);
6052 result_limbs[0] = cg.allocId();
6053 try cg.body.emit(gpa, .OpUConvert, .{
6054 .id_result_type = u32_ty_id,
6055 .id_result = result_limbs[0],
6056 .unsigned_value = src_id,
6057 });
56456058 const u64_ty_id = try cg.resolveType(.u64, .direct);
56466059 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5647 const hi = cg.module.allocId();
5648 try cg.body.emitRaw(gpa, .OpShiftRightLogical, 4);
5649 cg.body.writeOperand(Id, u64_ty_id);
5650 cg.body.writeOperand(Id, hi);
5651 cg.body.writeOperand(Id, src_id);
5652 cg.body.writeOperand(Id, shift32);
5653 result_limbs[1] = cg.module.allocId();
5654 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5655 cg.body.writeOperand(Id, u32_ty_id);
5656 cg.body.writeOperand(Id, result_limbs[1]);
5657 cg.body.writeOperand(Id, hi);
6060 const hi = cg.allocId();
6061 try cg.body.emit(gpa, .OpShiftRightLogical, .{
6062 .id_result_type = u64_ty_id,
6063 .id_result = hi,
6064 .base = src_id,
6065 .shift = shift32,
6066 });
6067 result_limbs[1] = cg.allocId();
6068 try cg.body.emit(gpa, .OpUConvert, .{
6069 .id_result_type = u32_ty_id,
6070 .id_result = result_limbs[1],
6071 .unsigned_value = hi,
6072 });
56586073 }
56596074 // Sign/zero-extend remaining limbs.
56606075 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;
56616076 const fill = if (src_info.signedness == .signed) blk: {
56626077 const i32_ty_id = try cg.resolveType(.i32, .direct);
56636078 const msb = result_limbs[fill_start - 1];
5664 const msb_signed = cg.module.allocId();
6079 const msb_signed = cg.allocId();
56656080 try cg.body.emit(gpa, .OpBitcast, .{
56666081 .id_result_type = i32_ty_id,
56676082 .id_result = msb_signed,
56686083 .operand = msb,
56696084 });
56706085 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5671 const sign_ext = cg.module.allocId();
5672 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
5673 cg.body.writeOperand(Id, i32_ty_id);
5674 cg.body.writeOperand(Id, sign_ext);
5675 cg.body.writeOperand(Id, msb_signed);
5676 cg.body.writeOperand(Id, shift31);
5677 const back = cg.module.allocId();
6086 const sign_ext = cg.allocId();
6087 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
6088 .id_result_type = i32_ty_id,
6089 .id_result = sign_ext,
6090 .base = msb_signed,
6091 .shift = shift31,
6092 });
6093 const back = cg.allocId();
56786094 try cg.body.emit(gpa, .OpBitcast, .{
56796095 .id_result_type = u32_ty_id,
56806096 .id_result = back,
......@@ -5715,8 +6131,8 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
57156131
57166132fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
57176133 const result_type_id = try cg.resolveType(.usize, .direct);
5718 const result_id = cg.module.allocId();
5719 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{
6134 const result_id = cg.allocId();
6135 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
57206136 .id_result_type = result_type_id,
57216137 .id_result = result_id,
57226138 .pointer = operand_id,
......@@ -5725,17 +6141,13 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id {
57256141}
57266142
57276143fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6144 const gpa = cg.gpa;
57286145 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
57296146 const operand_ty = cg.typeOf(ty_op.operand);
57306147 const operand_id = try cg.resolve(ty_op.operand);
57316148 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;
57376149 const operand_info = cg.arithmeticTypeInfo(operand_ty);
5738 const result_id = cg.module.allocId();
6150 const result_id = cg.allocId();
57396151 const result_ty_id = try cg.resolveType(result_ty, .direct);
57406152 switch (operand_info.signedness) {
57416153 .signed => try cg.body.emit(gpa, .OpConvertSToF, .{
......@@ -5753,17 +6165,13 @@ fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id)
57536165}
57546166
57556167fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6168 const gpa = cg.gpa;
57566169 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
57576170 const operand_id = try cg.resolve(ty_op.operand);
57586171 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;
57646172 const result_info = cg.arithmeticTypeInfo(result_ty);
57656173 const result_ty_id = try cg.resolveType(result_ty, .direct);
5766 const result_id = cg.module.allocId();
6174 const result_id = cg.allocId();
57676175 switch (result_info.signedness) {
57686176 .signed => try cg.body.emit(gpa, .OpConvertFToS, .{
57696177 .id_result_type = result_ty_id,
......@@ -5815,7 +6223,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
58156223}
58166224
58176225fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5818 const zcu = cg.module.zcu;
6226 const zcu = cg.zcu;
58196227 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
58206228 const array_ptr_ty = cg.typeOf(ty_op.operand);
58216229 const array_ty = array_ptr_ty.childType(zcu);
......@@ -5849,11 +6257,11 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
58496257}
58506258
58516259fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5852 const gpa = cg.module.gpa;
6260 const gpa = cg.gpa;
58536261 const pt = cg.pt;
5854 const zcu = cg.module.zcu;
6262 const zcu = cg.zcu;
58556263 const ip = &zcu.intern_pool;
5856 const target = cg.module.zcu.getTarget();
6264 const target = cg.zcu.getTarget();
58576265 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
58586266 const result_ty = cg.typeOfIndex(inst);
58596267 const len: usize = @intCast(result_ty.arrayLen(zcu));
......@@ -5978,23 +6386,8 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
59786386 }
59796387}
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
59966389fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
5997 const zcu = cg.module.zcu;
6390 const zcu = cg.zcu;
59986391 if (ty.isSlice(zcu)) {
59996392 const ptr_ty = ty.slicePtrFieldType(zcu);
60006393 return cg.extractField(ptr_ty, operand_id, 0);
......@@ -6010,8 +6403,17 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) !void {
60106403 const src_ty = cg.typeOf(bin_op.rhs);
60116404 const dest_ptr = try cg.sliceOrArrayPtr(dest_slice, dest_ty);
60126405 const src_ptr = try cg.sliceOrArrayPtr(src_slice, src_ty);
6013 const len = try cg.sliceOrArrayLen(dest_slice, dest_ty);
6014 try cg.body.emit(cg.module.gpa, .OpCopyMemorySized, .{
6406 const len = switch (dest_ty.ptrSize(cg.zcu)) {
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, .{
60156417 .target = dest_ptr,
60166418 .source = src_ptr,
60176419 .size = len,
......@@ -6031,12 +6433,12 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {
60316433}
60326434
60336435fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6034 const gpa = cg.module.gpa;
6436 const gpa = cg.gpa;
60356437 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
60366438 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
60376439 const struct_ptr_id = try cg.resolve(extra.struct_operand);
6038 const u32_ty_id = try cg.module.intType(.unsigned, 32);
6039 const result_id = cg.module.allocId();
6440 const u32_ty_id = try cg.intType(.unsigned, 32);
6441 const result_id = cg.allocId();
60406442 try cg.body.emit(gpa, .OpArrayLength, .{
60416443 .id_result_type = u32_ty_id,
60426444 .id_result = result_id,
......@@ -6047,7 +6449,7 @@ fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
60476449}
60486450
60496451fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6050 const zcu = cg.module.zcu;
6452 const zcu = cg.zcu;
60516453 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
60526454 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
60536455 const slice_ty = cg.typeOf(bin_op.lhs);
......@@ -6064,7 +6466,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
60646466}
60656467
60666468fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6067 const zcu = cg.module.zcu;
6469 const zcu = cg.zcu;
60686470 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
60696471 const slice_ty = cg.typeOf(bin_op.lhs);
60706472 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 {
60816483}
60826484
60836485fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
6084 const zcu = cg.module.zcu;
6486 const zcu = cg.zcu;
60856487 // Construct new pointer type for the resulting pointer
60866488 const elem_ty = ptr_ty.indexableElem(zcu);
60876489 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)));
60896491 if (ptr_ty.isSinglePointer(zcu)) {
60906492 // Pointer-to-array. In this case, the resulting pointer is not of the same type
60916493 // 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 {
60976499}
60986500
60996501fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6100 const zcu = cg.module.zcu;
6502 const zcu = cg.zcu;
61016503 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
61026504 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
61036505 const src_ptr_ty = cg.typeOf(bin_op.lhs);
......@@ -6111,8 +6513,8 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61116513}
61126514
61136515fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6114 const gpa = cg.module.gpa;
6115 const zcu = cg.module.zcu;
6516 const gpa = cg.gpa;
6517 const zcu = cg.zcu;
61166518 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
61176519 const array_ty = cg.typeOf(bin_op.lhs);
61186520 const elem_ty = array_ty.childType(zcu);
......@@ -6127,10 +6529,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61276529 const elem_repr: Repr = if (is_vector) .direct else .indirect;
61286530 const array_ty_id = try cg.resolveType(array_ty, .direct);
61296531 const elem_ty_id = try cg.resolveType(elem_ty, elem_repr);
6130 const ptr_array_ty_id = try cg.module.ptrType(array_ty_id, .function);
6131 const ptr_elem_ty_id = try cg.module.ptrType(elem_ty_id, .function);
6532 const ptr_array_ty_id = try cg.ptrType(array_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();
61346536 try cg.prologue.emit(gpa, .OpVariable, .{
61356537 .id_result_type = ptr_array_ty_id,
61366538 .id_result = tmp_id,
......@@ -6144,7 +6546,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61446546
61456547 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();
61486550 try cg.body.emit(gpa, .OpLoad, .{
61496551 .id_result_type = try cg.resolveType(elem_ty, elem_repr),
61506552 .id_result = result_id,
......@@ -6163,7 +6565,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61636565}
61646566
61656567fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6166 const zcu = cg.module.zcu;
6568 const zcu = cg.zcu;
61676569 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
61686570 const ptr_ty = cg.typeOf(bin_op.lhs);
61696571 const elem_ty = cg.typeOfIndex(inst);
......@@ -6174,7 +6576,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61746576}
61756577
61766578fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
6177 const zcu = cg.module.zcu;
6579 const zcu = cg.zcu;
61786580 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
61796581 const un_ptr_ty = cg.typeOf(bin_op.lhs);
61806582 const un_ty = un_ptr_ty.childType(zcu);
......@@ -6184,7 +6586,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
61846586
61856587 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
61866588 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
61896591 const union_ptr_id = try cg.resolve(bin_op.lhs);
61906592 const new_tag_id = try cg.resolve(bin_op.rhs);
......@@ -6201,7 +6603,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
62016603 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
62026604 const un_ty = cg.typeOf(ty_op.operand);
62036605
6204 const zcu = cg.module.zcu;
6606 const zcu = cg.zcu;
62056607 const layout = cg.unionLayout(un_ty);
62066608 if (layout.tag_size == 0) return null;
62076609
......@@ -6225,7 +6627,7 @@ fn unionInit(
62256627 // Note: The result here is not cached, because it generates runtime code.
62266628
62276629 const pt = cg.pt;
6228 const zcu = cg.module.zcu;
6630 const zcu = cg.zcu;
62296631 const ip = &zcu.intern_pool;
62306632 const union_ty = zcu.typeToUnion(ty).?;
62316633 const tag_ty: Type = .fromInterned(union_ty.enum_tag_type);
......@@ -6250,7 +6652,7 @@ fn unionInit(
62506652
62516653 if (layout.tag_size != 0) {
62526654 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);
62546656 const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
62556657 const tag_id = try cg.constInt(tag_ty, tag_int);
62566658 try cg.store(tag_ty, ptr_id, tag_id, .{});
......@@ -6258,13 +6660,13 @@ fn unionInit(
62586660
62596661 if (payload_ty.hasRuntimeBits(zcu)) {
62606662 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);
62626664 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
62636665 const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty)) blk: {
62646666 const payload_ty_id = try cg.resolveType(payload_ty, .indirect);
6265 const active_pl_ptr_ty_id = try cg.module.ptrType(payload_ty_id, .function);
6266 const active_pl_ptr_id = cg.module.allocId();
6267 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
6667 const active_pl_ptr_ty_id = try cg.ptrType(payload_ty_id, .function);
6668 const active_pl_ptr_id = cg.allocId();
6669 try cg.body.emit(cg.gpa, .OpBitcast, .{
62686670 .id_result_type = active_pl_ptr_ty_id,
62696671 .id_result = active_pl_ptr_id,
62706672 .operand = pl_ptr_id,
......@@ -6284,7 +6686,7 @@ fn unionInit(
62846686}
62856687
62866688fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6287 const zcu = cg.module.zcu;
6689 const zcu = cg.zcu;
62886690 const ip = &zcu.intern_pool;
62896691 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
62906692 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
......@@ -6301,7 +6703,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63016703
63026704fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63036705 const pt = cg.pt;
6304 const zcu = cg.module.zcu;
6706 const zcu = cg.zcu;
63056707 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
63066708 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 {
63166718 .@"struct" => switch (object_ty.containerLayout(zcu)) {
63176719 .@"packed" => {
63186720 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";
63206722 const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index);
63216723 // We use the same int type the packed struct is backed by, because even though it would
63226724 // 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 {
63296731 const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1);
63306732 const masked = try cg.buildBinary(.OpBitwiseAnd, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });
63316733 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)
63336735 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));
63346736 const trunc = try cg.buildConvert(field_int_ty, masked);
63356737 break :blk try trunc.materialize(cg);
......@@ -6353,7 +6755,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63536755 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },
63546756 );
63556757 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")
63576759 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));
63586760 const trunc = try cg.buildConvert(int_ty, masked);
63596761 break :blk try trunc.materialize(cg);
......@@ -6372,13 +6774,13 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63726774 try cg.store(object_ty, tmp_id, object_id, .{});
63736775
63746776 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);
63766778 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
63776779
63786780 const field_ty_id = try cg.resolveType(field_ty, .indirect);
6379 const active_pl_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);
6380 const active_pl_ptr_id = cg.module.allocId();
6381 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
6781 const active_pl_ptr_ty_id = try cg.ptrType(field_ty_id, .function);
6782 const active_pl_ptr_id = cg.allocId();
6783 try cg.body.emit(cg.gpa, .OpBitcast, .{
63826784 .id_result_type = active_pl_ptr_ty_id,
63836785 .id_result = active_pl_ptr_id,
63846786 .operand = pl_ptr_id,
......@@ -6391,7 +6793,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63916793}
63926794
63936795fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6394 const zcu = cg.module.zcu;
6796 const zcu = cg.zcu;
63956797 const target = zcu.getTarget();
63966798 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
63976799 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
......@@ -6424,8 +6826,8 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
64246826 }
64256827 }
64266828
6427 const base_ptr = cg.module.allocId();
6428 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{
6829 const base_ptr = cg.allocId();
6830 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
64296831 .id_result_type = result_ty_id,
64306832 .id_result = base_ptr,
64316833 .integer_value = base_ptr_int,
......@@ -6443,7 +6845,7 @@ fn structFieldPtr(
64436845) !Id {
64446846 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);
64456847
6446 const zcu = cg.module.zcu;
6848 const zcu = cg.zcu;
64476849 const object_ty = object_ptr_ty.childType(zcu);
64486850 switch (object_ty.zigTypeTag(zcu)) {
64496851 .pointer => {
......@@ -6455,8 +6857,8 @@ fn structFieldPtr(
64556857 const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu);
64566858 if (byte_offset == 0) return object_ptr;
64576859 const usize_ty_id = try cg.resolveType(.usize, .direct);
6458 const base_int = cg.module.allocId();
6459 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{
6860 const base_int = cg.allocId();
6861 try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{
64606862 .id_result_type = usize_ty_id,
64616863 .id_result = base_int,
64626864 .pointer = object_ptr,
......@@ -6464,8 +6866,8 @@ fn structFieldPtr(
64646866 const offset_id = try cg.constInt(.usize, byte_offset);
64656867 const adjusted = try cg.buildBinary(.OpIAdd, .{ .ty = .usize, .value = .{ .singleton = base_int } }, .{ .ty = .usize, .value = .{ .singleton = offset_id } });
64666868 const adjusted_id = try adjusted.materialize(cg);
6467 const result_id = cg.module.allocId();
6468 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{
6869 const result_id = cg.allocId();
6870 try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{
64696871 .id_result_type = result_ty_id,
64706872 .id_result = result_id,
64716873 .integer_value = adjusted_id,
......@@ -6483,19 +6885,19 @@ fn structFieldPtr(
64836885 if (!layout.has_payload) {
64846886 // Asked to get a pointer to a zero-sized field. Just lower this
64856887 // 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);
64876889 }
64886890
6489 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
6891 const storage_class = cg.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
64906892 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);
64926894 const pl_ptr_id = blk: {
64936895 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
64946896 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
64956897 };
64966898
6497 const active_pl_ptr_id = cg.module.allocId();
6498 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
6899 const active_pl_ptr_id = cg.allocId();
6900 try cg.body.emit(cg.gpa, .OpBitcast, .{
64996901 .id_result_type = result_ty_id,
65006902 .id_result = active_pl_ptr_id,
65016903 .operand = pl_ptr_id,
......@@ -6525,9 +6927,9 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32)
65256927}
65266928
65276929fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
6528 const ptr_ty_id = try cg.module.ptrType(ty_id, .function);
6529 const result_id = cg.module.allocId();
6530 try cg.prologue.emit(cg.module.gpa, .OpVariable, .{
6930 const ptr_ty_id = try cg.ptrType(ty_id, .function);
6931 const result_id = cg.allocId();
6932 try cg.prologue.emit(cg.gpa, .OpVariable, .{
65316933 .id_result_type = ptr_ty_id,
65326934 .id_result = result_id,
65336935 .storage_class = .function,
......@@ -6537,7 +6939,7 @@ fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id {
65376939}
65386940
65396941fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6540 const zcu = cg.module.zcu;
6942 const zcu = cg.zcu;
65416943 const target = zcu.getTarget();
65426944 const ptr_ty = cg.typeOfIndex(inst);
65436945 const child_ty = ptr_ty.childType(zcu);
......@@ -6546,9 +6948,9 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
65466948 .vulkan, .opengl => {
65476949 if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) {
65486950 const as = child_ty.ptrAddressSpace(zcu);
6549 if (cg.module.storageClass(as) == .function) {
6550 const result_id = cg.module.allocId();
6551 try cg.virtual_allocas.put(cg.module.gpa, result_id, null);
6951 if (cg.storageClass(as) == .function) {
6952 const result_id = cg.allocId();
6953 try cg.tracked_allocas.put(cg.gpa, result_id, null);
65526954 return result_id;
65536955 }
65546956 }
......@@ -6561,7 +6963,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
65616963 const result_id = try cg.alloc(child_ty_id, null);
65626964 if (ptr_align != child_ty.abiAlignment(zcu)) {
65636965 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, .{
65656967 .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) },
65666968 });
65676969 }
......@@ -6578,9 +6980,9 @@ fn airArg(cg: *CodeGen) Id {
65786980/// inside the merge block of the block.
65796981/// This function should only be called with structured control flow generation.
65806982fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
6581 const result_id = cg.module.allocId();
6983 const result_id = cg.allocId();
65826984 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...
65846986 cg.body.writeOperand(Id, block_id_ty_id);
65856987 cg.body.writeOperand(Id, result_id);
65866988
......@@ -6597,11 +6999,11 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
65976999fn structuredBreak(cg: *CodeGen, target_block: Id) !void {
65987000 if (cg.block_terminated) return;
65997001
6600 const gpa = cg.module.gpa;
7002 const gpa = cg.gpa;
66017003 const sblock = cg.block_stack.getLast().?;
66027004 const merge_block = switch (sblock.*) {
66037005 .selection => |*merge| blk: {
6604 const merge_label = cg.module.allocId();
7006 const merge_label = cg.allocId();
66057007 try merge.merge_stack.append(gpa, .{
66067008 .incoming = .{
66077009 .src_label = cg.block_label,
......@@ -6641,7 +7043,7 @@ fn genStructuredBody(
66417043 },
66427044 body: []const Air.Inst.Index,
66437045) !Id {
6644 const gpa = cg.module.gpa;
7046 const gpa = cg.gpa;
66457047
66467048 var sblock: Block = switch (block_merge_type) {
66477049 .loop => |merge| .{ .loop = .{
......@@ -6679,9 +7081,9 @@ fn genStructuredBody(
66797081
66807082 // Make sure that we are still in a block when exiting the function.
66817083 // TODO: Can we get rid of that?
6682 try cg.beginSpvBlock(cg.module.allocId());
7084 try cg.beginSpvBlock(cg.allocId());
66837085 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);
66857087 }
66867088
66877089 // 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)
67357137 // of the block, then a label, and then generate the rest of the current
67367138 // ir.Block in a different SPIR-V block.
67377139
6738 const gpa = cg.module.gpa;
6739 const zcu = cg.module.zcu;
7140 const gpa = cg.gpa;
7141 const zcu = cg.zcu;
67407142 const ty = cg.typeOfIndex(inst);
67417143 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)
67567158
67577159 // Check if the target of the branch was this current block.
67587160 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();
67607162 const bool_ty_id = try cg.resolveType(.bool, .direct);
67617163 try cg.body.emit(gpa, .OpIEqual, .{
67627164 .id_result_type = bool_ty_id,
......@@ -6776,8 +7178,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
67767178 .selection => |*merge| {
67777179 // To jump out of a selection block, push a new entry onto its merge stack and
67787180 // generate a conditional branch to there and to the instructions following this block.
6779 const merge_label = cg.module.allocId();
6780 const then_label = cg.module.allocId();
7181 const merge_label = cg.allocId();
7182 const then_label = cg.allocId();
67817183 try cg.body.emit(gpa, .OpSelectionMerge, .{
67827184 .merge_block = merge_label,
67837185 .selection_control = .{},
......@@ -6800,7 +7202,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
68007202 .loop => |*merge| {
68017203 // To jump out of a loop block, generate a conditional that exits the block
68027204 // 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();
68047206 try cg.body.emit(gpa, .OpBranchConditional, .{
68057207 .condition = jump_to_this_block_id,
68067208 .true_label = continue_label,
......@@ -6823,7 +7225,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
68237225}
68247226
68257227fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6826 const zcu = cg.module.zcu;
7228 const zcu = cg.zcu;
68277229 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
68287230 const operand_ty = cg.typeOf(br.operand);
68297231
......@@ -6838,16 +7240,16 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
68387240}
68397241
68407242fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6841 const gpa = cg.module.gpa;
7243 const gpa = cg.gpa;
68427244 const cond_br = cg.air.unwrapCondBr(inst);
68437245 const then_body = cond_br.then_body;
68447246 const else_body = cond_br.else_body;
68457247 const condition_id = try cg.resolve(cond_br.condition);
68467248
6847 const then_label = cg.module.allocId();
6848 const else_label = cg.module.allocId();
7249 const then_label = cg.allocId();
7250 const else_label = cg.allocId();
68497251
6850 const merge_label = cg.module.allocId();
7252 const merge_label = cg.allocId();
68517253
68527254 try cg.body.emit(gpa, .OpSelectionMerge, .{
68537255 .merge_block = merge_label,
......@@ -6888,14 +7290,14 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
68887290}
68897291
68907292fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
6891 const gpa = cg.module.gpa;
7293 const gpa = cg.gpa;
68927294 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();
6897 const merge_label = cg.module.allocId();
6898 const continue_label = cg.module.allocId();
7298 const header_label = cg.allocId();
7299 const merge_label = cg.allocId();
7300 const continue_label = cg.allocId();
68997301
69007302 // The back-edge must point to the loop header, so generate a separate block for the
69017303 // 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 {
69277329}
69287330
69297331fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6930 const zcu = cg.module.zcu;
7332 const zcu = cg.zcu;
69317333 const pt = cg.pt;
69327334 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6933
6934 const ptr_info = cg.typeOf(ty_op.operand).ptrInfo(zcu);
6935
7335 const ptr_ty = cg.typeOf(ty_op.operand);
7336 const ptr_info = ptr_ty.ptrInfo(zcu);
69367337 const elem_ty = cg.typeOfIndex(inst);
6937 const operand_ptr_id = try cg.resolve(ty_op.operand);
6938
7338 const ptr = try cg.resolvePtr(ty_op.operand);
69397339 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
69437346 if (ptr_info.packed_offset.host_size != 0 and
69447347 ptr_info.flags.vector_index == .none)
......@@ -6955,7 +7358,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
69557358 break :blk try shifted.materialize(cg);
69567359 } else host_val;
69577360 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")
69597362 break :blk try cg.bitCast(field_int_ty, host_int_ty, narrowed);
69607363 const trunc = try cg.buildConvert(field_int_ty, .{ .ty = host_int_ty, .value = .{ .singleton = narrowed } });
69617364 break :blk try trunc.materialize(cg);
......@@ -6968,9 +7371,9 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
69687371 const ptr_id = switch (ptr_info.flags.vector_index) {
69697372 .none => operand_ptr_id,
69707373 else => |index| ptr_id: {
6971 const elem_ptr_ty_id = try cg.module.ptrType(
7374 const elem_ptr_ty_id = try cg.ptrType(
69727375 try cg.resolveType(elem_ty, .indirect),
6973 cg.module.storageClass(ptr_info.flags.address_space),
7376 cg.storageClass(ptr_info.flags.address_space),
69747377 );
69757378 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
69767379 },
......@@ -6979,18 +7382,20 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
69797382}
69807383
69817384fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
6982 const zcu = cg.module.zcu;
7385 const zcu = cg.zcu;
69837386 const pt = cg.pt;
69847387 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);
69867390 const elem_ty: Type = .fromInterned(ptr_info.child);
6987 const operand_ptr_id = try cg.resolve(bin_op.lhs);
69887391 const value_id = try cg.resolve(bin_op.rhs);
6989
6990 if (cg.virtual_allocas.getPtr(operand_ptr_id)) |slot| {
6991 slot.* = value_id;
6992 return;
6993 }
7392 const operand_ptr_id = switch (try cg.resolvePtr(bin_op.lhs)) {
7393 .tracked => |t| {
7394 t.slot.* = value_id;
7395 return;
7396 },
7397 .id => |id| id,
7398 };
69947399
69957400 if (ptr_info.packed_offset.host_size != 0 and
69967401 ptr_info.flags.vector_index == .none)
......@@ -7013,7 +7418,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
70137418 }
70147419
70157420 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")
70177422 break :blk try cg.bitCast(host_int_ty, field_int_ty, value_as_int);
70187423 const conv = try cg.buildConvert(host_int_ty, .{ .ty = field_int_ty, .value = .{ .singleton = value_as_int } });
70197424 break :blk try conv.materialize(cg);
......@@ -7037,9 +7442,9 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
70377442 const ptr_id = switch (ptr_info.flags.vector_index) {
70387443 .none => operand_ptr_id,
70397444 else => |index| ptr_id: {
7040 const elem_ptr_ty_id = try cg.module.ptrType(
7445 const elem_ptr_ty_id = try cg.ptrType(
70417446 try cg.resolveType(elem_ty, .indirect),
7042 cg.module.storageClass(ptr_info.flags.address_space),
7447 cg.storageClass(ptr_info.flags.address_space),
70437448 );
70447449 break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)});
70457450 },
......@@ -7049,8 +7454,8 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
70497454}
70507455
70517456fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
7052 const gpa = cg.module.gpa;
7053 const zcu = cg.module.zcu;
7457 const gpa = cg.gpa;
7458 const zcu = cg.zcu;
70547459 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
70557460 const ret_ty = cg.typeOf(operand);
70567461 if (!ret_ty.hasRuntimeBits(zcu)) {
......@@ -7071,8 +7476,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
70717476}
70727477
70737478fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
7074 const gpa = cg.module.gpa;
7075 const zcu = cg.module.zcu;
7479 const gpa = cg.gpa;
7480 const zcu = cg.zcu;
70767481 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
70777482 const ptr_ty = cg.typeOf(un_op);
70787483 const ret_ty = ptr_ty.childType(zcu);
......@@ -7090,16 +7495,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
70907495 }
70917496 }
70927497
7093 const ptr = try cg.resolve(un_op);
7094 const value = try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
7498 const value = switch (try cg.resolvePtr(un_op)) {
7499 .tracked => |t| t.slot.*.?,
7500 .id => |ptr| try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }),
7501 };
70957502 try cg.body.emit(gpa, .OpReturnValue, .{
70967503 .value = value,
70977504 });
70987505}
70997506
71007507fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7101 const gpa = cg.module.gpa;
7102 const zcu = cg.module.zcu;
7508 const gpa = cg.gpa;
7509 const zcu = cg.zcu;
71037510 const unwrapped_try = cg.air.unwrapTry(inst);
71047511 const body = unwrapped_try.else_body;
71057512
......@@ -7118,7 +7525,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71187525 err_union_id;
71197526
71207527 const zero_id = try cg.constInt(.anyerror, 0);
7121 const is_err_id = cg.module.allocId();
7528 const is_err_id = cg.allocId();
71227529 try cg.body.emit(gpa, .OpINotEqual, .{
71237530 .id_result_type = bool_ty_id,
71247531 .id_result = is_err_id,
......@@ -7130,8 +7537,8 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71307537 // with the current body.
71317538 // 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();
7134 const ok_block = cg.module.allocId();
7540 const err_block = cg.allocId();
7541 const ok_block = cg.allocId();
71357542
71367543 // According to AIR documentation, this block is guaranteed
71377544 // to not break and end in a return instruction. Thus,
......@@ -7162,7 +7569,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71627569}
71637570
71647571fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7165 const zcu = cg.module.zcu;
7572 const zcu = cg.zcu;
71667573 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
71677574 const operand_id = try cg.resolve(ty_op.operand);
71687575 const err_union_ty = cg.typeOf(ty_op.operand);
......@@ -7170,7 +7577,7 @@ fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71707577
71717578 if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
71727579 // No error possible, so just return undefined.
7173 return try cg.module.constUndef(err_ty_id);
7580 return try cg.constUndef(err_ty_id);
71747581 }
71757582
71767583 const payload_ty = err_union_ty.errorUnionPayload(zcu);
......@@ -7198,7 +7605,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
71987605}
71997606
72007607fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7201 const zcu = cg.module.zcu;
7608 const zcu = cg.zcu;
72027609 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
72037610 const err_union_ty = cg.typeOfIndex(inst);
72047611 const payload_ty = err_union_ty.errorUnionPayload(zcu);
......@@ -7213,7 +7620,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
72137620
72147621 var members: [2]Id = undefined;
72157622 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
72187625 var types: [2]Type = undefined;
72197626 types[eu_layout.errorFieldIndex()] = .anyerror;
......@@ -7247,7 +7654,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
72477654}
72487655
72497656fn 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;
72517658 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
72527659 const operand_id = try cg.resolve(un_op);
72537660 const operand_ty = cg.typeOf(un_op);
......@@ -7274,7 +7681,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
72747681 loaded_id;
72757682
72767683 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);
72787685 const null_tmp: Temporary = .init(ptr_ty, null_id);
72797686 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 {
72897696 const is_non_null_id = blk: {
72907697 if (is_pointer) {
72917698 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));
72937700 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);
72957702 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});
72967703 break :blk try cg.load(.bool, tag_ptr_id, .{});
72977704 }
......@@ -7311,8 +7718,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
73117718 return switch (pred) {
73127719 .is_null => blk: {
73137720 // Invert condition
7314 const result_id = cg.module.allocId();
7315 try cg.body.emit(cg.module.gpa, .OpLogicalNot, .{
7721 const result_id = cg.allocId();
7722 try cg.body.emit(cg.gpa, .OpLogicalNot, .{
73167723 .id_result_type = bool_ty_id,
73177724 .id_result = result_id,
73187725 .operand = is_non_null_id,
......@@ -7324,7 +7731,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
73247731}
73257732
73267733fn 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;
73287735 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
73297736 const operand_id = try cg.resolve(un_op);
73307737 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
73427749 else
73437750 try cg.extractField(.anyerror, operand_id, eu_layout.errorFieldIndex());
73447751
7345 const result_id = cg.module.allocId();
7752 const result_id = cg.allocId();
73467753 switch (pred) {
73477754 inline else => |pred_ct| try cg.body.emit(
7348 cg.module.gpa,
7755 cg.gpa,
73497756 switch (pred_ct) {
73507757 .is_err => .OpINotEqual,
73517758 .is_non_err => .OpIEqual,
......@@ -7362,7 +7769,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
73627769}
73637770
73647771fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7365 const zcu = cg.module.zcu;
7772 const zcu = cg.zcu;
73667773 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
73677774 const operand_id = try cg.resolve(ty_op.operand);
73687775 const optional_ty = cg.typeOf(ty_op.operand);
......@@ -7378,7 +7785,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
73787785}
73797786
73807787fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7381 const zcu = cg.module.zcu;
7788 const zcu = cg.zcu;
73827789 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
73837790 const operand_id = try cg.resolve(ty_op.operand);
73847791 const operand_ty = cg.typeOf(ty_op.operand);
......@@ -7402,7 +7809,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
74027809}
74037810
74047811fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7405 const zcu = cg.module.zcu;
7812 const zcu = cg.zcu;
74067813 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
74077814 const payload_ty = cg.typeOf(ty_op.operand);
74087815
......@@ -7422,9 +7829,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
74227829}
74237830
74247831fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7425 const gpa = cg.module.gpa;
7426 const zcu = cg.module.zcu;
7427 const target = cg.module.zcu.getTarget();
7832 const gpa = cg.gpa;
7833 const zcu = cg.zcu;
7834 const target = cg.zcu.getTarget();
74287835 const switch_br = cg.air.unwrapSwitch(inst);
74297836 const cond_ty = cg.typeOf(switch_br.operand);
74307837 const cond = try cg.resolve(switch_br.operand);
......@@ -7434,14 +7841,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
74347841 .bool, .error_set => 1,
74357842 .int => blk: {
74367843 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);
74387845 if (big_int) return cg.todo("implement composite int switch", .{});
74397846 break :blk if (backing_bits <= 32) 1 else 2;
74407847 },
74417848 .@"enum" => blk: {
74427849 const int_ty = cond_ty.intTagType(zcu);
74437850 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);
74457852 if (big_int) return cg.todo("implement composite int switch", .{});
74467853 break :blk if (backing_bits <= 32) 1 else 2;
74477854 },
......@@ -7470,12 +7877,12 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
74707877 }
74717878
74727879 // 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);
74747881 // We always need the default case - if zig has none, we will generate unreachable there.
7475 const default_label = cg.module.allocId();
7476 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;
7882 const default_label = cg.allocId();
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
74807887 try cg.body.emit(gpa, .OpSelectionMerge, .{
74817888 .merge_block = merge_label,
......@@ -7540,12 +7947,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
75407947 const item_tmp: Temporary = try cg.temporary(item);
75417948 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
75427949 case_cond = if (case_cond) |prev| blk: {
7543 const combined = cg.module.allocId();
7544 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7545 cg.body.writeOperand(Id, bool_ty_id);
7546 cg.body.writeOperand(Id, combined);
7547 cg.body.writeOperand(Id, prev);
7548 cg.body.writeOperand(Id, eq);
7950 const combined = cg.allocId();
7951 try cg.body.emit(gpa, .OpLogicalOr, .{
7952 .id_result_type = bool_ty_id,
7953 .id_result = combined,
7954 .operand_1 = prev,
7955 .operand_2 = eq,
7956 });
75497957 break :blk combined;
75507958 } else eq;
75517959 }
......@@ -7555,26 +7963,28 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
75557963 const hi_tmp: Temporary = try cg.temporary(range[1]);
75567964 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
75577965 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7558 const in_range = cg.module.allocId();
7559 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
7560 cg.body.writeOperand(Id, bool_ty_id);
7561 cg.body.writeOperand(Id, in_range);
7562 cg.body.writeOperand(Id, ge);
7563 cg.body.writeOperand(Id, le);
7966 const in_range = cg.allocId();
7967 try cg.body.emit(gpa, .OpLogicalAnd, .{
7968 .id_result_type = bool_ty_id,
7969 .id_result = in_range,
7970 .operand_1 = ge,
7971 .operand_2 = le,
7972 });
75647973 case_cond = if (case_cond) |prev| blk: {
7565 const combined = cg.module.allocId();
7566 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7567 cg.body.writeOperand(Id, bool_ty_id);
7568 cg.body.writeOperand(Id, combined);
7569 cg.body.writeOperand(Id, prev);
7570 cg.body.writeOperand(Id, in_range);
7974 const combined = cg.allocId();
7975 try cg.body.emit(gpa, .OpLogicalOr, .{
7976 .id_result_type = bool_ty_id,
7977 .id_result = combined,
7978 .operand_1 = prev,
7979 .operand_2 = in_range,
7980 });
75717981 break :blk combined;
75727982 } else in_range;
75737983 }
75747984
75757985 const case_label = case_labels.at(case.idx);
75767986 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
75797989 try cg.body.emit(gpa, .OpSelectionMerge, .{
75807990 .merge_block = next_check,
......@@ -7633,9 +8043,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
76338043}
76348044
76358045fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7636 const gpa = cg.module.gpa;
7637 const zcu = cg.module.zcu;
7638 const target = cg.module.zcu.getTarget();
8046 const gpa = cg.gpa;
8047 const zcu = cg.zcu;
8048 const target = cg.zcu.getTarget();
76398049 const switch_br = cg.air.unwrapSwitch(inst);
76408050 const cond_ty = cg.typeOf(switch_br.operand);
76418051 const initial_cond = try cg.resolve(switch_br.operand);
......@@ -7645,14 +8055,14 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
76458055 .bool, .error_set => 1,
76468056 .int => blk: {
76478057 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);
76498059 if (big_int) return cg.todo("implement composite int loop switch", .{});
76508060 break :blk if (backing_bits <= 32) 1 else 2;
76518061 },
76528062 .@"enum" => blk: {
76538063 const int_ty = cond_ty.intTagType(zcu);
76548064 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);
76568066 if (big_int) return cg.todo("implement composite int loop switch", .{});
76578067 break :blk if (backing_bits <= 32) 1 else 2;
76588068 },
......@@ -7682,15 +8092,15 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
76828092 }
76838093 }
76848094
7685 const case_labels = cg.module.allocIds(num_cases);
7686 const default_label = cg.module.allocId();
7687 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;
8095 const case_labels = cg.allocIds(num_cases);
8096 const default_label = cg.allocId();
8097 const switch_default = if (last_range_case != null) cg.allocId() else default_label;
76888098
7689 const header_label = cg.module.allocId();
7690 const loop_merge = cg.module.allocId();
7691 const continue_label = cg.module.allocId();
7692 const switch_merge = cg.module.allocId();
7693 const body_label = cg.module.allocId();
8099 const header_label = cg.allocId();
8100 const loop_merge = cg.allocId();
8101 const continue_label = cg.allocId();
8102 const switch_merge = cg.allocId();
8103 const body_label = cg.allocId();
76948104
76958105 // switch_dispatch signals "continue the loop" by using this sentinel as the
76968106 // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes
......@@ -7772,12 +8182,13 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
77728182 const item_tmp: Temporary = try cg.temporary(item);
77738183 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
77748184 case_cond = if (case_cond) |prev| blk: {
7775 const combined = cg.module.allocId();
7776 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7777 cg.body.writeOperand(Id, bool_ty_id);
7778 cg.body.writeOperand(Id, combined);
7779 cg.body.writeOperand(Id, prev);
7780 cg.body.writeOperand(Id, eq);
8185 const combined = cg.allocId();
8186 try cg.body.emit(gpa, .OpLogicalOr, .{
8187 .id_result_type = bool_ty_id,
8188 .id_result = combined,
8189 .operand_1 = prev,
8190 .operand_2 = eq,
8191 });
77818192 break :blk combined;
77828193 } else eq;
77838194 }
......@@ -7787,26 +8198,28 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
77878198 const hi_tmp: Temporary = try cg.temporary(range[1]);
77888199 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
77898200 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7790 const in_range = cg.module.allocId();
7791 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
7792 cg.body.writeOperand(Id, bool_ty_id);
7793 cg.body.writeOperand(Id, in_range);
7794 cg.body.writeOperand(Id, ge);
7795 cg.body.writeOperand(Id, le);
8201 const in_range = cg.allocId();
8202 try cg.body.emit(gpa, .OpLogicalAnd, .{
8203 .id_result_type = bool_ty_id,
8204 .id_result = in_range,
8205 .operand_1 = ge,
8206 .operand_2 = le,
8207 });
77968208 case_cond = if (case_cond) |prev| blk: {
7797 const combined = cg.module.allocId();
7798 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7799 cg.body.writeOperand(Id, bool_ty_id);
7800 cg.body.writeOperand(Id, combined);
7801 cg.body.writeOperand(Id, prev);
7802 cg.body.writeOperand(Id, in_range);
8209 const combined = cg.allocId();
8210 try cg.body.emit(gpa, .OpLogicalOr, .{
8211 .id_result_type = bool_ty_id,
8212 .id_result = combined,
8213 .operand_1 = prev,
8214 .operand_2 = in_range,
8215 });
78038216 break :blk combined;
78048217 } else in_range;
78058218 }
78068219
78078220 const case_label = case_labels.at(case.idx);
78088221 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
78118224 try cg.body.emit(gpa, .OpSelectionMerge, .{
78128225 .merge_block = next_check,
......@@ -7860,7 +8273,7 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
78608273 try cg.beginSpvBlock(switch_merge);
78618274 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);
78628275
7863 const is_dispatch = cg.module.allocId();
8276 const is_dispatch = cg.allocId();
78648277 const bool_ty_id = try cg.resolveType(.bool, .direct);
78658278 try cg.body.emit(gpa, .OpIEqual, .{
78668279 .id_result_type = bool_ty_id,
......@@ -7869,12 +8282,12 @@ fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
78698282 .operand_2 = dispatch_sentinel,
78708283 });
78718284
7872 const dispatch_check_merge = cg.module.allocId();
8285 const dispatch_check_merge = cg.allocId();
78738286 try cg.body.emit(gpa, .OpSelectionMerge, .{
78748287 .merge_block = dispatch_check_merge,
78758288 .selection_control = .{},
78768289 });
7877 const exit_block = cg.module.allocId();
8290 const exit_block = cg.allocId();
78788291 try cg.body.emit(gpa, .OpBranchConditional, .{
78798292 .condition = is_dispatch,
78808293 .true_label = dispatch_check_merge,
......@@ -7906,25 +8319,30 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void {
79068319}
79078320
79088321fn airUnreach(cg: *CodeGen) !void {
7909 try cg.body.emit(cg.module.gpa, .OpUnreachable, {});
8322 try cg.body.emit(cg.gpa, .OpUnreachable, {});
79108323}
79118324
79128325fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {
7913 const zcu = cg.module.zcu;
8326 const zcu = cg.zcu;
79148327 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
79158328 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;
79168329
79178330 if (zcu.comp.config.root_strip) return;
79188331
7919 try cg.body.emit(cg.module.gpa, .OpLine, .{
7920 .file = try cg.module.debugString(path),
8332 const path_id = cg.allocId();
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,
79218339 .line = cg.base_line + dbg_stmt.line + 1,
79228340 .column = dbg_stmt.column + 1,
79238341 });
79248342}
79258343
79268344fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7927 const zcu = cg.module.zcu;
8345 const zcu = cg.zcu;
79288346 const block = cg.air.unwrapDbgBlock(inst);
79298347 const old_base_line = cg.base_line;
79308348 defer cg.base_line = old_base_line;
......@@ -7934,15 +8352,17 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
79348352
79358353fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
79368354 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
7937 const target_id = try cg.resolve(pl_op.operand);
7938 if (cg.virtual_allocas.contains(target_id)) return;
8355 const target_id = switch (try cg.resolvePtr(pl_op.operand)) {
8356 .tracked => return,
8357 .id => |id| id,
8358 };
79398359 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));
79418361}
79428362
79438363fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
7944 const gpa = cg.module.gpa;
7945 const zcu = cg.module.zcu;
8364 const gpa = cg.gpa;
8365 const zcu = cg.zcu;
79468366 const unwrapped_asm = cg.air.unwrapAsm(inst);
79478367
79488368 const is_volatile = unwrapped_asm.is_volatile;
......@@ -7974,7 +8394,6 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
79748394 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});
79758395 });
79768396
7977 // TODO: This entire function should be handled a bit better...
79788397 const ip = &zcu.intern_pool;
79798398 switch (ip.indexToKey(val.toIntern())) {
79808399 .int_type,
......@@ -8080,8 +8499,8 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
80808499fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) !?Id {
80818500 _ = modifier;
80828501
8083 const gpa = cg.module.gpa;
8084 const zcu = cg.module.zcu;
8502 const gpa = cg.gpa;
8503 const zcu = cg.zcu;
80858504 const air_call = cg.air.unwrapCall(inst);
80868505 const args = air_call.args;
80878506 const callee_ty = cg.typeOf(air_call.callee);
......@@ -8094,11 +8513,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
80948513 const return_type = fn_info.return_type;
80958514
80968515 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));
8097 const result_id = cg.module.allocId();
8516 const result_id = cg.allocId();
80988517 const callee_id = try cg.resolve(air_call.callee);
80998518
8100 comptime assert(zig_call_abi_ver == 3);
8101
81028519 const scratch_top = cg.id_scratch.items.len;
81038520 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
81048521 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)
81128529 if (!arg_ty.hasRuntimeBits(zcu)) continue;
81138530
81148531 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)
81168534 {
81178535 // in logical addressing, pointer arguments to function calls
81188536 // must be memory object declarations (OpVariable). for pointers to
......@@ -8147,15 +8565,26 @@ fn builtin3D(
81478565 dimension: u32,
81488566 out_of_range_value: anytype,
81498567) !Id {
8150 const gpa = cg.module.gpa;
8568 const gpa = cg.gpa;
81518569 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);
8152 const u32_ty_id = try cg.module.intType(.unsigned, 32);
8153 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);
8154 const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input);
8155 const spv_decl_index = try cg.module.builtin(ptr_ty_id, built_in, .input);
8156 try cg.module.decl_deps.append(gpa, spv_decl_index);
8157 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;
8158 const vec_id = cg.module.allocId();
8570 const u32_ty_id = try cg.intType(.unsigned, 32);
8571 const vec_ty_id = try cg.vectorType(3, u32_ty_id);
8572 const ptr_ty_id = try cg.ptrType(vec_ty_id, .input);
8573 const builtins_gop = try cg.builtins.getOrPut(gpa, .{ built_in, .input });
8574 if (!builtins_gop.found_existing) {
8575 builtins_gop.value_ptr.* = try cg.allocDecl(.global);
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();
81598588 try cg.body.emit(gpa, .OpLoad, .{
81608589 .id_result_type = vec_ty_id,
81618590 .id_result = vec_id,
......@@ -8186,12 +8615,30 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
81868615 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
81878616}
81888617
8189fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
8190 const zcu = cg.module.zcu;
8191 return cg.air.typeOf(inst, &zcu.intern_pool);
8192}
8618const std = @import("std");
8619const Allocator = std.mem.Allocator;
8620const Target = std.Target;
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 {
8195 const zcu = cg.module.zcu;
8196 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
8197}
8625const builtin = @import("builtin");
8626const link = @import("../../link.zig");
8627const codegen = @import("../../codegen.zig");
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;
66const Id = spec.Id;
77
88const InternPool = @import("../../InternPool.zig");
9const Module = @import("Module.zig");
9const CodeGen = @import("CodeGen.zig");
1010
1111const Mir = @This();
1212
1313id_bound: Word,
1414owner_nav: InternPool.Nav.Index,
15kind: Module.Decl.Kind,
15kind: CodeGen.Decl.Kind,
1616decl_result_id: Id,
1717extended_instruction_set: []const Word,
1818globals: []const Word,
......@@ -30,18 +30,18 @@ entry_points: []const EntryPoint,
3030pub const NavRef = struct {
3131 local_id: Id,
3232 nav: InternPool.Nav.Index,
33 kind: Module.Decl.Kind,
33 kind: CodeGen.Decl.Kind,
3434};
3535
3636pub const UavRef = struct {
3737 local_id: Id,
3838 val: InternPool.Index,
3939 storage_class: spec.StorageClass,
40 kind: Module.Decl.Kind,
40 kind: CodeGen.Decl.Kind,
4141};
4242
4343pub const DeclDep = struct {
44 kind: Module.Decl.Kind,
44 kind: CodeGen.Decl.Kind,
4545 nav: InternPool.Nav.Index,
4646};
4747
src/codegen/spirv/Module.zig deleted-791
......@@ -1,791 +0,0 @@
1//! This structure represents a SPIR-V (sections) module being compiled, and keeps
2//! track of all relevant information. That includes the actual instructions, the
3//! current result-id bound, and data structures for querying result-id's of data
4//! which needs to be persistent over different calls to Decl code generation.
5//!
6//! A SPIR-V binary module supports both little- and big endian layout. The layout
7//! is detected by the magic word in the header. Therefore, we can ignore any byte
8//! order throughout the implementation, and just use the host byte order, and make
9//! this a problem for the consumer.
10const std = @import("std");
11const Allocator = std.mem.Allocator;
12const assert = std.debug.assert;
13
14const Zcu = @import("../../Zcu.zig");
15const InternPool = @import("../../InternPool.zig");
16const Section = @import("Section.zig");
17const spec = @import("spec.zig");
18const Word = spec.Word;
19const Id = spec.Id;
20
21const Module = @This();
22
23gpa: Allocator,
24arena: Allocator,
25zcu: *Zcu,
26nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty,
27uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty,
28intern_map: std.AutoHashMapUnmanaged(struct { InternPool.Index, Repr }, Id) = .empty,
29decls: std.ArrayList(Decl) = .empty,
30decl_deps: std.ArrayList(Decl.Index) = .empty,
31entry_points: std.array_hash_map.Auto(Id, EntryPoint) = .empty,
32/// This map serves a dual purpose:
33/// - It keeps track of pointers that are currently being emitted, so that we can tell
34/// if they are recursive and need an OpTypeForwardPointer.
35/// - It caches pointers by child-type. This is required because sometimes we rely on
36/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned
37/// via the usual `intern_map` mechanism.
38ptr_types: std.AutoHashMapUnmanaged(struct { Id, spec.StorageClass }, Id) = .{},
39/// For test declarations compiled for Vulkan target, we have to add a buffer.
40/// We only need to generate this once, this holds the link information related to that.
41error_buffer: ?Decl.Index = null,
42/// SPIR-V instructions return result-ids.
43/// This variable holds the module-wide counter for these.
44next_result_id: Word = 1,
45/// Some types shouldn't be emitted more than one time, but cannot be caught by
46/// the `intern_map` during codegen. Sometimes, IDs are compared to check if
47/// types are the same, so we can't delay until the dedup pass. Therefore,
48/// this is an ad-hoc structure to cache types where required.
49/// According to the SPIR-V specification, section 2.8, this includes all non-aggregate
50/// non-pointer types.
51/// Additionally, this is used for other values which can be cached, for example,
52/// built-in variables.
53cache: struct {
54 bool_type: ?Id = null,
55 void_type: ?Id = null,
56 opaque_types: std.StringHashMapUnmanaged(Id) = .empty,
57 int_types: std.AutoHashMapUnmanaged(std.lang.Type.Int, Id) = .empty,
58 float_types: std.AutoHashMapUnmanaged(std.lang.Type.Float, Id) = .empty,
59 vector_types: std.AutoHashMapUnmanaged(struct { Id, u32 }, Id) = .empty,
60 array_types: std.AutoHashMapUnmanaged(struct { Id, Id }, Id) = .empty,
61 struct_types: std.array_hash_map.Custom(StructType, Id, StructType.HashContext, true) = .empty,
62 fn_types: std.array_hash_map.Custom(FnType, Id, FnType.HashContext, true) = .empty,
63
64 extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,
65 decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,
66 builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty,
67 strings: std.array_hash_map.String(Id) = .empty,
68
69 bool_const: [2]?Id = .{ null, null },
70 constants: std.array_hash_map.Custom(Constant, Id, Constant.HashContext, true) = .empty,
71
72 spirv_types: std.AutoHashMapUnmanaged(InternPool.Index, Id) = .empty,
73} = .{},
74/// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".
75sections: struct {
76 extended_instruction_set: Section = .{},
77 memory_model: Section = .{},
78 execution_modes: Section = .{},
79 debug_strings: Section = .{},
80 debug_names: Section = .{},
81 annotations: Section = .{},
82 globals: Section = .{},
83 functions: Section = .{},
84} = .{},
85
86pub const big_int_bits = 32;
87
88/// Data can be lowered into in two basic representations: indirect, which is when
89/// a type is stored in memory, and direct, which is how a type is stored when its
90/// a direct SPIR-V value.
91pub const Repr = enum {
92 /// A SPIR-V value as it would be used in operations.
93 direct,
94 /// A SPIR-V value as it is stored in memory.
95 indirect,
96};
97
98/// Declarations, both functions and globals, can have dependencies. These are used for 2 things:
99/// - Globals must be declared before they are used, also between globals. The compiler processes
100/// globals unordered, so we must use the dependencies here to figure out how to order the globals
101/// in the final module. The Globals structure is also used for that.
102/// - Entry points must declare the complete list of OpVariable instructions that they access.
103/// For these we use the same dependency structure.
104/// In this mechanism, globals will only depend on other globals, while functions may depend on
105/// globals or other functions.
106pub const Decl = struct {
107 /// Index to refer to a Decl by.
108 pub const Index = enum(u32) { _ };
109
110 /// Useful to tell what kind of decl this is, and hold the result-id or field index
111 /// to be used for this decl.
112 pub const Kind = enum {
113 func,
114 global,
115 invocation_global,
116 };
117
118 /// See comment on Kind
119 kind: Kind,
120 /// The result-id associated to this decl. The specific meaning of this depends on `kind`:
121 /// - For `func`, this is the result-id of the associated OpFunction instruction.
122 /// - For `global`, this is the result-id of the associated OpVariable instruction.
123 /// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
124 result_id: Id,
125 /// The offset of the first dependency of this decl in the `decl_deps` array.
126 begin_dep: usize = 0,
127 /// The past-end offset of the dependencies of this decl in the `decl_deps` array.
128 end_dep: usize = 0,
129 /// Whether a stub OpFunction/OpFunctionEnd + Import linkage decoration has
130 /// already been emitted for this extern function decl.
131 has_extern_stub: bool = false,
132};
133
134pub const EntryPoint = struct {
135 decl_index: Decl.Index,
136 name: []const u8,
137 cc: std.builtin.CallingConvention,
138};
139
140const StructType = struct {
141 fields: []const Id,
142 ip_index: InternPool.Index,
143
144 const HashContext = struct {
145 pub fn hash(_: @This(), ty: StructType) u32 {
146 var hasher = std.hash.Wyhash.init(0);
147 hasher.update(std.mem.sliceAsBytes(ty.fields));
148 hasher.update(std.mem.asBytes(&ty.ip_index));
149 return @truncate(hasher.final());
150 }
151
152 pub fn eql(_: @This(), a: StructType, b: StructType, _: usize) bool {
153 return a.ip_index == b.ip_index and std.mem.eql(Id, a.fields, b.fields);
154 }
155 };
156};
157
158const FnType = struct {
159 return_ty: Id,
160 params: []const Id,
161
162 const HashContext = struct {
163 pub fn hash(_: @This(), ty: FnType) u32 {
164 var hasher = std.hash.Wyhash.init(0);
165 hasher.update(std.mem.asBytes(&ty.return_ty));
166 hasher.update(std.mem.sliceAsBytes(ty.params));
167 return @truncate(hasher.final());
168 }
169
170 pub fn eql(_: @This(), a: FnType, b: FnType, _: usize) bool {
171 return a.return_ty == b.return_ty and
172 std.mem.eql(Id, a.params, b.params);
173 }
174 };
175};
176
177const Constant = struct {
178 ty: Id,
179 value: spec.LiteralContextDependentNumber,
180
181 const HashContext = struct {
182 pub fn hash(_: @This(), value: Constant) u32 {
183 const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?;
184 var hasher = std.hash.Wyhash.init(0);
185 hasher.update(std.mem.asBytes(&value.ty));
186 hasher.update(std.mem.asBytes(&@as(Tag, value.value)));
187 switch (value.value) {
188 inline else => |v| hasher.update(std.mem.asBytes(&v)),
189 }
190 return @truncate(hasher.final());
191 }
192
193 pub fn eql(_: @This(), a: Constant, b: Constant, _: usize) bool {
194 if (a.ty != b.ty) return false;
195 const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?;
196 if (@as(Tag, a.value) != @as(Tag, b.value)) return false;
197 return switch (a.value) {
198 inline else => |v, tag| v == @field(b.value, @tagName(tag)),
199 };
200 }
201 };
202};
203
204pub fn deinit(module: *Module) void {
205 module.nav_link.deinit(module.gpa);
206 module.uav_link.deinit(module.gpa);
207 module.intern_map.deinit(module.gpa);
208 module.ptr_types.deinit(module.gpa);
209
210 module.sections.extended_instruction_set.deinit(module.gpa);
211 module.sections.memory_model.deinit(module.gpa);
212 module.sections.execution_modes.deinit(module.gpa);
213 module.sections.debug_strings.deinit(module.gpa);
214 module.sections.debug_names.deinit(module.gpa);
215 module.sections.annotations.deinit(module.gpa);
216 module.sections.globals.deinit(module.gpa);
217 module.sections.functions.deinit(module.gpa);
218
219 module.cache.opaque_types.deinit(module.gpa);
220 module.cache.int_types.deinit(module.gpa);
221 module.cache.float_types.deinit(module.gpa);
222 module.cache.vector_types.deinit(module.gpa);
223 module.cache.array_types.deinit(module.gpa);
224 module.cache.struct_types.deinit(module.gpa);
225 module.cache.fn_types.deinit(module.gpa);
226 module.cache.spirv_types.deinit(module.gpa);
227 module.cache.extended_instruction_set.deinit(module.gpa);
228 module.cache.decorations.deinit(module.gpa);
229 module.cache.builtins.deinit(module.gpa);
230 module.cache.strings.deinit(module.gpa);
231
232 module.cache.constants.deinit(module.gpa);
233
234 module.decls.deinit(module.gpa);
235 module.decl_deps.deinit(module.gpa);
236 module.entry_points.deinit(module.gpa);
237
238 module.* = undefined;
239}
240
241/// Fetch or allocate a result id for nav index. This function also marks the nav as alive.
242/// Note: Function does not actually generate the nav, it just allocates an index.
243pub fn resolveNav(module: *Module, ip: *InternPool, nav_index: InternPool.Nav.Index) !Decl.Index {
244 const entry = try module.nav_link.getOrPut(module.gpa, nav_index);
245 if (!entry.found_existing) {
246 const nav = ip.getNav(nav_index);
247 // TODO: Extern fn?
248 const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type))
249 .func
250 else switch (nav.resolved.?.@"addrspace") {
251 .generic => .invocation_global,
252 else => .global,
253 };
254 entry.value_ptr.* = try module.allocDecl(kind);
255 }
256
257 return entry.value_ptr.*;
258}
259
260pub fn allocIds(module: *Module, n: u32) spec.IdRange {
261 defer module.next_result_id += n;
262 return .{ .base = module.next_result_id, .len = n };
263}
264
265pub fn allocId(module: *Module) Id {
266 return module.allocIds(1).at(0);
267}
268
269pub fn idBound(module: Module) Word {
270 return module.next_result_id;
271}
272
273pub fn addEntryPointDeps(
274 module: *Module,
275 decl_index: Decl.Index,
276 seen: *std.bit_set.Dynamic,
277 interface: *std.array_list.Managed(Id),
278) !void {
279 const decl = module.declPtr(decl_index);
280 const deps = module.decl_deps.items[decl.begin_dep..decl.end_dep];
281
282 if (seen.isSet(@intFromEnum(decl_index))) {
283 return;
284 }
285
286 seen.set(@intFromEnum(decl_index));
287
288 if (decl.kind == .global) {
289 try interface.append(decl.result_id);
290 }
291
292 for (deps) |dep| {
293 try module.addEntryPointDeps(dep, seen, interface);
294 }
295}
296
297/// Imports or returns the existing id of an extended instruction set
298pub fn importInstructionSet(module: *Module, set: spec.InstructionSet) !Id {
299 assert(set != .core);
300
301 const gop = try module.cache.extended_instruction_set.getOrPut(module.gpa, set);
302 if (gop.found_existing) return gop.value_ptr.*;
303
304 const result_id = module.allocId();
305 try module.sections.extended_instruction_set.emit(module.gpa, .OpExtInstImport, .{
306 .id_result = result_id,
307 .name = @tagName(set),
308 });
309 gop.value_ptr.* = result_id;
310
311 return result_id;
312}
313
314pub fn boolType(module: *Module) !Id {
315 if (module.cache.bool_type) |id| return id;
316
317 const result_id = module.allocId();
318 try module.sections.globals.emit(module.gpa, .OpTypeBool, .{
319 .id_result = result_id,
320 });
321 module.cache.bool_type = result_id;
322 return result_id;
323}
324
325pub fn voidType(module: *Module) !Id {
326 if (module.cache.void_type) |id| return id;
327
328 const result_id = module.allocId();
329 try module.sections.globals.emit(module.gpa, .OpTypeVoid, .{
330 .id_result = result_id,
331 });
332 module.cache.void_type = result_id;
333 try module.debugName(result_id, "void");
334 return result_id;
335}
336
337pub fn opaqueType(module: *Module, name: []const u8) !Id {
338 if (module.cache.opaque_types.get(name)) |id| return id;
339 const result_id = module.allocId();
340 const name_dup = try module.arena.dupe(u8, name);
341 try module.sections.globals.emit(module.gpa, .OpTypeOpaque, .{
342 .id_result = result_id,
343 .literal_string = name_dup,
344 });
345 try module.debugName(result_id, name_dup);
346 try module.cache.opaque_types.put(module.gpa, name_dup, result_id);
347 return result_id;
348}
349
350pub fn backingIntBits(module: *Module, bits: u16) struct { u16, bool } {
351 assert(bits != 0);
352 const target = module.zcu.getTarget();
353 const ints = [_]struct { bits: u16, enabled: bool }{
354 .{ .bits = 8, .enabled = target.cpu.has(.spirv, .int8) },
355 .{ .bits = 16, .enabled = target.cpu.has(.spirv, .int16) },
356 .{ .bits = 32, .enabled = true },
357 .{ .bits = 64, .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64 },
358 };
359
360 for (ints) |int| {
361 if (bits <= int.bits and int.enabled) return .{ int.bits, false };
362 }
363
364 return .{ std.mem.alignForward(u16, bits, big_int_bits), true };
365}
366
367pub fn intType(module: *Module, signedness: std.lang.Signedness, bits: u16) !Id {
368 assert(bits > 0);
369
370 const target = module.zcu.getTarget();
371 const actual_signedness = switch (target.os.tag) {
372 // Kernel only supports unsigned ints.
373 .opencl, .amdhsa => .unsigned,
374 else => signedness,
375 };
376 const backing_bits, const big_int = module.backingIntBits(bits);
377 if (big_int) {
378 const u32_ty = try module.intType(.unsigned, 32);
379 const len_id = try module.constant(u32_ty, .{ .uint32 = backing_bits / big_int_bits });
380 return module.arrayType(len_id, u32_ty);
381 }
382
383 const entry = try module.cache.int_types.getOrPut(module.gpa, .{ .signedness = actual_signedness, .bits = backing_bits });
384 if (!entry.found_existing) {
385 const result_id = module.allocId();
386 entry.value_ptr.* = result_id;
387 try module.sections.globals.emit(module.gpa, .OpTypeInt, .{
388 .id_result = result_id,
389 .width = backing_bits,
390 .signedness = switch (actual_signedness) {
391 .signed => 1,
392 .unsigned => 0,
393 },
394 });
395
396 switch (actual_signedness) {
397 .signed => try module.debugNameFmt(result_id, "i{}", .{backing_bits}),
398 .unsigned => try module.debugNameFmt(result_id, "u{}", .{backing_bits}),
399 }
400 }
401 return entry.value_ptr.*;
402}
403
404pub fn floatType(module: *Module, bits: u16) !Id {
405 assert(bits > 0);
406 const entry = try module.cache.float_types.getOrPut(module.gpa, .{ .bits = bits });
407 if (!entry.found_existing) {
408 const result_id = module.allocId();
409 entry.value_ptr.* = result_id;
410 try module.sections.globals.emit(module.gpa, .OpTypeFloat, .{
411 .id_result = result_id,
412 .width = bits,
413 });
414 try module.debugNameFmt(result_id, "f{}", .{bits});
415 }
416 return entry.value_ptr.*;
417}
418
419pub fn vectorType(module: *Module, len: u32, child_ty_id: Id) !Id {
420 const entry = try module.cache.vector_types.getOrPut(module.gpa, .{ child_ty_id, len });
421 if (!entry.found_existing) {
422 const result_id = module.allocId();
423 entry.value_ptr.* = result_id;
424 try module.sections.globals.emit(module.gpa, .OpTypeVector, .{
425 .id_result = result_id,
426 .component_type = child_ty_id,
427 .component_count = len,
428 });
429 }
430 return entry.value_ptr.*;
431}
432
433pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id {
434 const entry = try module.cache.array_types.getOrPut(module.gpa, .{ child_ty_id, len_id });
435 if (!entry.found_existing) {
436 const result_id = module.allocId();
437 entry.value_ptr.* = result_id;
438 try module.sections.globals.emit(module.gpa, .OpTypeArray, .{
439 .id_result = result_id,
440 .element_type = child_ty_id,
441 .length = len_id,
442 });
443 }
444 return entry.value_ptr.*;
445}
446
447pub fn ptrType(module: *Module, child_ty_id: Id, storage_class: spec.StorageClass) !Id {
448 const key = .{ child_ty_id, storage_class };
449 const gop = try module.ptr_types.getOrPut(module.gpa, key);
450 if (!gop.found_existing) {
451 gop.value_ptr.* = module.allocId();
452 try module.sections.globals.emit(module.gpa, .OpTypePointer, .{
453 .id_result = gop.value_ptr.*,
454 .storage_class = storage_class,
455 .type = child_ty_id,
456 });
457 return gop.value_ptr.*;
458 }
459 return gop.value_ptr.*;
460}
461
462pub fn structType(
463 module: *Module,
464 types: []const Id,
465 maybe_names: ?[]const []const u8,
466 ip_index: InternPool.Index,
467) !Id {
468 const actual_ip_index = if (module.zcu.comp.config.root_strip) .none else ip_index;
469
470 if (module.cache.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id;
471 const result_id = module.allocId();
472 const types_dup = try module.arena.dupe(Id, types);
473 try module.sections.globals.emit(module.gpa, .OpTypeStruct, .{
474 .id_result = result_id,
475 .id_ref = types_dup,
476 });
477
478 if (maybe_names) |names| {
479 assert(names.len == types.len);
480 for (names, 0..) |name, i| {
481 try module.memberDebugName(result_id, @intCast(i), name);
482 }
483 }
484
485 try module.cache.struct_types.put(
486 module.gpa,
487 .{ .fields = types_dup, .ip_index = actual_ip_index },
488 result_id,
489 );
490 return result_id;
491}
492
493pub fn structFields(module: *const Module, struct_ty_id: Id) ?[]const Id {
494 for (module.cache.struct_types.keys(), module.cache.struct_types.values()) |key, val| {
495 if (val == struct_ty_id) return key.fields;
496 }
497 return null;
498}
499
500pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const Id) !Id {
501 if (module.cache.fn_types.get(.{
502 .return_ty = return_ty_id,
503 .params = param_type_ids,
504 })) |id| return id;
505 const result_id = module.allocId();
506 const params_dup = try module.arena.dupe(Id, param_type_ids);
507 try module.sections.globals.emit(module.gpa, .OpTypeFunction, .{
508 .id_result = result_id,
509 .return_type = return_ty_id,
510 .id_ref_2 = params_dup,
511 });
512 try module.cache.fn_types.put(module.gpa, .{
513 .return_ty = return_ty_id,
514 .params = params_dup,
515 }, result_id);
516 return result_id;
517}
518
519pub fn samplerType(module: *Module, ip_index: InternPool.Index) !Id {
520 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
521 if (!entry.found_existing) {
522 const result_id = module.allocId();
523 entry.value_ptr.* = result_id;
524 try module.sections.globals.emit(module.gpa, .OpTypeSampler, .{
525 .id_result = result_id,
526 });
527 }
528 return entry.value_ptr.*;
529}
530
531pub fn imageType(
532 module: *Module,
533 ip_index: InternPool.Index,
534 sampled_ty_id: Id,
535 dim: spec.Dim,
536 depth: spec.LiteralInteger,
537 arrayed: spec.LiteralInteger,
538 ms: spec.LiteralInteger,
539 sampled: spec.LiteralInteger,
540 image_format: spec.ImageFormat,
541 access_qualifier: ?spec.AccessQualifier,
542) !Id {
543 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
544 if (!entry.found_existing) {
545 const result_id = module.allocId();
546 entry.value_ptr.* = result_id;
547 try module.sections.globals.emit(module.gpa, .OpTypeImage, .{
548 .id_result = result_id,
549 .sampled_type = sampled_ty_id,
550 .dim = dim,
551 .depth = depth,
552 .arrayed = arrayed,
553 .ms = ms,
554 .sampled = sampled,
555 .image_format = image_format,
556 .access_qualifier = access_qualifier,
557 });
558 }
559 return entry.value_ptr.*;
560}
561
562pub fn sampledImageType(module: *Module, ip_index: InternPool.Index, image_ty_id: Id) !Id {
563 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
564 if (!entry.found_existing) {
565 const result_id = module.allocId();
566 entry.value_ptr.* = result_id;
567 try module.sections.globals.emit(module.gpa, .OpTypeSampledImage, .{
568 .id_result = result_id,
569 .image_type = image_ty_id,
570 });
571 }
572 return entry.value_ptr.*;
573}
574
575pub fn runtimeArrayType(module: *Module, ip_index: InternPool.Index, elem_ty_id: Id) !Id {
576 const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index);
577 if (!entry.found_existing) {
578 const result_id = module.allocId();
579 entry.value_ptr.* = result_id;
580 try module.sections.globals.emit(module.gpa, .OpTypeRuntimeArray, .{
581 .id_result = result_id,
582 .element_type = elem_ty_id,
583 });
584 }
585 return entry.value_ptr.*;
586}
587
588pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id {
589 const gop = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value });
590 if (!gop.found_existing) {
591 gop.value_ptr.* = module.allocId();
592 try module.sections.globals.emit(module.gpa, .OpConstant, .{
593 .id_result_type = ty_id,
594 .id_result = gop.value_ptr.*,
595 .value = value,
596 });
597 }
598 return gop.value_ptr.*;
599}
600
601pub fn constBool(module: *Module, value: bool) !Id {
602 if (module.cache.bool_const[@intFromBool(value)]) |b| return b;
603
604 const result_ty_id = try module.boolType();
605 const result_id = module.allocId();
606 module.cache.bool_const[@intFromBool(value)] = result_id;
607
608 switch (value) {
609 inline else => |value_ct| try module.sections.globals.emit(
610 module.gpa,
611 if (value_ct) .OpConstantTrue else .OpConstantFalse,
612 .{
613 .id_result_type = result_ty_id,
614 .id_result = result_id,
615 },
616 ),
617 }
618
619 return result_id;
620}
621
622pub fn builtin(
623 module: *Module,
624 result_ty_id: Id,
625 spirv_builtin: spec.BuiltIn,
626 storage_class: spec.StorageClass,
627) !Decl.Index {
628 const gop = try module.cache.builtins.getOrPut(module.gpa, .{ spirv_builtin, storage_class });
629 if (!gop.found_existing) {
630 const decl_index = try module.allocDecl(.global);
631 const decl = module.declPtr(decl_index);
632
633 gop.value_ptr.* = decl_index;
634 try module.sections.globals.emit(module.gpa, .OpVariable, .{
635 .id_result_type = result_ty_id,
636 .id_result = decl.result_id,
637 .storage_class = storage_class,
638 });
639 try module.decorate(decl.result_id, .{ .built_in = .{ .built_in = spirv_builtin } });
640 }
641 return gop.value_ptr.*;
642}
643
644pub fn constUndef(module: *Module, ty_id: Id) !Id {
645 const result_id = module.allocId();
646 try module.sections.globals.emit(module.gpa, .OpUndef, .{
647 .id_result_type = ty_id,
648 .id_result = result_id,
649 });
650 return result_id;
651}
652
653pub fn constNull(module: *Module, ty_id: Id) !Id {
654 const result_id = module.allocId();
655 try module.sections.globals.emit(module.gpa, .OpConstantNull, .{
656 .id_result_type = ty_id,
657 .id_result = result_id,
658 });
659 return result_id;
660}
661
662/// Decorate a result-id.
663pub fn decorate(
664 module: *Module,
665 target: Id,
666 decoration: spec.Decoration.Extended,
667) !void {
668 const gop = try module.cache.decorations.getOrPut(module.gpa, .{ target, decoration });
669 if (!gop.found_existing) {
670 try module.sections.annotations.emit(module.gpa, .OpDecorate, .{
671 .target = target,
672 .decoration = decoration,
673 });
674 }
675}
676
677/// Decorate a result-id which is a member of some struct.
678/// We really don't have to and shouldn't need to cache this.
679pub fn decorateMember(
680 module: *Module,
681 structure_type: Id,
682 member: u32,
683 decoration: spec.Decoration.Extended,
684) !void {
685 try module.sections.annotations.emit(module.gpa, .OpMemberDecorate, .{
686 .structure_type = structure_type,
687 .member = member,
688 .decoration = decoration,
689 });
690}
691
692pub fn allocDecl(module: *Module, kind: Decl.Kind) !Decl.Index {
693 try module.decls.append(module.gpa, .{
694 .kind = kind,
695 .result_id = module.allocId(),
696 });
697
698 return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(module.decls.items.len - 1))));
699}
700
701pub fn declPtr(module: *Module, index: Decl.Index) *Decl {
702 return &module.decls.items[@intFromEnum(index)];
703}
704
705/// Declare a SPIR-V function as an entry point. This causes an extra wrapper
706/// function to be generated, which is then exported as the real entry point. The purpose of this
707/// wrapper is to allocate and initialize the structure holding the instance globals.
708pub fn declareEntryPoint(
709 module: *Module,
710 decl_index: Decl.Index,
711 name: []const u8,
712 cc: std.builtin.CallingConvention,
713) !void {
714 const gop = try module.entry_points.getOrPut(module.gpa, module.declPtr(decl_index).result_id);
715 gop.value_ptr.decl_index = decl_index;
716 gop.value_ptr.name = name;
717 gop.value_ptr.cc = cc;
718}
719
720pub fn debugName(module: *Module, target: Id, name: []const u8) !void {
721 if (module.zcu.comp.config.root_strip) return;
722 try module.sections.debug_names.emit(module.gpa, .OpName, .{
723 .target = target,
724 .name = name,
725 });
726}
727
728pub fn debugNameFmt(module: *Module, target: Id, comptime fmt: []const u8, args: anytype) !void {
729 if (module.zcu.comp.config.root_strip) return;
730 const name = try std.fmt.allocPrint(module.gpa, fmt, args);
731 defer module.gpa.free(name);
732 try module.debugName(target, name);
733}
734
735pub fn memberDebugName(module: *Module, target: Id, member: u32, name: []const u8) !void {
736 if (module.zcu.comp.config.root_strip) return;
737 try module.sections.debug_names.emit(module.gpa, .OpMemberName, .{
738 .type = target,
739 .member = member,
740 .name = name,
741 });
742}
743
744pub fn debugString(module: *Module, string: []const u8) !Id {
745 const entry = try module.cache.strings.getOrPut(module.gpa, string);
746 if (!entry.found_existing) {
747 entry.value_ptr.* = module.allocId();
748 try module.sections.debug_strings.emit(module.gpa, .OpString, .{
749 .id_result = entry.value_ptr.*,
750 .string = string,
751 });
752 }
753 return entry.value_ptr.*;
754}
755
756pub fn storageClass(module: *Module, as: std.lang.AddressSpace) spec.StorageClass {
757 const target = module.zcu.getTarget();
758 return switch (as) {
759 .generic => .function,
760 .global => switch (target.os.tag) {
761 .opencl, .amdhsa => .cross_workgroup,
762 else => .storage_buffer,
763 },
764 .push_constant => .push_constant,
765 .output => .output,
766 .uniform => .uniform,
767 .storage_buffer => .storage_buffer,
768 .physical_storage_buffer => .physical_storage_buffer,
769 .constant => .uniform_constant,
770 .shared => .workgroup,
771 .local => .function,
772 .input => .input,
773 .gs,
774 .fs,
775 .ss,
776 .far,
777 .param,
778 .flash,
779 .flash1,
780 .flash2,
781 .flash3,
782 .flash4,
783 .flash5,
784 .cog,
785 .lut,
786 .hub,
787 .externref,
788 .funcref,
789 => unreachable,
790 };
791}
src/link/SpirV.zig+66-40
......@@ -1034,10 +1034,6 @@ fn collectEntryPointInterface(
10341034 for (mir.decl_deps) |dep| {
10351035 try collectEntryPointInterface(linker, dep.nav, interface, visited, nav_final_ids, uav_final_ids, frag_infos, gpa);
10361036 }
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 }
10411037}
10421038
10431039fn remapAndAppend(
......@@ -1078,52 +1074,82 @@ fn remapAndAppendInst(
10781074 for (inst_spec.operands) |operand| {
10791075 const cat = operand.kind.category();
10801076 switch (operand.quantifier) {
1081 .required => {
1077 .required, .optional => {
10821078 if (offset >= inst.operands.len) break;
1083 if (cat == .id) {
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 }
1079 offset += remapOperand(operand.kind, cat, inst, inst_slice, offset, id_offset, id_remap);
11051080 },
11061081 .variadic => {
11071082 while (offset < inst.operands.len) {
1108 if (cat == .id) {
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 }
1083 offset += remapOperand(operand.kind, cat, inst, inst_slice, offset, id_offset, id_remap);
11211084 }
11221085 },
11231086 }
11241087 }
11251088}
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
11271153fn remapCompositeOperand(
11281154 kind: spec.OperandKind,
11291155 inst_slice: []Word,
src/link/SpirV/prune_unused.zig+1-3
......@@ -92,9 +92,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
9292 }
9393
9494 // mark operands of alive function contents
95 if (!canPrune(inst.opcode)) {
96 try markAlive(parser, binary.*, inst, &alive, &id_to_index, &code_offsets, &id_offset_buf);
97 }
95 try markAlive(parser, binary.*, inst, &alive, &id_to_index, &code_offsets, &id_offset_buf);
9896 }
9997
10098 // rewrite
test/behavior/array.zig+4
......@@ -654,6 +654,8 @@ test "array of array agregate init" {
654654}
655655
656656test "pointer to array has ptr field" {
657 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
658
657659 const arr: *const [5]u32 = &.{ 10, 20, 30, 40, 50 };
658660 try std.testing.expect(arr.ptr == @as([*]const u32, arr));
659661 try std.testing.expect(arr.ptr[0] == 10);
......@@ -1150,6 +1152,8 @@ test "resist alias of explicit copy of array passed as arg" {
11501152}
11511153
11521154test "access element through reference" {
1155 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1156
11531157 const S = struct {
11541158 fn doTheTest(x: u8) !void {
11551159 {
test/behavior/bitcast.zig+10
......@@ -439,6 +439,8 @@ test "@bitCast of packed struct with void field to integer" {
439439}
440440
441441test "@bitCast vector to array with different element size" {
442 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
443
442444 const static = struct {
443445 fn doTheTest(v: @Vector(4, u5)) !void {
444446 const result: [5]u4 = @bitCast(v);
......@@ -462,6 +464,8 @@ test "@bitCast vector to array with different element size" {
462464}
463465
464466test "@bitCast packed struct to array of bits" {
467 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
468
465469 const S = packed struct(u16) {
466470 foo: u5,
467471 bar: i7,
......@@ -508,6 +512,8 @@ test "@bitCast packed struct to array of bits" {
508512}
509513
510514test "@bitCast nested arrays of vectors" {
515 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
516
511517 const Src = [2][2]@Vector(4, u5);
512518 const Dest = [5]@Vector(2, u8);
513519
......@@ -543,6 +549,8 @@ test "@bitCast nested arrays of vectors" {
543549}
544550
545551test "@bitCast nested arrays of bool to scalar" {
552 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
553
546554 const static = struct {
547555 fn doTheTest(src: [4][4]bool) !void {
548556 const result: u16 = @bitCast(src);
......@@ -560,6 +568,8 @@ test "@bitCast nested arrays of bool to scalar" {
560568}
561569
562570test "@bitCast deeply nested arrays to scalar" {
571 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
572
563573 const static = struct {
564574 fn doTheTest(src: [2][1][3][5]u4) !void {
565575 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" {
585585}
586586
587587test "reinterpret sentinel-terminated array as packed struct" {
588 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
589
588590 const S = packed struct(u16) { lo: u8, hi: u8 };
589591 const data: [2:0]u8 = .{ 0x12, 0x34 };
590592 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 };
1616test "store to global vector" {
1717 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1818 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1920
2021 try expect(vpos[1] == 0.0);
2122 vpos = @Vector(2, f32){ 0.0, 1.0 };
test/behavior/spirv.zig+1-1
......@@ -10,7 +10,7 @@ const Image = @SpirvType(.{ .image = .{
1010} });
1111const SampledImage = @SpirvType(.{ .sampled_image = Image });
1212const StorageImage = @SpirvType(.{ .image = .{
13 .usage = .storage,
13 .usage = .{ .storage = u32 },
1414 .format = .unknown,
1515 .dim = .@"2d",
1616 .depth = .unknown,
test/behavior/type_info.zig+40
......@@ -613,3 +613,43 @@ test "@typeInfo function with generic return type and inferred error set" {
613613 const ret_ty = @typeInfo(@TypeOf(S.testFn)).@"fn".return_type;
614614 comptime assert(ret_ty == null);
615615}
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
77// compile
88// output_mode=Obj
99// backend=selfhosted
10// target=spirv64-vulkan
11// emit_bin=false
10// target=spirv32-vulkan
11// 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 @@
11comptime {
22 _ = @SpirvType(.{ .image = .{
3 .usage = .storage,
3 .usage = .{ .storage = u32 },
44 .format = .unknown,
55 .dim = .@"2d",
66 .depth = .unknown,
......@@ -48,7 +48,7 @@ comptime {
4848
4949// error
5050// backend=selfhosted
51// target=spirv64-vulkan
51// target=spirv32-vulkan
5252//
5353// :2:21: error: access qualifier '.read_only' is only valid under the 'opencl' os
5454// :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 {
2121
2222// error
2323// backend=selfhosted
24// target=spirv64-vulkan
24// target=spirv32-vulkan
2525//
2626// :1:28: error: kernel workgroup dimensions must be at least 1
2727// :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 {
2222// error
2323// backend=selfhosted
2424// target=spirv64-opencl
25// cpu_features=opencl_v2+mesh_shading_ext
2526//
2627// :1:28: error: calling convention 'spirv_fragment' not supported by compiler backend 'stage2_spirv'
2728// :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 {
2525
2626// error
2727// backend=selfhosted
28// target=spirv64-vulkan
28// target=spirv32-vulkan
2929//
3030// :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct
3131// :4:8: note: opaque types have unknown size
test/cases/compile_errors/extern_spirv_decoration_validation.zig+1-1
......@@ -8,6 +8,6 @@ comptime {
88
99// error
1010// backend=selfhosted
11// target=spirv64-vulkan
11// target=spirv32-vulkan
1212//
1313// :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 {
1111}
1212
1313// error
14// target=spirv64-vulkan
14// target=spirv32-vulkan
1515//
1616// :9:13: error: value with non-mergable pointer type '*i32' depends on runtime control flow
1717// :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_spirv
18// :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 {
1313// compile
1414// output_mode=Obj
1515// backend=selfhosted
16// target=spirv64-vulkan
17// emit_bin=false
16// target=spirv32-vulkan
17// emit_bin=true
test/src/Cases.zig+12-1
......@@ -357,7 +357,15 @@ fn addFromDirInner(
357357 var manifest = try TestManifest.parse(ctx.arena, src);
358358
359359 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 }
361369 const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);
362370 const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);
363371 const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);
......@@ -707,6 +715,8 @@ const TestManifestConfigDefaults = struct {
707715 return "null";
708716 } else if (std.mem.eql(u8, key, "imports")) {
709717 return "";
718 } else if (std.mem.eql(u8, key, "cpu_features")) {
719 return "";
710720 } else unreachable;
711721 }
712722};
......@@ -739,6 +749,7 @@ const TestManifest = struct {
739749 .{ "is_test", {} },
740750 .{ "output_mode", {} },
741751 .{ "target", {} },
752 .{ "cpu_features", {} },
742753 .{ "c_frontend", {} },
743754 .{ "link_libc", {} },
744755 .{ "backend", {} },