diff --git a/src/Sema.zig b/src/Sema.zig index 835b95acb0768371855adc76ab7c7eb144bd933f..0e58f0c819bf00d512bd58aa7f346e634bdb0368 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25377,12 +25377,16 @@ pub fn explainWhyTypeIsNotExtern( .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), .@"opaque", - .spirv, .bool, .float, .@"anyframe", => unreachable, // these *are* allowed + .spirv => { + assert(ty.isSpirvRuntimeArray(zcu)); + try sema.errNote(src_loc, msg, "SPIR-V runtime arrays must be the last field of an extern struct", .{}); + }, + .pointer => if (ty.isSlice(zcu)) { try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); } else { @@ -30541,6 +30545,10 @@ fn analyzeLoad( try sema.ensureLayoutResolved(elem_ty, src, .ptr_access); + if (elem_ty.isSpirvRuntimeArray(zcu)) { + return sema.fail(block, src, "cannot load SPIR-V runtime array value", .{}); + } + const comptime_only = switch (elem_ty.classify(zcu)) { .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) { .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}), diff --git a/src/Type.zig b/src/Type.zig index e648e48dd3c0e44ff49d743463b3400c4cc192f4..0e54f7c51f36c9a88558c792b7fed439929f68c7 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -3119,12 +3119,16 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool .noreturn => position == .ret_ty, .@"opaque", - .spirv, .bool, .float, .@"anyframe", => true, + .spirv => switch (position) { + .struct_field, .union_field => true, + .ret_ty, .param_ty, .element, .other => !ty.isSpirvRuntimeArray(zcu), + }, + .pointer => { if (ty.isSlice(zcu)) return false; const child_ty = ty.childType(zcu); diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig index 329ea763adde6ae390cfa0c6626aa740b9593338..0ea7567b5eed6859069b031835c57d1b539afbed 100644 --- a/src/codegen/spirv/CodeGen.zig +++ b/src/codegen/spirv/CodeGen.zig @@ -625,6 +625,49 @@ pub fn layoutType(cg: *CodeGen, ty: Type, is_block_root: bool) Error!Id { }); break :id id; }, + .@"union" => id: { + const union_obj = zcu.typeToUnion(ty).?; + if (union_obj.layout == .@"packed") return cg.resolveType(ty, .indirect); + + const layout = cg.unionLayout(ty); + if (!layout.has_payload) return cg.resolveType(ty, .indirect); + + const id = cg.allocId(); + if (is_block_root) try cg.decorate(id, .block); + + var member_types: [4]Id = undefined; + const u8_id = try cg.resolveType(.u8, .direct); + if (layout.tag_size != 0) { + const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); + try cg.decorateMember(id, layout.tag_index, .{ .offset = .{ + .byte_offset = @intCast(ty.unionGetLayout(zcu).tagOffset()), + } }); + member_types[layout.tag_index] = try cg.layoutType(tag_ty, false); + } + if (layout.payload_size != 0) { + try cg.decorateMember(id, layout.payload_index, .{ .offset = .{ + .byte_offset = @intCast(ty.unionGetLayout(zcu).payloadOffset()), + } }); + member_types[layout.payload_index] = try cg.layoutType(layout.payload_ty, false); + } + if (layout.payload_padding_size != 0) { + const len_id = try cg.constInt(.u32, layout.payload_padding_size); + const arr_id = try cg.arrayType(len_id, u8_id); + try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } }); + member_types[layout.payload_padding_index] = arr_id; + } + if (layout.padding_size != 0) { + const len_id = try cg.constInt(.u32, layout.padding_size); + const arr_id = try cg.arrayType(len_id, u8_id); + try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } }); + member_types[layout.padding_index] = arr_id; + } + try cg.sections.globals.emit(gpa, .OpTypeStruct, .{ + .id_result = id, + .id_ref = member_types[0..layout.total_fields], + }); + break :id id; + }, .array => id: { const elem_ty = ty.childType(zcu); const elem_ty_id = try cg.layoutType(elem_ty, false); @@ -1883,8 +1926,13 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { const nav_ty_id = try cg.resolveType(nav_ty, .indirect); const decl_ptr_ty_id = try cg.ptrType(nav_ty_id, storage_class); - if (nav_ty.zigTypeTag(zcu) == .@"struct" and cg.needsLayout(nav.resolved.?.@"addrspace", nav_ty)) { - try cg.block_var_ids.put(gpa, spv_decl.result_id, {}); + switch (nav_ty.zigTypeTag(zcu)) { + .@"struct", .@"union" => { + if (cg.needsLayout(nav.resolved.?.@"addrspace", nav_ty)) { + try cg.block_var_ids.put(gpa, spv_decl.result_id, {}); + } + }, + else => {}, } if (decl_ptr_ty_id == ty_id) return spv_decl.result_id; switch (target.os.tag) { @@ -4175,7 +4223,7 @@ fn needsLayout(cg: *CodeGen, as: std.lang.AddressSpace, pointee_ty: Type) bool { else => return false, } return switch (pointee_ty.zigTypeTag(cg.zcu)) { - .@"struct", .array => true, + .@"struct", .@"union", .array => true, .spirv => pointee_ty.isSpirvRuntimeArray(cg.zcu), else => false, }; @@ -4222,6 +4270,8 @@ fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id { } fn store(cg: *CodeGen, value_ty: Type, ptr_id: Id, value_id: Id, options: MemoryOptions) !void { + const zcu = cg.zcu; + const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?); const bare_value_id = try cg.convertToIndirect(value_ty, value_id); const bare_ty_id = try cg.resolveType(value_ty, .indirect); const store_ty_id = if (cg.needsLayout(options.ptr_address_space, value_ty)) @@ -4232,7 +4282,10 @@ fn store(cg: *CodeGen, value_ty: Type, ptr_id: Id, value_id: Id, options: Memory try cg.body.emit(cg.gpa, .OpStore, .{ .pointer = ptr_id, .object = object_id, - .memory_access = .{ .@"volatile" = options.is_volatile }, + .memory_access = .{ + .@"volatile" = options.is_volatile, + .aligned = .{ .literal_integer = alignment }, + }, }); } @@ -6896,6 +6949,20 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, .function); const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index}); + if (field_ty.toIntern() == layout.payload_ty.toIntern()) { + return try cg.load(field_ty, pl_ptr_id, .{}); + } + + switch (zcu.getTarget().os.tag) { + .vulkan, .opengl => { + // Logical addressing forbids OpBitcast on pointers. Load the + // payload as its type and bitcast the value instead. + const payload_id = try cg.load(layout.payload_ty, pl_ptr_id, .{}); + return try cg.bitCast(field_ty, layout.payload_ty, payload_id); + }, + else => {}, + } + const field_ty_id = try cg.resolveType(field_ty, .indirect); const active_pl_ptr_ty_id = try cg.ptrType(field_ty_id, .function); const active_pl_ptr_id = cg.allocId(); @@ -7008,6 +7075,23 @@ fn structFieldPtr( } const storage_class = cg.storageClass(object_ptr_ty.ptrAddressSpace(zcu)); + const field_ty = result_ptr_ty.childType(zcu); + if (field_ty.toIntern() == layout.payload_ty.toIntern()) { + if (object_ty.containerLayout(zcu) == .@"packed") return object_ptr; + return try cg.accessChain(result_ty_id, object_ptr, &.{layout.payload_index}); + } + + switch (zcu.getTarget().os.tag) { + .vulkan, .opengl => { + // Logical addressing forbids OpBitcast on pointers. If the field + // type is structurally identical to the payload type (dedup will + // unify them) the access chain typed as the field type is valid. + if (object_ty.containerLayout(zcu) == .@"packed") return object_ptr; + return try cg.accessChain(result_ty_id, object_ptr, &.{layout.payload_index}); + }, + else => {}, + } + const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect); const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, storage_class); const pl_ptr_id = blk: { diff --git a/test/behavior/align.zig b/test/behavior/align.zig index cb300d535060891096337de5c0996e48e8870eb9..9ffb238dfdb9994bf587b7e4e4b5743842dbcc4c 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -89,8 +89,6 @@ test "implicitly-aligned pointer is coercible to equivalent explicitly-aligned p } test "implicitly decreasing pointer alignment" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const a: u32 align(4) = 3; const b: u32 align(8) = 4; try expect(addUnaligned(&a, &b) == 7); @@ -450,7 +448,6 @@ test "read 128-bit field from default aligned struct in global memory" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(12 == default_aligned_global.badguy); } @@ -505,7 +502,6 @@ test "comptime alloc alignment" { if (true) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky comptime var bytes1 = [_]u8{0}; _ = &bytes1; diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 4a68b51d33f11593b29f4783deec3b0267184a65..55024fdf559ebb8521737017252e07f096c107ab 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -7,7 +7,6 @@ const expect = testing.expect; const expectEqual = testing.expectEqual; test "array to slice" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const a: u32 align(4) = 3; const b: u32 align(8) = 4; const a_slice: []align(1) const u32 = @as(*const [1]u32, &a)[0..]; diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index 3b77d2c6023256829590cc98d9b8c217e6bbe660..b3b64af19b9d99ed922ec087209d02ecab14354a 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -138,7 +138,6 @@ test "bitcast packed struct to integer and back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const LevelUpMove = packed struct { move_id: u9, diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 1cd6d009e6b07031bbcf8fe0f17f56b7b479c24e..c2604072144f4b65cd34e622acc8a29c49c559f8 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1811,7 +1811,6 @@ test "cast compatible optional types" { } test "coerce undefined single-item pointer of array to error union of slice" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const a = @as([*]u8, undefined)[0..0]; @@ -1901,8 +1900,6 @@ test "cast typed undefined to int" { // } test "bitcast packed struct with u0" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = packed struct(u2) { a: u0, b: u2 }; const s = @as(S, @bitCast(@as(u2, 2))); try expect(s.a == 0); @@ -1976,7 +1973,6 @@ test "peer type resolution forms error union" { } test "@constCast without a result location" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const x: i32 = 1234; const y = @constCast(&x); try expect(@TypeOf(y) == *i32); @@ -1984,7 +1980,6 @@ test "@constCast without a result location" { } test "@constCast optional" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const x: u8 = 10; const m: ?*const u8 = &x; const p = @constCast(m); @@ -2552,7 +2547,6 @@ test "peer type resolution: many compatible pointers" { test "peer type resolution: tuples with comptime fields" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - // if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const a = .{ 1, 2 }; const b = .{ @as(u32, 3), @as(i16, 4) }; @@ -3029,7 +3023,6 @@ test "@intCast vector of signed integer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; var x: @Vector(4, i32) = .{ 1, 2, 3, 4 }; @@ -3077,7 +3070,6 @@ test "peer type resolution: slice of sentinel-terminated array" { } test "@intFromFloat boundary cases" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -3109,7 +3101,6 @@ test "@intFromFloat boundary cases" { } test "@intFromFloat vector boundary cases" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 19a053e2c9192c63fd13929a39c73e1b9085f0bb..ca253a102ff5351d730e5ad6f004755e0c225c5f 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1221,7 +1221,6 @@ test "bit field access with enum fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO var data = bit_field_1; @@ -1406,7 +1405,6 @@ test "matching captures causes enum equivalence" { test "large enum field values" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; { const E = enum(u64) { min = std.math.minInt(u64), max = std.math.maxInt(u64) }; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 63014707d9b72088668422fc2680699420aa10d7..ab8d8ddf1d70d7916304ec513faa3a0a84a7d003 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -785,7 +785,6 @@ const NoReturn = struct { test "error union of noreturn used with if" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; @@ -799,7 +798,6 @@ test "error union of noreturn used with if" { test "error union of noreturn used with try" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; @@ -810,7 +808,6 @@ test "error union of noreturn used with try" { test "error union of noreturn used with catch" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; @@ -1070,7 +1067,6 @@ test "result location initialization of error union with OPV payload" { test "return error union with i65" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(try add(1000, 234) == 1234); } diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 95dbcd393d69aefc7a893d0b35a19fa0b48b18e9..7694b8a2966a24478423d03eea26bcbb525e8fa3 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -559,7 +559,6 @@ fn StructCapture(comptime T: type) type { test "call generic function that uses capture from function declaration's scope" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = StructCapture(f64); const s = S.foo(123); diff --git a/test/behavior/inline_switch.zig b/test/behavior/inline_switch.zig index 405ea5a9c6fd9e446d1b2c8526154ff83276bc96..25582f790edc7ae6ce8655b64aa0808eb5e8e3f1 100644 --- a/test/behavior/inline_switch.zig +++ b/test/behavior/inline_switch.zig @@ -46,7 +46,6 @@ const U = union(E) { a: void, b: u2, c: u3, d: u4 }; test "inline switch unions" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var x: U = .a; _ = &x; switch (x) { @@ -93,7 +92,6 @@ test "inline else error" { test "inline else enum" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; var a: E2 = .a; @@ -106,7 +104,6 @@ test "inline else enum" { test "inline else int with gaps" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO var a: u8 = 0; _ = &a; @@ -124,7 +121,6 @@ test "inline else int with gaps" { test "inline else int all values" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var a: u2 = 0; _ = &a; @@ -140,8 +136,6 @@ test "inline else int all values" { } test "inline switch capture is set when switch operand is comptime known" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const U2 = union(enum) { a: u32, }; diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 1a8cae41eb87e2dd4b2ff551839365d221c65f89..705aae28dbcfe45cadf9421b4ae6268b0f6599a9 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1744,7 +1744,6 @@ fn testAbs(comptime T: type, a: T, expected: anytype) !void { test "@abs > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testAbs(u140, 0, 0); try testAbs(u140, 1 << 139, 1 << 139); @@ -1877,8 +1876,6 @@ test "@divTrunc > 128 bits" { } test "overflow arithmetic with u0 values" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - { var a: u0 = 0; _ = &a; diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 4dc461a146033030f621dfc127b3ded9279bdfd4..086a325bd6246dd660641aec924c20339494f8a2 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -124,7 +124,6 @@ test "vector f32" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try comptime vector32(); try vector32(); @@ -148,7 +147,6 @@ test "vector f64" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try comptime vector64(); try vector64(); diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 9e2789618a07a1c484a23c7800c71cf725395957..4d54d96ad9bb702e85228464f02664aa3187824d 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -520,7 +520,6 @@ test "alignment of wrapping an optional payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { diff --git a/test/behavior/overlapping_assign.zig b/test/behavior/overlapping_assign.zig index 7fcdb99aa8cfba0fc342e9ad7c17bc2a7b9eee49..74425a8fab1c7c2799b91e8b2d1e98a893a72885 100644 --- a/test/behavior/overlapping_assign.zig +++ b/test/behavior/overlapping_assign.zig @@ -1,7 +1,10 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; test "assignment to overlapping memory" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + try theTest(); try comptime theTest(); } diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index b3643da988edb019e7ed87af057ae51d189b7742..f1efaa9f43686a0d3570c7e33c335a0f1e6c84e3 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -852,8 +852,6 @@ test "slice len modification at comptime" { } test "slice field ptr const" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const const_slice: []const u8 = "string"; const const_ptr_const_slice = &const_slice; @@ -867,7 +865,6 @@ test "slice field ptr const" { test "slice field ptr var" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var var_slice: []const u8 = "string"; diff --git a/test/behavior/splat.zig b/test/behavior/splat.zig index 60d4c23f19b0d3621ff49601fbd04e3c690b8b7a..7ffb02017d456c7a854021251d6e567d7395ddca 100644 --- a/test/behavior/splat.zig +++ b/test/behavior/splat.zig @@ -5,7 +5,6 @@ const expect = std.testing.expect; const assert = std.debug.assert; test "@splat array" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 3384421f2a2bf08e613931b3697b5fd72078ae85..54844789a2813ff178856a08f1f65e132cc1e4e8 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -689,7 +689,6 @@ test "pointer to packed struct member in a stack variable" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO const S = packed struct { @@ -819,7 +818,6 @@ test "packed struct field passed to generic function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { const P = packed struct { @@ -1204,7 +1202,6 @@ test "packed struct field access via pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1502,8 +1499,6 @@ test "struct fields get automatically reordered" { } test "directly initiating tuple like struct" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const a = struct { u8 }{8}; try expect(a[0] == 8); } @@ -2306,7 +2301,6 @@ test "struct queries typeinfo of struct containing pointer back to first struct" } test "pointer to runtime field of struct containing struct containing comptime-only optional" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Foo = struct { padding: struct { a: u8, b: ?comptime_int }, number: u8, diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index d5b91949f8003551fbf5c462ba836736aebb81f2..555eda7f30ef354061a1c30038532641be591b7e 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -354,7 +354,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 { test "switch on union with some prongs capturing" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const X = union(enum) { a, @@ -391,7 +390,6 @@ test "switch on const enum with var" { test "anon enum literal used in switch on union enum" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Foo = union(enum) { a: i32, @@ -534,7 +532,6 @@ test "switch prongs with error set cases make a new error set type for capture v test "return result loc and then switch with range implicit casted to error union" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -615,8 +612,6 @@ test "switch prongs with cases with identical payload types" { } test "switch prong pointer capture alignment" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const U = union(enum) { a: u8 align(8), b: u8 align(4), @@ -755,7 +750,6 @@ test "switch capture copies its payload" { test "capture of integer forwards the switch condition directly" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const S = struct { fn foo(x: u8) !void { @@ -971,8 +965,6 @@ test "switch prong captures range" { } test "prong with inline call to unreachable" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const U = union(enum) { void: void, bool: bool, @@ -1018,8 +1010,6 @@ test "block error return trace index is reset between prongs" { } test "labeled switch with break" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - var six: u32 = undefined; six = 6; @@ -1047,7 +1037,6 @@ test "unlabeled break ignores switch" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const result = while (true) { _ = s: switch (@as(u32, 1)) { @@ -1079,8 +1068,6 @@ test "switch on 8-bit mod result" { } test "switch on non-exhaustive enum" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - const E = enum(u4) { a, b, @@ -1314,8 +1301,6 @@ test "single-item prong in switch on enum has comptime-known capture" { } test "single range switch prong capture" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn doTheTest(x: u8) !void { switch (x) { @@ -1575,8 +1560,6 @@ test "repeated switch analysis overrides previous analysis results" { } test "union field pointer capture preserves alignment in inline prong" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const U = union(enum) { a: u32, b: u32, diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index c86c297fa42836456f1b7f64002dffc6aa96313d..40fd66fb74f07100634e5f78bf53841af45ec6b9 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -179,7 +179,6 @@ test "switch loop with pointer capture" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const S = struct { const U = union(enum) { diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 8a8846c2ac196f8e76ca0bead377f2ecd520092a..1d6ec8a6e43e70e2472777143cec18e586c3397f 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -255,7 +255,6 @@ test "coerce tuple to tuple" { test "tuple type with void field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const T = @Tuple(&.{void}); const x = T{{}}; @@ -280,7 +279,6 @@ test "zero sized struct in tuple handled correctly" { test "tuple type with void field and a runtime field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const T = @Tuple(&.{ usize, void }); var t: T = .{ 5, {} }; @@ -291,7 +289,6 @@ test "tuple type with void field and a runtime field" { test "branching inside tuple literal" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn foo(a: anytype) !void { @@ -371,7 +368,6 @@ test "sentinel slice in tuple" { test "tuple pointer is indexable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { u32, bool }; @@ -552,8 +548,6 @@ test "OPV tuple fields aren't comptime" { } test "array of tuples that end with a zero-bit field followed by padding" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { var foo: [2]struct { u32, u8, void } = .{ .{ 1, 2, {} }, .{ 3, 4, {} } }; }; diff --git a/test/behavior/union.zig b/test/behavior/union.zig index be8ae37a4eb5e9287f4392b62d35e73a5f5f1777..6922774d4ee31976b2f7c9d8a28f00b30bab784d 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -31,7 +31,6 @@ test "init union with runtime value - floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var foo: FooWithFloats = undefined; @@ -445,7 +444,6 @@ var glbl: Foo1 = undefined; test "global union with single field is correctly initialized" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; glbl = Foo1{ .f = @typeInfo(Foo1).@"union".field_types[0]{ .x = 123 }, @@ -488,7 +486,6 @@ test "update the tag value for zero-sized unions" { test "union initializer generates padding only if needed" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const U = union(enum) { A: u24, @@ -659,7 +656,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { test "switch on union with only 1 field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var r: PartialInst = undefined; r = PartialInst.Compiled; @@ -773,7 +769,6 @@ test "return union init with void payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -925,7 +920,6 @@ test "function call result coerces from tagged union to the tag" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { const Arch = union(enum) { @@ -1142,7 +1136,6 @@ test "union tag is set when initiated as a temporary value at runtime" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const U = union(enum) { a, @@ -1392,7 +1385,6 @@ test "no dependency loop when function pointer in union returns the union" { test "union reassignment can use previous value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const U = union { a: u32, @@ -1550,7 +1542,6 @@ test "packed union field pointer has correct alignment" { test "union with 128 bit integer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const ValueTag = enum { int, other }; @@ -2040,7 +2031,6 @@ test "pass nested union with rls" { test "runtime union init, most-aligned field != largest" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest; @@ -2202,7 +2192,6 @@ test "matching captures causes union equivalence" { test "signed enum tag with negative value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Enum = enum(i8) { @@ -2278,8 +2267,6 @@ test "assign global tagged union" { } test "set mutable union by switching on same union" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const U = union(enum) { foo, bar: usize, diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index c19155c864124180b6baadcb2aaa9b7b6d7a4dfe..06d5677fe7e392c5c8c12b50a17adcd30950c675 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -395,7 +395,6 @@ test "load vector elements via comptime index" { } test "store vector elements via comptime index" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -577,7 +576,6 @@ test "vector division operators" { test "vector bitwise not operator" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -610,7 +608,6 @@ test "vector bitwise not operator" { test "vector boolean not operator" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1090,7 +1087,6 @@ test "multiplication-assignment operator with an array operand" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { diff --git a/test/cases/compile_errors/loading_spirv_runtime_array_value.zig b/test/cases/compile_errors/loading_spirv_runtime_array_value.zig new file mode 100644 index 0000000000000000000000000000000000000000..b3473fa406eb8883f7fbf372c22e075386b10f71 --- /dev/null +++ b/test/cases/compile_errors/loading_spirv_runtime_array_value.zig @@ -0,0 +1,23 @@ +const RuntimeArray = @SpirvType(.{ .runtime_array = f32 }); +const Buffer = extern struct { + data: RuntimeArray, +}; +const buf = @extern(*addrspace(.storage_buffer) Buffer, .{ + .name = "buf", + .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, +}); +export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void { + const a = buf.data; + _ = a; +} +export fn main2() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void { + const p: *addrspace(.storage_buffer) const RuntimeArray = &buf.data; + _ = p.*; +} + +// error +// backend=selfhosted +// target=spirv32-vulkan +// +// :10:15: error: cannot load SPIR-V runtime array value +// :15:12: error: cannot load SPIR-V runtime array value diff --git a/test/cases/compile_errors/spirv_runtime_array_as_value_type.zig b/test/cases/compile_errors/spirv_runtime_array_as_value_type.zig new file mode 100644 index 0000000000000000000000000000000000000000..634837d3cf86d1b8b9ed8d3288d4ee1f099ebe20 --- /dev/null +++ b/test/cases/compile_errors/spirv_runtime_array_as_value_type.zig @@ -0,0 +1,26 @@ +const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); + +const a = @extern(*addrspace(.storage_buffer) RuntimeArray, .{ + .name = "a", + .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, +}); +const b = @extern(*addrspace(.uniform) const RuntimeArray, .{ + .name = "b", + .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } }, +}); + +comptime { + _ = a; + _ = b; +} + +// error +// backend=selfhosted +// target=spirv32-vulkan +// +// :3:19: error: extern symbol cannot have type '*addrspace(.storage_buffer) @SpirvType(.runtime_array, u32)' +// :3:19: note: pointer element type '@SpirvType(.runtime_array, u32)' is not extern compatible +// :3:19: note: SPIR-V runtime arrays must be the last field of an extern struct +// :7:19: error: extern symbol cannot have type '*addrspace(.uniform) const @SpirvType(.runtime_array, u32)' +// :7:19: note: pointer element type '@SpirvType(.runtime_array, u32)' is not extern compatible +// :7:19: note: SPIR-V runtime arrays must be the last field of an extern struct