authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-17 00:31:17+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-18 13:38:58+02:00
log508cbec69455d82c0e9bb5ae47f064ab33460469
treea7dff5e985ff33474e1f5982767e4dd1a18749d1
parent4653794852923e08cceab69620b7d0bb5d11e42d

spirv: implement tuple types


8 files changed, 40 insertions(+), 29 deletions(-)

src/codegen/spirv/CodeGen.zig+17-1
...@@ -1286,7 +1286,23 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1286,7 +1286,23 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1286 const comp_ty_id = try cg.resolveType(ty, .direct);1286 const comp_ty_id = try cg.resolveType(ty, .direct);
1287 return try cg.constructComposite(comp_ty_id, constituents.items);1287 return try cg.constructComposite(comp_ty_id, constituents.items);
1288 },1288 },
1289 .tuple_type => return cg.todo("implement tuple types", .{}),1289 .tuple_type => |tuple| {
1290 var constituents: std.ArrayList(Id) = .empty;
1291 defer constituents.deinit(gpa);
1292
1293 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
1294 if (field_val != .none) continue;
1295 const ft: Type = .fromInterned(field_ty);
1296 if (!ft.hasRuntimeBits(zcu)) continue;
1297
1298 const fv = try val.fieldValue(pt, i);
1299 const field_id = try cg.constant(ft, fv, .indirect);
1300 try constituents.append(gpa, field_id);
1301 }
1302
1303 const comp_ty_id = try cg.resolveType(ty, .direct);
1304 return try cg.constructComposite(comp_ty_id, constituents.items);
1305 },
1290 else => unreachable,1306 else => unreachable,
1291 },1307 },
1292 .un => |un| {1308 .un => |un| {
src/link/SpirV/lower_invocation_globals.zig+22-11
...@@ -457,21 +457,31 @@ const ModuleBuilder = struct {...@@ -457,21 +457,31 @@ const ModuleBuilder = struct {
457 },457 },
458 .OpEntryPoint => {458 .OpEntryPoint => {
459 const original_id: ResultId = @enumFromInt(inst.operands[1]);459 const original_id: ResultId = @enumFromInt(inst.operands[1]);
460 const new_id_index = info.entry_points.getIndex(original_id).?;460 const fn_info = info.functions.get(original_id).?;
461 const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index);461 if (fn_info.invocation_globals.count() > 0) {
462 try self.section.emitRaw(self.arena, .OpEntryPoint, inst.operands.len);462 const new_id_index = info.entry_points.getIndex(original_id).?;
463 self.section.writeWord(inst.operands[0]);463 const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index);
464 self.section.writeOperand(ResultId, new_id);464 try self.section.emitRaw(self.arena, .OpEntryPoint, inst.operands.len);
465 self.section.writeWords(inst.operands[2..]);465 self.section.writeWord(inst.operands[0]);
466 self.section.writeOperand(ResultId, new_id);
467 self.section.writeWords(inst.operands[2..]);
468 } else {
469 try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands);
470 }
466 continue;471 continue;
467 },472 },
468 .OpExecutionMode, .OpExecutionModeId => {473 .OpExecutionMode, .OpExecutionModeId => {
469 const original_id: ResultId = @enumFromInt(inst.operands[0]);474 const original_id: ResultId = @enumFromInt(inst.operands[0]);
470 const new_id_index = info.entry_points.getIndex(original_id).?;475 const fn_info = info.functions.get(original_id).?;
471 const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index);476 if (fn_info.invocation_globals.count() > 0) {
472 try self.section.emitRaw(self.arena, inst.opcode, inst.operands.len);477 const new_id_index = info.entry_points.getIndex(original_id).?;
473 self.section.writeOperand(ResultId, new_id);478 const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index);
474 self.section.writeWords(inst.operands[1..]);479 try self.section.emitRaw(self.arena, inst.opcode, inst.operands.len);
480 self.section.writeOperand(ResultId, new_id);
481 self.section.writeWords(inst.operands[1..]);
482 } else {
483 try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands);
484 }
475 continue;485 continue;
476 },486 },
477 .OpTypeFunction => {487 .OpTypeFunction => {
...@@ -652,6 +662,7 @@ const ModuleBuilder = struct {...@@ -652,6 +662,7 @@ const ModuleBuilder = struct {
652662
653 for (info.entry_points.keys(), 0..) |func, entry_point_index| {663 for (info.entry_points.keys(), 0..) |func, entry_point_index| {
654 const fn_info = info.functions.get(func).?;664 const fn_info = info.functions.get(func).?;
665 if (fn_info.invocation_globals.count() == 0) continue;
655 const ep_id: ResultId = @enumFromInt(self.entry_point_new_id_base + @as(u32, @intCast(entry_point_index)));666 const ep_id: ResultId = @enumFromInt(self.entry_point_new_id_base + @as(u32, @intCast(entry_point_index)));
656 const fn_type = self.function_types.get(.{667 const fn_type = self.function_types.get(.{
657 .return_type = fn_info.return_type,668 .return_type = fn_info.return_type,
test/behavior/basic.zig-6
...@@ -302,9 +302,6 @@ test "compile time global reinterpret" {...@@ -302,9 +302,6 @@ test "compile time global reinterpret" {
302}302}
303303
304test "cast undefined" {304test "cast undefined" {
305 // if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
306 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
307
308 const array: [100]u8 = undefined;305 const array: [100]u8 = undefined;
309 const slice = @as([]const u8, &array);306 const slice = @as([]const u8, &array);
310 testCastUndefined(slice);307 testCastUndefined(slice);
...@@ -374,9 +371,7 @@ fn fB() []const u8 {...@@ -374,9 +371,7 @@ fn fB() []const u8 {
374test "call function pointer in struct" {371test "call function pointer in struct" {
375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
376 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;373 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
377
378 try expect(mem.eql(u8, f3(true), "a"));374 try expect(mem.eql(u8, f3(true), "a"));
379 try expect(mem.eql(u8, f3(false), "b"));
380}375}
381376
382fn f3(x: bool) []const u8 {377fn f3(x: bool) []const u8 {
...@@ -417,7 +412,6 @@ test "call result of if else expression" {...@@ -417,7 +412,6 @@ test "call result of if else expression" {
417 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;412 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
418413
419 try expect(mem.eql(u8, f2(true), "a"));414 try expect(mem.eql(u8, f2(true), "a"));
420 try expect(mem.eql(u8, f2(false), "b"));
421}415}
422fn f2(x: bool) []const u8 {416fn f2(x: bool) []const u8 {
423 return (if (x) &fA else &fB)();417 return (if (x) &fA else &fB)();
test/behavior/cast.zig+1-1
...@@ -2541,7 +2541,7 @@ test "peer type resolution: many compatible pointers" {...@@ -2541,7 +2541,7 @@ test "peer type resolution: many compatible pointers" {
2541test "peer type resolution: tuples with comptime fields" {2541test "peer type resolution: tuples with comptime fields" {
2542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2544 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO2544 // if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
25452545
2546 const a = .{ 1, 2 };2546 const a = .{ 1, 2 };
2547 const b = .{ @as(u32, 3), @as(i16, 4) };2547 const b = .{ @as(u32, 3), @as(i16, 4) };
test/behavior/eval.zig-3
...@@ -1159,8 +1159,6 @@ test "repeated value is correctly expanded" {...@@ -1159,8 +1159,6 @@ test "repeated value is correctly expanded" {
1159}1159}
11601160
1161test "value in if block is comptime-known" {1161test "value in if block is comptime-known" {
1162 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1163
1164 const first = blk: {1162 const first = blk: {
1165 const s = if (false) "a" else "b";1163 const s = if (false) "a" else "b";
1166 break :blk "foo" ++ s;1164 break :blk "foo" ++ s;
...@@ -1196,7 +1194,6 @@ test "lazy value is resolved as slice operand" {...@@ -1196,7 +1194,6 @@ test "lazy value is resolved as slice operand" {
1196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1197 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1198 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1196 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1199
1200 const A = struct { a: u32 };1197 const A = struct { a: u32 };
1201 var a: [512]u64 = undefined;1198 var a: [512]u64 = undefined;
12021199
test/behavior/math.zig-3
...@@ -456,8 +456,6 @@ test "division" {...@@ -456,8 +456,6 @@ test "division" {
456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
457 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO457 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;458 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
459 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
460
461 try testIntDivision();459 try testIntDivision();
462 try comptime testIntDivision();460 try comptime testIntDivision();
463461
...@@ -576,7 +574,6 @@ test "large integer division" {...@@ -576,7 +574,6 @@ test "large integer division" {
576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
577 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;575 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
578 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;576 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
579 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
580577
581 {578 {
582 var numerator: u256 = 99999999999999999997315645440;579 var numerator: u256 = 99999999999999999997315645440;
test/behavior/struct.zig-3
...@@ -503,8 +503,6 @@ test "implicit cast packed struct field to const ptr" {...@@ -503,8 +503,6 @@ test "implicit cast packed struct field to const ptr" {
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
507 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
508506
509 const LevelUpMove = packed struct {507 const LevelUpMove = packed struct {
510 move_id: u9,508 move_id: u9,
...@@ -538,7 +536,6 @@ test "packed struct with non-ABI-aligned field" {...@@ -538,7 +536,6 @@ test "packed struct with non-ABI-aligned field" {
538 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO536 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
539 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO537 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
540 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;538 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
541 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
542539
543 const S = packed struct {540 const S = packed struct {
544 x: u9,541 x: u9,
test/behavior/tuple.zig-1
...@@ -225,7 +225,6 @@ test "initializing anon struct with mixed comptime-runtime fields" {...@@ -225,7 +225,6 @@ test "initializing anon struct with mixed comptime-runtime fields" {
225test "tuple in tuple passed to generic function" {225test "tuple in tuple passed to generic function" {
226 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO226 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
228 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
229 const S = struct {228 const S = struct {
230 fn pair(x: f32, y: f32) @Tuple(&.{ f32, f32 }) {229 fn pair(x: f32, y: f32) @Tuple(&.{ f32, f32 }) {
231 return .{ x, y };230 return .{ x, y };