| author | |
| committer | |
| log | 292e6b99017dcbcc67e12b1eaf83217f9efce42a |
| tree | 3789906afc86c20861369a74ad7a97f6ff40f7a7 |
| parent | 245d477879b3b1646ef42c53317e94464325ccaa |
| signature | Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM |
I'm writing a small numeric library whose kernels run on the CPU, on CUDA and on Vulkan through the self-hosted SPIR-V backend, and I was making them generic over the float type. `f64` needs its own `exp` and `log` on the GPU, so I wrote them as polynomial series, and the `f64` Vulkan module stopped validating. This fixes the three backend bugs underneath that, and a crash I ran into after merging master.
The series take floats apart with `@bitCast` on vectors. Between vectors of the same length this reaches the Vulkan/OpenGL fallback in `bitCast`, which stores the source into a function variable of the destination type:
```zig
export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
var x: @Vector(2, f32) = .{ 1, 2 };
_ = &x;
const bits: @Vector(2, i32) = @bitCast(x);
_ = bits;
}
```
```
$ zig build-exe -fno-llvm -target spirv64-vulkan -mcpu vulkan_v1_2 bitcast.zig -femit-bin=bitcast.spv
$ spirv-val --target-env vulkan1.2 bitcast.spv
error: line 45: OpStore Pointer <id> '36[%36]'s type does not match Object <id> '29[%29]'s type.
```
An elementwise vector bitcast is now a scalar `bitCast` per lane, the way `buildConvert` and friends already unroll vectors. Going through the scalar path also normalizes lanes of strange integers: a single `OpBitcast` on the whole vector validates for `@Vector(n, u3)` to `@Vector(n, i3)`, but leaves lanes that don't compare equal to the negative values they should hold.
The series also convert between integer and float lanes. A vector of one lane, or of more than four without `vector16`, is an array in SPIR-V, and `airFloatFromInt` and `airIntFromFloat` emitted a single `OpConvert*` with that array as its result type:
```zig
export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
var x: @Vector(1, i32) = .{1};
_ = &x;
const y: @Vector(1, f32) = @floatFromInt(x);
_ = y;
}
```
```
$ spirv-val --target-env vulkan1.2 convert.spv
error: line 40: Expected float scalar or vector type as Result Type: ConvertSToF
%y = OpConvertSToF %_arr_f32_u32_1 %26
```
`@floatCast` and `@intCast` already go through `buildConvert`, which unrolls the vector; these two now do as well, with `buildConvert` picking the int/float conversion opcodes.
The coefficients sit in a comptime array that the series take as a comptime slice, and that alone fails to compile, although nothing reads the slice at runtime:
```zig
const weights = [_]f32{ 1, 2, 3 };
inline fn first(comptime w: []const f32) f32 {
return w[0];
}
export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
var x: f32 = first(&weights);
_ = &x;
}
```
```
$ zig build-exe -fno-llvm -target spirv64-vulkan -mcpu vulkan_v1_2 dbgvar.zig -femit-bin=dbgvar.spv
dbgvar.zig:7:8: error: TODO (SPIR-V): pointer to constant 'dbgvar.weights'
```
It appears `airDbgVar` lowers the operand only to attach an `OpName` to it, and a pointer to a non-extern constant is still a TODO. A comptime-known value has no runtime variable of its own to name, so `airDbgVar` now leaves interned operands alone. The same thing held back 58 of the behavior tests skipped on SPIR-V, and the test commit un-skips them.
After merging master, four of those tests crashed the compiler in `structFieldPtr`, which has `unreachable` for packed containers since ebb8683ef1 ([#36996](https://codeberg.org/ziglang/zig/pulls/36996)):
```zig
const Flags = packed struct { a: bool, b: bool };
export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
var flags: Flags = .{ .a = true, .b = false };
const b = &flags.b;
b.* = true;
}
```
```
thread 3961624 panic: reached unreachable code
src/codegen/spirv/CodeGen.zig:6906:27: 0x4767157 in structFieldPtr (main.zig)
.@"packed" => unreachable,
```
My reading is that the `unreachable` holds for the pointer derivations it was written for, since `constantPtr` now turns packed pointers into pointers to their host integer first, but `airStructFieldPtr` and `airStructFieldPtrIndex` still pass packed structs through. A pointer to a packed field is a bit-pointer into the struct's own host integer, so it is the struct pointer: that is what the old code computed, and what the C backend now does with `.begin`. Packed unions get back the TODO error they had before. I may be missing a plan for packed field pointers here, and I'm happy to change it if so. The commit also un-skips three packed tests that crash on master the same way. I suppose nothing caught this because those tests are skipped on SPIR-V and the `spirv64-vulkan` behavior target is commented out in `test/tests.zig`.
I ran the behavior tests through `tools/unskip_spirv_tests.zig` and [zig-spirv-test-executor](https://github.com/Snektron/zig-spirv-test-executor) on a Radeon 680M, and the new and un-skipped tests on an RTX 4060 as well. Every fix has tests that fail on master and pass with it; the vector ones compare lane by lane, since `expectEqual` on vectors doesn't compile for SPIR-V yet. Running each behavior file whole, nothing that passes on master fails. Five more skips already pass on master without these changes, so I left them out, but I can add them. The new vector tests copy the aarch64, arm, sparc64 and riscv64 skips of the tests around them, which I couldn't check.
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37040
Reviewed-by: Ali Cheraghi <alichraghi@noreply.codeberg.org>20 files changed, 119 insertions(+), 137 deletions(-)
src/codegen/spirv/CodeGen.zig+40-43| ... | @@ -3423,8 +3423,8 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization { | ... | @@ -3423,8 +3423,8 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization { |
| 3423 | return v; | 3423 | return v; |
| 3424 | } | 3424 | } |
| 3425 | 3425 | ||
| 3426 | /// This function builds an OpSConvert of OpUConvert depending on the | 3426 | /// This function builds the conversion between two numeric types: OpFConvert, OpSConvert or |
| 3427 | /// signedness of the types. | 3427 | /// OpUConvert within floats or integers, and OpConvert{S,U}ToF or OpConvertFTo{S,U} across them. |
| 3428 | fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { | 3428 | fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { |
| 3429 | const zcu = cg.zcu; | 3429 | const zcu = cg.zcu; |
| 3430 | 3430 | ||
| ... | @@ -3453,8 +3453,16 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { | ... | @@ -3453,8 +3453,16 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { |
| 3453 | const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); | 3453 | const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); |
| 3454 | 3454 | ||
| 3455 | const opcode: Opcode = blk: { | 3455 | const opcode: Opcode = blk: { |
| 3456 | if (dst_ty.scalarType(zcu).isAnyFloat()) break :blk .OpFConvert; | 3456 | if (dst_scalar.isAnyFloat()) { |
| 3457 | if (dst_ty.scalarType(zcu).isSignedInt(zcu)) break :blk .OpSConvert; | 3457 | if (src_scalar.isAnyFloat()) break :blk .OpFConvert; |
| 3458 | if (src_scalar.isSignedInt(zcu)) break :blk .OpConvertSToF; | ||
| 3459 | break :blk .OpConvertUToF; | ||
| 3460 | } | ||
| 3461 | if (src_scalar.isAnyFloat()) { | ||
| 3462 | if (dst_scalar.isSignedInt(zcu)) break :blk .OpConvertFToS; | ||
| 3463 | break :blk .OpConvertFToU; | ||
| 3464 | } | ||
| 3465 | if (dst_scalar.isSignedInt(zcu)) break :blk .OpSConvert; | ||
| 3458 | break :blk .OpUConvert; | 3466 | break :blk .OpUConvert; |
| 3459 | }; | 3467 | }; |
| 3460 | 3468 | ||
| ... | @@ -5801,6 +5809,23 @@ fn bitCast( | ... | @@ -5801,6 +5809,23 @@ fn bitCast( |
| 5801 | // TODO: Some more cases are missing here | 5809 | // TODO: Some more cases are missing here |
| 5802 | // See fn bitCast in llvm.zig | 5810 | // See fn bitCast in llvm.zig |
| 5803 | 5811 | ||
| 5812 | // An elementwise vector bitcast is a scalar bitcast per lane, which also normalizes lanes | ||
| 5813 | // of strange integers. | ||
| 5814 | if (src_ty.isVector(zcu) and dst_ty.isVector(zcu) and | ||
| 5815 | src_ty.vectorLen(zcu) == dst_ty.vectorLen(zcu) and | ||
| 5816 | src_ty.childType(zcu).isNumeric(zcu) and dst_ty.childType(zcu).isNumeric(zcu)) | ||
| 5817 | { | ||
| 5818 | const src_elem_ty = src_ty.childType(zcu); | ||
| 5819 | const dst_elem_ty = dst_ty.childType(zcu); | ||
| 5820 | const scratch_top = cg.id_scratch.items.len; | ||
| 5821 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); | ||
| 5822 | for (0..src_ty.vectorLen(zcu)) |i| { | ||
| 5823 | const src_lane_id = try cg.extractVectorComponent(src_elem_ty, src_id, @intCast(i)); | ||
| 5824 | try cg.id_scratch.append(gpa, try cg.bitCast(dst_elem_ty, src_elem_ty, src_lane_id)); | ||
| 5825 | } | ||
| 5826 | break :blk try cg.constructComposite(dst_ty_id, cg.id_scratch.items[scratch_top..]); | ||
| 5827 | } | ||
| 5828 | |||
| 5804 | if (src_ty.zigTypeTag(zcu) == .int and dst_ty.isPtrAtRuntime(zcu)) { | 5829 | if (src_ty.zigTypeTag(zcu) == .int and dst_ty.isPtrAtRuntime(zcu)) { |
| 5805 | if (target.os.tag != .opencl) { | 5830 | if (target.os.tag != .opencl) { |
| 5806 | if (dst_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) { | 5831 | if (dst_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) { |
| ... | @@ -6139,50 +6164,19 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id { | ... | @@ -6139,50 +6164,19 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id { |
| 6139 | } | 6164 | } |
| 6140 | 6165 | ||
| 6141 | fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | 6166 | fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6142 | const gpa = cg.gpa; | ||
| 6143 | const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; | 6167 | const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; |
| 6144 | const operand_ty = cg.typeOf(ty_op.operand); | 6168 | const operand = try cg.temporary(ty_op.operand); |
| 6145 | const operand_id = try cg.resolve(ty_op.operand); | ||
| 6146 | const result_ty = cg.typeOfIndex(inst); | 6169 | const result_ty = cg.typeOfIndex(inst); |
| 6147 | const operand_info = cg.arithmeticTypeInfo(operand_ty); | 6170 | const result = try cg.buildConvert(result_ty, operand); |
| 6148 | const result_id = cg.allocId(); | 6171 | return try result.materialize(cg); |
| 6149 | const result_ty_id = try cg.resolveType(result_ty, .direct); | ||
| 6150 | switch (operand_info.signedness) { | ||
| 6151 | .signed => try cg.body.emit(gpa, .OpConvertSToF, .{ | ||
| 6152 | .id_result_type = result_ty_id, | ||
| 6153 | .id_result = result_id, | ||
| 6154 | .signed_value = operand_id, | ||
| 6155 | }), | ||
| 6156 | .unsigned => try cg.body.emit(gpa, .OpConvertUToF, .{ | ||
| 6157 | .id_result_type = result_ty_id, | ||
| 6158 | .id_result = result_id, | ||
| 6159 | .unsigned_value = operand_id, | ||
| 6160 | }), | ||
| 6161 | } | ||
| 6162 | return result_id; | ||
| 6163 | } | 6172 | } |
| 6164 | 6173 | ||
| 6165 | fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | 6174 | fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6166 | const gpa = cg.gpa; | ||
| 6167 | const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; | 6175 | const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; |
| 6168 | const operand_id = try cg.resolve(ty_op.operand); | 6176 | const operand = try cg.temporary(ty_op.operand); |
| 6169 | const result_ty = cg.typeOfIndex(inst); | 6177 | const result_ty = cg.typeOfIndex(inst); |
| 6170 | const result_info = cg.arithmeticTypeInfo(result_ty); | 6178 | const result = try cg.buildConvert(result_ty, operand); |
| 6171 | const result_ty_id = try cg.resolveType(result_ty, .direct); | 6179 | return try result.materialize(cg); |
| 6172 | const result_id = cg.allocId(); | ||
| 6173 | switch (result_info.signedness) { | ||
| 6174 | .signed => try cg.body.emit(gpa, .OpConvertFToS, .{ | ||
| 6175 | .id_result_type = result_ty_id, | ||
| 6176 | .id_result = result_id, | ||
| 6177 | .float_value = operand_id, | ||
| 6178 | }), | ||
| 6179 | .unsigned => try cg.body.emit(gpa, .OpConvertFToU, .{ | ||
| 6180 | .id_result_type = result_ty_id, | ||
| 6181 | .id_result = result_id, | ||
| 6182 | .float_value = operand_id, | ||
| 6183 | }), | ||
| 6184 | } | ||
| 6185 | return result_id; | ||
| 6186 | } | 6180 | } |
| 6187 | 6181 | ||
| 6188 | fn airFloatCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | 6182 | fn airFloatCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| ... | @@ -6903,14 +6897,14 @@ fn structFieldPtr( | ... | @@ -6903,14 +6897,14 @@ fn structFieldPtr( |
| 6903 | return cg.accessChain(result_ptr_ty_id, object_ptr, &.{field_index}); | 6897 | return cg.accessChain(result_ptr_ty_id, object_ptr, &.{field_index}); |
| 6904 | }, | 6898 | }, |
| 6905 | .@"struct" => switch (object_ty.containerLayout(zcu)) { | 6899 | .@"struct" => switch (object_ty.containerLayout(zcu)) { |
| 6906 | .@"packed" => unreachable, | 6900 | .@"packed" => return cg.todo("implement field access for packed structs", .{}), |
| 6907 | .auto, .@"extern" => { | 6901 | .auto, .@"extern" => { |
| 6908 | const member_index = cg.memberIndex(object_ty, field_index); | 6902 | const member_index = cg.memberIndex(object_ty, field_index); |
| 6909 | return try cg.accessChain(result_ptr_ty_id, object_ptr, &.{member_index}); | 6903 | return try cg.accessChain(result_ptr_ty_id, object_ptr, &.{member_index}); |
| 6910 | }, | 6904 | }, |
| 6911 | }, | 6905 | }, |
| 6912 | .@"union" => switch (object_ty.containerLayout(zcu)) { | 6906 | .@"union" => switch (object_ty.containerLayout(zcu)) { |
| 6913 | .@"packed" => unreachable, | 6907 | .@"packed" => return cg.todo("implement field access for packed unions", .{}), |
| 6914 | .auto => { | 6908 | .auto => { |
| 6915 | if (!field_ty.hasRuntimeBits(zcu)) return try cg.constUndef(result_ptr_ty_id); | 6909 | if (!field_ty.hasRuntimeBits(zcu)) return try cg.constUndef(result_ptr_ty_id); |
| 6916 | return try cg.accessChain(result_ptr_ty_id, object_ptr, &.{field_index}); | 6910 | return try cg.accessChain(result_ptr_ty_id, object_ptr, &.{field_index}); |
| ... | @@ -8483,6 +8477,9 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -8483,6 +8477,9 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 8483 | 8477 | ||
| 8484 | fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void { | 8478 | fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 8485 | const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op; | 8479 | const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op; |
| 8480 | // A comptime-known value has no runtime variable of its own to name, and lowering it only to | ||
| 8481 | // name it can fail, as for a slice of a global constant. | ||
| 8482 | if (pl_op.operand.toInterned() != null) return; | ||
| 8486 | const target_id = switch (try cg.resolvePtr(pl_op.operand)) { | 8483 | const target_id = switch (try cg.resolvePtr(pl_op.operand)) { |
| 8487 | .tracked => return, | 8484 | .tracked => return, |
| 8488 | .id => |id| id, | 8485 | .id => |id| id, |
test/behavior/align.zig-2| ... | @@ -639,8 +639,6 @@ test "function pointer @intFromPtr/@ptrFromInt roundtrip" { | ... | @@ -639,8 +639,6 @@ test "function pointer @intFromPtr/@ptrFromInt roundtrip" { |
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | test "function pointer align mask" { | 641 | test "function pointer align mask" { |
| 642 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 643 | |||
| 644 | const int = if (builtin.cpu.arch.isArm() or builtin.cpu.arch.isMIPS()) 0x20202021 else 0x20202020; | 642 | const int = if (builtin.cpu.arch.isArm() or builtin.cpu.arch.isMIPS()) 0x20202021 else 0x20202020; |
| 645 | const unaligned: *const fn () callconv(.c) void = @ptrFromInt(int); | 643 | const unaligned: *const fn () callconv(.c) void = @ptrFromInt(int); |
| 646 | const aligned: *align(16) const fn () callconv(.c) void = @alignCast(unaligned); | 644 | const aligned: *align(16) const fn () callconv(.c) void = @alignCast(unaligned); |
test/behavior/array.zig-8| ... | @@ -836,8 +836,6 @@ test "pointer to sentinel-terminated array initialized through reference to anon | ... | @@ -836,8 +836,6 @@ test "pointer to sentinel-terminated array initialized through reference to anon |
| 836 | } | 836 | } |
| 837 | 837 | ||
| 838 | test "tuple initialized through reference to anonymous array init provides result types" { | 838 | test "tuple initialized through reference to anonymous array init provides result types" { |
| 839 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 840 | |||
| 841 | const Tuple = struct { u64, *const u32 }; | 839 | const Tuple = struct { u64, *const u32 }; |
| 842 | const foo: *const Tuple = &.{ | 840 | const foo: *const Tuple = &.{ |
| 843 | @intCast(12345), | 841 | @intCast(12345), |
| ... | @@ -978,15 +976,11 @@ test "runtime index of array of zero-bit values" { | ... | @@ -978,15 +976,11 @@ test "runtime index of array of zero-bit values" { |
| 978 | } | 976 | } |
| 979 | 977 | ||
| 980 | test "initialize slice with reference to empty array initializer" { | 978 | test "initialize slice with reference to empty array initializer" { |
| 981 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 982 | |||
| 983 | const a: []const u8 = &.{}; | 979 | const a: []const u8 = &.{}; |
| 984 | comptime assert(a.len == 0); | 980 | comptime assert(a.len == 0); |
| 985 | } | 981 | } |
| 986 | 982 | ||
| 987 | test "initialize many-pointer with reference to empty array initializer" { | 983 | test "initialize many-pointer with reference to empty array initializer" { |
| 988 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 989 | |||
| 990 | const a: [*]const u8 = &.{}; | 984 | const a: [*]const u8 = &.{}; |
| 991 | _ = a; // nothing meaningful to test; points to zero bits | 985 | _ = a; // nothing meaningful to test; points to zero bits |
| 992 | } | 986 | } |
| ... | @@ -1012,8 +1006,6 @@ test "pass pointer to empty array initializer to anytype parameter" { | ... | @@ -1012,8 +1006,6 @@ test "pass pointer to empty array initializer to anytype parameter" { |
| 1012 | } | 1006 | } |
| 1013 | 1007 | ||
| 1014 | test "initialize pointer to anyopaque with reference to empty array initializer" { | 1008 | test "initialize pointer to anyopaque with reference to empty array initializer" { |
| 1015 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1016 | |||
| 1017 | const ptr: *const anyopaque = &.{}; | 1009 | const ptr: *const anyopaque = &.{}; |
| 1018 | // The above acts like an untyped initializer, since the `.{}` has no result type. | 1010 | // The above acts like an untyped initializer, since the `.{}` has no result type. |
| 1019 | // So, `ptr` points in memory to an empty tuple (`@TypeOf(.{})`). | 1011 | // So, `ptr` points in memory to an empty tuple (`@TypeOf(.{})`). |
test/behavior/basic.zig-8| ... | @@ -297,7 +297,6 @@ const global_a: i32 = 1234; | ... | @@ -297,7 +297,6 @@ const global_a: i32 = 1234; |
| 297 | const global_b: *const i32 = &global_a; | 297 | const global_b: *const i32 = &global_a; |
| 298 | const global_c: *const f32 = @as(*const f32, @ptrCast(global_b)); | 298 | const global_c: *const f32 = @as(*const f32, @ptrCast(global_b)); |
| 299 | test "compile time global reinterpret" { | 299 | test "compile time global reinterpret" { |
| 300 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 301 | const d = @as(*const i32, @ptrCast(global_c)); | 300 | const d = @as(*const i32, @ptrCast(global_c)); |
| 302 | try expect(d.* == 1234); | 301 | try expect(d.* == 1234); |
| 303 | } | 302 | } |
| ... | @@ -637,7 +636,6 @@ fn emptyFn() void {} | ... | @@ -637,7 +636,6 @@ fn emptyFn() void {} |
| 637 | 636 | ||
| 638 | const addr1 = @as(*const u8, @ptrCast(&emptyFn)); | 637 | const addr1 = @as(*const u8, @ptrCast(&emptyFn)); |
| 639 | test "comptime cast fn to ptr" { | 638 | test "comptime cast fn to ptr" { |
| 640 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 641 | const addr2 = @as(*const u8, @ptrCast(&emptyFn)); | 639 | const addr2 = @as(*const u8, @ptrCast(&emptyFn)); |
| 642 | comptime assert(addr1 == addr2); | 640 | comptime assert(addr1 == addr2); |
| 643 | } | 641 | } |
| ... | @@ -915,7 +913,6 @@ test "labeled block with runtime branch forwards its result location type to bre | ... | @@ -915,7 +913,6 @@ test "labeled block with runtime branch forwards its result location type to bre |
| 915 | 913 | ||
| 916 | test "try in labeled block doesn't cast to wrong type" { | 914 | test "try in labeled block doesn't cast to wrong type" { |
| 917 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 915 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 918 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 919 | 916 | ||
| 920 | const S = struct { | 917 | const S = struct { |
| 921 | a: u32, | 918 | a: u32, |
| ... | @@ -1001,8 +998,6 @@ test "generic function uses return type of other generic function" { | ... | @@ -1001,8 +998,6 @@ test "generic function uses return type of other generic function" { |
| 1001 | } | 998 | } |
| 1002 | 999 | ||
| 1003 | test "const alloc with comptime-known initializer is made comptime-known" { | 1000 | test "const alloc with comptime-known initializer is made comptime-known" { |
| 1004 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1005 | |||
| 1006 | const S = struct { | 1001 | const S = struct { |
| 1007 | a: bool, | 1002 | a: bool, |
| 1008 | b: [2]u8, | 1003 | b: [2]u8, |
| ... | @@ -1276,7 +1271,6 @@ test "@Int returned from block" { | ... | @@ -1276,7 +1271,6 @@ test "@Int returned from block" { |
| 1276 | } | 1271 | } |
| 1277 | 1272 | ||
| 1278 | test "comptime variable initialized with addresses of literals" { | 1273 | test "comptime variable initialized with addresses of literals" { |
| 1279 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1280 | comptime var st = .{ | 1274 | comptime var st = .{ |
| 1281 | .foo = &1, | 1275 | .foo = &1, |
| 1282 | .bar = &2, | 1276 | .bar = &2, |
| ... | @@ -1326,8 +1320,6 @@ test "proper value is returned from labeled block" { | ... | @@ -1326,8 +1320,6 @@ test "proper value is returned from labeled block" { |
| 1326 | } | 1320 | } |
| 1327 | 1321 | ||
| 1328 | test "const inferred array of slices" { | 1322 | test "const inferred array of slices" { |
| 1329 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1330 | |||
| 1331 | const T = struct { v: bool }; | 1323 | const T = struct { v: bool }; |
| 1332 | 1324 | ||
| 1333 | const decls = [_][]const T{ | 1325 | const decls = [_][]const T{ |
test/behavior/bitcast.zig+30| ... | @@ -311,6 +311,36 @@ test "bitcast vector to integer and back" { | ... | @@ -311,6 +311,36 @@ test "bitcast vector to integer and back" { |
| 311 | try expect(int_again == 0b1111_1111_1111_1101); | 311 | try expect(int_again == 0b1111_1111_1111_1101); |
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | test "bitcast vector elementwise" { | ||
| 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 316 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 317 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 318 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 319 | |||
| 320 | const S = struct { | ||
| 321 | fn doTheTest(comptime len: comptime_int) !void { | ||
| 322 | var floats: @Vector(len, f32) = std.simd.iota(f32, len) + @as(@Vector(len, f32), @splat(0.5)); | ||
| 323 | _ = &floats; | ||
| 324 | const bits: @Vector(len, i32) = @bitCast(floats); | ||
| 325 | inline for (0..len) |i| try expect(bits[i] == @as(i32, @bitCast(@as(f32, @floatFromInt(i)) + 0.5))); | ||
| 326 | const floats_again: @Vector(len, f32) = @bitCast(bits); | ||
| 327 | inline for (0..len) |i| try expect(floats_again[i] == @as(f32, @floatFromInt(i)) + 0.5); | ||
| 328 | |||
| 329 | var unsigned: @Vector(len, u3) = std.simd.iota(u3, len); | ||
| 330 | _ = &unsigned; | ||
| 331 | const signed: @Vector(len, i3) = @bitCast(unsigned); | ||
| 332 | inline for (0..len) |i| try expect(signed[i] == @as(i3, @bitCast(@as(u3, i)))); | ||
| 333 | const unsigned_again: @Vector(len, u3) = @bitCast(signed); | ||
| 334 | inline for (0..len) |i| try expect(unsigned_again[i] == i); | ||
| 335 | } | ||
| 336 | }; | ||
| 337 | |||
| 338 | inline for (.{ 1, 2, 3, 4, 8 }) |len| { | ||
| 339 | try S.doTheTest(len); | ||
| 340 | try comptime S.doTheTest(len); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 314 | fn bitCastWrapper16(x: f16) u16 { | 344 | fn bitCastWrapper16(x: f16) u16 { |
| 315 | return @as(u16, @bitCast(x)); | 345 | return @as(u16, @bitCast(x)); |
| 316 | } | 346 | } |
test/behavior/cast.zig+30-13| ... | @@ -9,8 +9,6 @@ const maxInt = std.math.maxInt; | ... | @@ -9,8 +9,6 @@ const maxInt = std.math.maxInt; |
| 9 | const native_endian = builtin.target.cpu.arch.endian(); | 9 | const native_endian = builtin.target.cpu.arch.endian(); |
| 10 | 10 | ||
| 11 | test "int to ptr cast" { | 11 | test "int to ptr cast" { |
| 12 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 13 | |||
| 14 | const x = @as(usize, 13); | 12 | const x = @as(usize, 13); |
| 15 | const y = @as(*u8, @ptrFromInt(x)); | 13 | const y = @as(*u8, @ptrFromInt(x)); |
| 16 | const z = @intFromPtr(y); | 14 | const z = @intFromPtr(y); |
| ... | @@ -18,8 +16,6 @@ test "int to ptr cast" { | ... | @@ -18,8 +16,6 @@ test "int to ptr cast" { |
| 18 | } | 16 | } |
| 19 | 17 | ||
| 20 | test "integer literal to pointer cast" { | 18 | test "integer literal to pointer cast" { |
| 21 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 22 | |||
| 23 | const vga_mem = @as(*u16, @ptrFromInt(0xB8000)); | 19 | const vga_mem = @as(*u16, @ptrFromInt(0xB8000)); |
| 24 | try expect(@intFromPtr(vga_mem) == 0xB8000); | 20 | try expect(@intFromPtr(vga_mem) == 0xB8000); |
| 25 | } | 21 | } |
| ... | @@ -71,8 +67,6 @@ test "implicit cast comptime_int to comptime_float" { | ... | @@ -71,8 +67,6 @@ test "implicit cast comptime_int to comptime_float" { |
| 71 | } | 67 | } |
| 72 | 68 | ||
| 73 | test "comptime_int @floatFromInt" { | 69 | test "comptime_int @floatFromInt" { |
| 74 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 75 | |||
| 76 | { | 70 | { |
| 77 | const result = @as(f16, @floatFromInt(1234)); | 71 | const result = @as(f16, @floatFromInt(1234)); |
| 78 | try expect(@TypeOf(result) == f16); | 72 | try expect(@TypeOf(result) == f16); |
| ... | @@ -538,8 +532,6 @@ test "return u8 coercing into ?u32 return type" { | ... | @@ -538,8 +532,6 @@ test "return u8 coercing into ?u32 return type" { |
| 538 | } | 532 | } |
| 539 | 533 | ||
| 540 | test "cast from ?[*]T to ??[*]T" { | 534 | test "cast from ?[*]T to ??[*]T" { |
| 541 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 542 | |||
| 543 | const a: ??[*]u8 = @as(?[*]u8, null); | 535 | const a: ??[*]u8 = @as(?[*]u8, null); |
| 544 | try expect(a != null and a.? == null); | 536 | try expect(a != null and a.? == null); |
| 545 | } | 537 | } |
| ... | @@ -1423,7 +1415,6 @@ test "comptime float casts" { | ... | @@ -1423,7 +1415,6 @@ test "comptime float casts" { |
| 1423 | } | 1415 | } |
| 1424 | 1416 | ||
| 1425 | test "pointer reinterpret const float to int" { | 1417 | test "pointer reinterpret const float to int" { |
| 1426 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1427 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1418 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1428 | 1419 | ||
| 1429 | // The hex representation is 0x3fe3333333333303. | 1420 | // The hex representation is 0x3fe3333333333303. |
| ... | @@ -1843,8 +1834,6 @@ test "coerce between pointers of compatible differently-named floats" { | ... | @@ -1843,8 +1834,6 @@ test "coerce between pointers of compatible differently-named floats" { |
| 1843 | } | 1834 | } |
| 1844 | 1835 | ||
| 1845 | test "peer type resolution of const and non-const pointer to array" { | 1836 | test "peer type resolution of const and non-const pointer to array" { |
| 1846 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1847 | |||
| 1848 | const a = @as(*[1024]u8, @ptrFromInt(42)); | 1837 | const a = @as(*[1024]u8, @ptrFromInt(42)); |
| 1849 | const b = @as(*const [1024]u8, @ptrFromInt(42)); | 1838 | const b = @as(*const [1024]u8, @ptrFromInt(42)); |
| 1850 | try std.testing.expect(@TypeOf(a, b) == *const [1024]u8); | 1839 | try std.testing.expect(@TypeOf(a, b) == *const [1024]u8); |
| ... | @@ -1909,8 +1898,6 @@ test "optional pointer coerced to optional allowzero pointer" { | ... | @@ -1909,8 +1898,6 @@ test "optional pointer coerced to optional allowzero pointer" { |
| 1909 | } | 1898 | } |
| 1910 | 1899 | ||
| 1911 | test "optional slice coerced to allowzero many pointer" { | 1900 | test "optional slice coerced to allowzero many pointer" { |
| 1912 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1913 | |||
| 1914 | const a: ?[]const u32 = null; | 1901 | const a: ?[]const u32 = null; |
| 1915 | const b: [*]allowzero const u8 = @ptrCast(a); | 1902 | const b: [*]allowzero const u8 = @ptrCast(a); |
| 1916 | const c = @intFromPtr(b); | 1903 | const c = @intFromPtr(b); |
| ... | @@ -2932,6 +2919,36 @@ test "@intFromFloat on vector" { | ... | @@ -2932,6 +2919,36 @@ test "@intFromFloat on vector" { |
| 2932 | try comptime S.doTheTest(); | 2919 | try comptime S.doTheTest(); |
| 2933 | } | 2920 | } |
| 2934 | 2921 | ||
| 2922 | test "@floatFromInt and @intFromFloat on vectors of any length" { | ||
| 2923 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 2924 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 2925 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 2926 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 2927 | |||
| 2928 | const S = struct { | ||
| 2929 | fn doTheTest(comptime len: comptime_int) !void { | ||
| 2930 | var signed: @Vector(len, i32) = std.simd.iota(i32, len) - @as(@Vector(len, i32), @splat(4)); | ||
| 2931 | _ = &signed; | ||
| 2932 | const from_signed: @Vector(len, f32) = @floatFromInt(signed); | ||
| 2933 | inline for (0..len) |i| try expect(from_signed[i] == @as(f32, @floatFromInt(@as(i32, i) - 4))); | ||
| 2934 | const to_signed: @Vector(len, i32) = @intFromFloat(from_signed); | ||
| 2935 | inline for (0..len) |i| try expect(to_signed[i] == @as(i32, i) - 4); | ||
| 2936 | |||
| 2937 | var unsigned: @Vector(len, u32) = std.simd.iota(u32, len) * @as(@Vector(len, u32), @splat(3)); | ||
| 2938 | _ = &unsigned; | ||
| 2939 | const from_unsigned: @Vector(len, f32) = @floatFromInt(unsigned); | ||
| 2940 | inline for (0..len) |i| try expect(from_unsigned[i] == @as(f32, @floatFromInt(i * 3))); | ||
| 2941 | const to_unsigned: @Vector(len, u32) = @intFromFloat(from_unsigned); | ||
| 2942 | inline for (0..len) |i| try expect(to_unsigned[i] == i * 3); | ||
| 2943 | } | ||
| 2944 | }; | ||
| 2945 | |||
| 2946 | inline for (.{ 1, 2, 3, 4, 8 }) |len| { | ||
| 2947 | try S.doTheTest(len); | ||
| 2948 | try comptime S.doTheTest(len); | ||
| 2949 | } | ||
| 2950 | } | ||
| 2951 | |||
| 2935 | test "@intFromBool on vector" { | 2952 | test "@intFromBool on vector" { |
| 2936 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 2953 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2937 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 2954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
test/behavior/comptime_memory.zig-10| ... | @@ -407,8 +407,6 @@ test "mutate entire slice at comptime" { | ... | @@ -407,8 +407,6 @@ test "mutate entire slice at comptime" { |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | test "dereference undefined pointer to zero-bit type" { | 409 | test "dereference undefined pointer to zero-bit type" { |
| 410 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 411 | |||
| 412 | const p0: *void = undefined; | 410 | const p0: *void = undefined; |
| 413 | try testing.expectEqual({}, p0.*); | 411 | try testing.expectEqual({}, p0.*); |
| 414 | 412 | ||
| ... | @@ -424,16 +422,12 @@ test "type pun extern struct" { | ... | @@ -424,16 +422,12 @@ test "type pun extern struct" { |
| 424 | } | 422 | } |
| 425 | 423 | ||
| 426 | test "type pun @ptrFromInt" { | 424 | test "type pun @ptrFromInt" { |
| 427 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 428 | |||
| 429 | const p: *u8 = @ptrFromInt(42); | 425 | const p: *u8 = @ptrFromInt(42); |
| 430 | // note that expectEqual hides the bug | 426 | // note that expectEqual hides the bug |
| 431 | try testing.expect(@as(*const [*]u8, @ptrCast(&p)).* == @as([*]u8, @ptrFromInt(42))); | 427 | try testing.expect(@as(*const [*]u8, @ptrCast(&p)).* == @as([*]u8, @ptrFromInt(42))); |
| 432 | } | 428 | } |
| 433 | 429 | ||
| 434 | test "type pun null pointer-like optional" { | 430 | test "type pun null pointer-like optional" { |
| 435 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 436 | |||
| 437 | const p: ?*u8 = null; | 431 | const p: ?*u8 = null; |
| 438 | // note that expectEqual hides the bug | 432 | // note that expectEqual hides the bug |
| 439 | try testing.expect(@as(*const ?*i8, @ptrCast(&p)).* == null); | 433 | try testing.expect(@as(*const ?*i8, @ptrCast(&p)).* == null); |
| ... | @@ -557,8 +551,6 @@ test "comptime store of packed struct with void field into array" { | ... | @@ -557,8 +551,6 @@ test "comptime store of packed struct with void field into array" { |
| 557 | } | 551 | } |
| 558 | 552 | ||
| 559 | test "comptime store of reinterpreted zero-bit type" { | 553 | test "comptime store of reinterpreted zero-bit type" { |
| 560 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 561 | |||
| 562 | const S = struct { | 554 | const S = struct { |
| 563 | fn doTheTest(comptime T: type) void { | 555 | fn doTheTest(comptime T: type) void { |
| 564 | comptime var buf: T = undefined; | 556 | comptime var buf: T = undefined; |
| ... | @@ -590,8 +582,6 @@ test "comptime store to extern struct reinterpreted as byte array" { | ... | @@ -590,8 +582,6 @@ test "comptime store to extern struct reinterpreted as byte array" { |
| 590 | } | 582 | } |
| 591 | 583 | ||
| 592 | test "reinterpret sentinel-terminated array as packed struct" { | 584 | test "reinterpret sentinel-terminated array as packed struct" { |
| 593 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 594 | |||
| 595 | const S = packed struct(u16) { lo: u8, hi: u8 }; | 585 | const S = packed struct(u16) { lo: u8, hi: u8 }; |
| 596 | const data: [2:0]u8 = .{ 0x12, 0x34 }; | 586 | const data: [2:0]u8 = .{ 0x12, 0x34 }; |
| 597 | const ptr: *align(1) const S = @ptrCast(&data); | 587 | const ptr: *align(1) const S = @ptrCast(&data); |
test/behavior/error.zig-2| ... | @@ -555,7 +555,6 @@ test "return result loc as peer result loc in inferred error set function" { | ... | @@ -555,7 +555,6 @@ test "return result loc as peer result loc in inferred error set function" { |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | test "error payload type is correctly resolved" { | 557 | test "error payload type is correctly resolved" { |
| 558 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 559 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 558 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 560 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 559 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 561 | 560 | ||
| ... | @@ -1108,7 +1107,6 @@ test "'if' ignores error via local while 'else' ignores error directly" { | ... | @@ -1108,7 +1107,6 @@ test "'if' ignores error via local while 'else' ignores error directly" { |
| 1108 | } | 1107 | } |
| 1109 | 1108 | ||
| 1110 | test "@errorCast into own inferred error set" { | 1109 | test "@errorCast into own inferred error set" { |
| 1111 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1112 | const static = struct { | 1110 | const static = struct { |
| 1113 | fn foo(b: bool) !void { | 1111 | fn foo(b: bool) !void { |
| 1114 | if (b) { | 1112 | if (b) { |
test/behavior/eval.zig-6| ... | @@ -876,16 +876,12 @@ test "comptime pointer load through elem_ptr" { | ... | @@ -876,16 +876,12 @@ test "comptime pointer load through elem_ptr" { |
| 876 | } | 876 | } |
| 877 | 877 | ||
| 878 | test "debug variable type resolved through indirect zero-bit types" { | 878 | test "debug variable type resolved through indirect zero-bit types" { |
| 879 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 880 | |||
| 881 | const T = struct { key: []void }; | 879 | const T = struct { key: []void }; |
| 882 | const slice: []const T = &[_]T{}; | 880 | const slice: []const T = &[_]T{}; |
| 883 | _ = slice; | 881 | _ = slice; |
| 884 | } | 882 | } |
| 885 | 883 | ||
| 886 | test "const local with comptime init through array init" { | 884 | test "const local with comptime init through array init" { |
| 887 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 888 | |||
| 889 | const E1 = enum { | 885 | const E1 = enum { |
| 890 | A, | 886 | A, |
| 891 | pub fn a() void {} | 887 | pub fn a() void {} |
| ... | @@ -1163,8 +1159,6 @@ test "repeated value is correctly expanded" { | ... | @@ -1163,8 +1159,6 @@ test "repeated value is correctly expanded" { |
| 1163 | } | 1159 | } |
| 1164 | 1160 | ||
| 1165 | test "value in if block is comptime-known" { | 1161 | test "value in if block is comptime-known" { |
| 1166 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1167 | |||
| 1168 | const first = blk: { | 1162 | const first = blk: { |
| 1169 | const s = if (false) "a" else "b"; | 1163 | const s = if (false) "a" else "b"; |
| 1170 | break :blk "foo" ++ s; | 1164 | break :blk "foo" ++ s; |
test/behavior/floatop.zig-2| ... | @@ -349,7 +349,6 @@ fn testDifferentSizedFloatComparisons() !void { | ... | @@ -349,7 +349,6 @@ fn testDifferentSizedFloatComparisons() !void { |
| 349 | test "negative f128 intFromFloat at compile-time" { | 349 | test "negative f128 intFromFloat at compile-time" { |
| 350 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 350 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 352 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 353 | 352 | ||
| 354 | const a: f128 = -2; | 353 | const a: f128 = -2; |
| 355 | var b: i64 = @intFromFloat(a); | 354 | var b: i64 = @intFromFloat(a); |
| ... | @@ -1550,7 +1549,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { | ... | @@ -1550,7 +1549,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { |
| 1550 | test "comptime fixed-width float non-zero divided by zero produces signed Inf" { | 1549 | test "comptime fixed-width float non-zero divided by zero produces signed Inf" { |
| 1551 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1550 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1552 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1551 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1553 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1554 | 1552 | ||
| 1555 | inline for (.{ f16, f32, f64, f80, f128 }) |F| { | 1553 | inline for (.{ f16, f32, f64, f80, f128 }) |F| { |
| 1556 | const pos = @as(F, 1) / @as(F, 0); | 1554 | const pos = @as(F, 1) / @as(F, 0); |
test/behavior/for.zig-3| ... | @@ -453,7 +453,6 @@ test "inline for with counter as the comptime-known" { | ... | @@ -453,7 +453,6 @@ test "inline for with counter as the comptime-known" { |
| 453 | test "inline for on tuple pointer" { | 453 | test "inline for on tuple pointer" { |
| 454 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 454 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 455 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 455 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 456 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 457 | 456 | ||
| 458 | const S = struct { u32, u32, u32 }; | 457 | const S = struct { u32, u32, u32 }; |
| 459 | var s: S = .{ 100, 200, 300 }; | 458 | var s: S = .{ 100, 200, 300 }; |
| ... | @@ -522,8 +521,6 @@ test "return from inline for" { | ... | @@ -522,8 +521,6 @@ test "return from inline for" { |
| 522 | } | 521 | } |
| 523 | 522 | ||
| 524 | test "for loop 0 length range" { | 523 | test "for loop 0 length range" { |
| 525 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 526 | |||
| 527 | const map: []const u8 = &.{}; | 524 | const map: []const u8 = &.{}; |
| 528 | for (map, 0..map.len) |i, j| { | 525 | for (map, 0..map.len) |i, j| { |
| 529 | _ = i; | 526 | _ = i; |
test/behavior/math.zig-1| ... | @@ -2506,7 +2506,6 @@ test "runtime comparison to NaN is comptime-known" { | ... | @@ -2506,7 +2506,6 @@ test "runtime comparison to NaN is comptime-known" { |
| 2506 | test "runtime int comparison to inf is comptime-known" { | 2506 | test "runtime int comparison to inf is comptime-known" { |
| 2507 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 2507 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2508 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 2508 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2509 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 2510 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 2509 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2511 | 2510 | ||
| 2512 | const S = struct { | 2511 | const S = struct { |
test/behavior/pointers.zig-14| ... | @@ -266,8 +266,6 @@ test "implicit cast error unions with non-optional to optional pointer" { | ... | @@ -266,8 +266,6 @@ test "implicit cast error unions with non-optional to optional pointer" { |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | test "compare equality of optional and non-optional pointer" { | 268 | test "compare equality of optional and non-optional pointer" { |
| 269 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 270 | |||
| 271 | const a = @as(*const usize, @ptrFromInt(0x12345678)); | 269 | const a = @as(*const usize, @ptrFromInt(0x12345678)); |
| 272 | const b = @as(?*usize, @ptrFromInt(0x12345678)); | 270 | const b = @as(?*usize, @ptrFromInt(0x12345678)); |
| 273 | try expect(a == b); | 271 | try expect(a == b); |
| ... | @@ -453,8 +451,6 @@ test "pointer sentinel with +inf" { | ... | @@ -453,8 +451,6 @@ test "pointer sentinel with +inf" { |
| 453 | } | 451 | } |
| 454 | 452 | ||
| 455 | test "pointer to array at fixed address" { | 453 | test "pointer to array at fixed address" { |
| 456 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 457 | |||
| 458 | const array = @as(*volatile [2]u32, @ptrFromInt(0x10)); | 454 | const array = @as(*volatile [2]u32, @ptrFromInt(0x10)); |
| 459 | // Silly check just to reference `array` | 455 | // Silly check just to reference `array` |
| 460 | try expect(@intFromPtr(&array[0]) == 0x10); | 456 | try expect(@intFromPtr(&array[0]) == 0x10); |
| ... | @@ -496,8 +492,6 @@ test "pointer-integer arithmetic affects the alignment" { | ... | @@ -496,8 +492,6 @@ test "pointer-integer arithmetic affects the alignment" { |
| 496 | } | 492 | } |
| 497 | 493 | ||
| 498 | test "@intFromPtr on null optional at comptime" { | 494 | test "@intFromPtr on null optional at comptime" { |
| 499 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 500 | |||
| 501 | { | 495 | { |
| 502 | const pointer = @as(?*u8, @ptrFromInt(0x000)); | 496 | const pointer = @as(?*u8, @ptrFromInt(0x000)); |
| 503 | const x = @intFromPtr(pointer); | 497 | const x = @intFromPtr(pointer); |
| ... | @@ -642,8 +636,6 @@ test "result type preserved through multiple references" { | ... | @@ -642,8 +636,6 @@ test "result type preserved through multiple references" { |
| 642 | } | 636 | } |
| 643 | 637 | ||
| 644 | test "result type found through optional pointer" { | 638 | test "result type found through optional pointer" { |
| 645 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 646 | |||
| 647 | const ptr1: ?*const u32 = &@intCast(123); | 639 | const ptr1: ?*const u32 = &@intCast(123); |
| 648 | const ptr2: ?[]const u8 = &.{ @intCast(123), @truncate(0xABCD) }; | 640 | const ptr2: ?[]const u8 = &.{ @intCast(123), @truncate(0xABCD) }; |
| 649 | try expect(ptr1.?.* == 123); | 641 | try expect(ptr1.?.* == 123); |
| ... | @@ -710,8 +702,6 @@ test "pointer-to-array constness for zero-size elements, const" { | ... | @@ -710,8 +702,6 @@ test "pointer-to-array constness for zero-size elements, const" { |
| 710 | } | 702 | } |
| 711 | 703 | ||
| 712 | test "cast pointers with zero sized elements" { | 704 | test "cast pointers with zero sized elements" { |
| 713 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 714 | |||
| 715 | const a: *void = undefined; | 705 | const a: *void = undefined; |
| 716 | const b: *[1]void = a; | 706 | const b: *[1]void = a; |
| 717 | _ = b; | 707 | _ = b; |
| ... | @@ -721,8 +711,6 @@ test "cast pointers with zero sized elements" { | ... | @@ -721,8 +711,6 @@ test "cast pointers with zero sized elements" { |
| 721 | } | 711 | } |
| 722 | 712 | ||
| 723 | test "comptime pointer equality through distinct fields with well-defined layout" { | 713 | test "comptime pointer equality through distinct fields with well-defined layout" { |
| 724 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 725 | |||
| 726 | const A = extern struct { | 714 | const A = extern struct { |
| 727 | x: u32, | 715 | x: u32, |
| 728 | z: u16, | 716 | z: u16, |
| ... | @@ -785,8 +773,6 @@ test "pointers to elements of many-ptr to zero-bit type" { | ... | @@ -785,8 +773,6 @@ test "pointers to elements of many-ptr to zero-bit type" { |
| 785 | } | 773 | } |
| 786 | 774 | ||
| 787 | test "comptime C pointer to optional pointer" { | 775 | test "comptime C pointer to optional pointer" { |
| 788 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 789 | |||
| 790 | const opt: ?*u8 = @ptrFromInt(0x1000); | 776 | const opt: ?*u8 = @ptrFromInt(0x1000); |
| 791 | const outer_ptr: [*c]const ?*u8 = &opt; | 777 | const outer_ptr: [*c]const ?*u8 = &opt; |
| 792 | const inner_ptr = &outer_ptr.*.?; | 778 | const inner_ptr = &outer_ptr.*.?; |
test/behavior/ptrcast.zig-9| ... | @@ -24,7 +24,6 @@ fn testReinterpretBytesAsInteger() !void { | ... | @@ -24,7 +24,6 @@ fn testReinterpretBytesAsInteger() !void { |
| 24 | test "reinterpret an array over multiple elements, with no well-defined layout" { | 24 | test "reinterpret an array over multiple elements, with no well-defined layout" { |
| 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 28 | 27 | ||
| 29 | try testReinterpretWithOffsetAndNoWellDefinedLayout(); | 28 | try testReinterpretWithOffsetAndNoWellDefinedLayout(); |
| 30 | try comptime testReinterpretWithOffsetAndNoWellDefinedLayout(); | 29 | try comptime testReinterpretWithOffsetAndNoWellDefinedLayout(); |
| ... | @@ -282,8 +281,6 @@ test "@ptrCast undefined value at comptime" { | ... | @@ -282,8 +281,6 @@ test "@ptrCast undefined value at comptime" { |
| 282 | } | 281 | } |
| 283 | 282 | ||
| 284 | test "comptime @ptrCast with packed struct leaves value unmodified" { | 283 | test "comptime @ptrCast with packed struct leaves value unmodified" { |
| 285 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 286 | |||
| 287 | const S = packed struct { three: u3 }; | 284 | const S = packed struct { three: u3 }; |
| 288 | const st: S = .{ .three = 6 }; | 285 | const st: S = .{ .three = 6 }; |
| 289 | try expect(st.three == 6); | 286 | try expect(st.three == 6); |
| ... | @@ -293,8 +290,6 @@ test "comptime @ptrCast with packed struct leaves value unmodified" { | ... | @@ -293,8 +290,6 @@ test "comptime @ptrCast with packed struct leaves value unmodified" { |
| 293 | } | 290 | } |
| 294 | 291 | ||
| 295 | test "@ptrCast restructures comptime-only array" { | 292 | test "@ptrCast restructures comptime-only array" { |
| 296 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 297 | |||
| 298 | { | 293 | { |
| 299 | const a3a2: [3][2]comptime_int = .{ | 294 | const a3a2: [3][2]comptime_int = .{ |
| 300 | .{ 1, 2 }, | 295 | .{ 1, 2 }, |
| ... | @@ -561,8 +556,6 @@ test "@ptrCast single-item pointer to slice of bytes" { | ... | @@ -561,8 +556,6 @@ test "@ptrCast single-item pointer to slice of bytes" { |
| 561 | } | 556 | } |
| 562 | 557 | ||
| 563 | test "@ptrCast array pointer removing sentinel" { | 558 | test "@ptrCast array pointer removing sentinel" { |
| 564 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 565 | |||
| 566 | const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 }; | 559 | const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 }; |
| 567 | const out: []const i8 = @ptrCast(in); | 560 | const out: []const i8 = @ptrCast(in); |
| 568 | comptime assert(out.len == 4); | 561 | comptime assert(out.len == 4); |
| ... | @@ -573,8 +566,6 @@ test "@ptrCast array pointer removing sentinel" { | ... | @@ -573,8 +566,6 @@ test "@ptrCast array pointer removing sentinel" { |
| 573 | } | 566 | } |
| 574 | 567 | ||
| 575 | test "@ptrcast larger type to smaller one" { | 568 | test "@ptrcast larger type to smaller one" { |
| 576 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 577 | |||
| 578 | const T = packed struct { x: u17 }; | 569 | const T = packed struct { x: u17 }; |
| 579 | const a: u32 = 0; | 570 | const a: u32 = 0; |
| 580 | const b: *const T = @ptrCast(&a); | 571 | const b: *const T = @ptrCast(&a); |
test/behavior/ptrfromint.zig-1| ... | @@ -44,7 +44,6 @@ test "@ptrFromInt creates null pointer" { | ... | @@ -44,7 +44,6 @@ test "@ptrFromInt creates null pointer" { |
| 44 | test "@ptrFromInt creates allowzero zero pointer" { | 44 | test "@ptrFromInt creates allowzero zero pointer" { |
| 45 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 45 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 46 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 46 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 47 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 48 | 47 | ||
| 49 | const ptr = @as(*allowzero u32, @ptrFromInt(0)); | 48 | const ptr = @as(*allowzero u32, @ptrFromInt(0)); |
| 50 | try expectEqual(@as(usize, 0), @intFromPtr(ptr)); | 49 | try expectEqual(@as(usize, 0), @intFromPtr(ptr)); |
test/behavior/slice.zig+19-2| ... | @@ -385,8 +385,6 @@ test "obtaining a null terminated slice" { | ... | @@ -385,8 +385,6 @@ test "obtaining a null terminated slice" { |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | test "empty array to slice" { | 387 | test "empty array to slice" { |
| 388 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 389 | |||
| 390 | const S = struct { | 388 | const S = struct { |
| 391 | fn doTheTest() !void { | 389 | fn doTheTest() !void { |
| 392 | const empty: []align(16) u8 = &[_]u8{}; | 390 | const empty: []align(16) u8 = &[_]u8{}; |
| ... | @@ -403,6 +401,25 @@ test "empty array to slice" { | ... | @@ -403,6 +401,25 @@ test "empty array to slice" { |
| 403 | try comptime S.doTheTest(); | 401 | try comptime S.doTheTest(); |
| 404 | } | 402 | } |
| 405 | 403 | ||
| 404 | test "comptime-known slice of a global constant" { | ||
| 405 | const S = struct { | ||
| 406 | const weights = [_]f32{ 1, 2, 3 }; | ||
| 407 | |||
| 408 | inline fn first(comptime w: []const f32) f32 { | ||
| 409 | return w[0]; | ||
| 410 | } | ||
| 411 | }; | ||
| 412 | |||
| 413 | var from_param: f32 = S.first(&S.weights); | ||
| 414 | _ = &from_param; | ||
| 415 | try expect(from_param == 1); | ||
| 416 | |||
| 417 | const w: []const f32 = &S.weights; | ||
| 418 | var from_local: f32 = w[1]; | ||
| 419 | _ = &from_local; | ||
| 420 | try expect(from_local == 2); | ||
| 421 | } | ||
| 422 | |||
| 406 | test "@ptrCast slice to pointer" { | 423 | test "@ptrCast slice to pointer" { |
| 407 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 424 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 408 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 425 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/struct.zig-3| ... | @@ -1631,8 +1631,6 @@ test "struct init with no result pointer sets field result types" { | ... | @@ -1631,8 +1631,6 @@ test "struct init with no result pointer sets field result types" { |
| 1631 | } | 1631 | } |
| 1632 | 1632 | ||
| 1633 | test "runtime side-effects in comptime-known struct init" { | 1633 | test "runtime side-effects in comptime-known struct init" { |
| 1634 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1635 | |||
| 1636 | var side_effects: u4 = 0; | 1634 | var side_effects: u4 = 0; |
| 1637 | const S = struct { a: u4, b: u4, c: u4, d: u4 }; | 1635 | const S = struct { a: u4, b: u4, c: u4, d: u4 }; |
| 1638 | const init = S{ | 1636 | const init = S{ |
| ... | @@ -2275,7 +2273,6 @@ test "struct contains underaligned field with overaligned pointer to itself" { | ... | @@ -2275,7 +2273,6 @@ test "struct contains underaligned field with overaligned pointer to itself" { |
| 2275 | } | 2273 | } |
| 2276 | 2274 | ||
| 2277 | test "struct contains pointer to function accepting that struct" { | 2275 | test "struct contains pointer to function accepting that struct" { |
| 2278 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 2279 | const S = struct { | 2276 | const S = struct { |
| 2280 | const FnPtr = ?*const fn (@This()) void; | 2277 | const FnPtr = ?*const fn (@This()) void; |
| 2281 | fn_ptr: FnPtr, | 2278 | fn_ptr: FnPtr, |
test/behavior/type.zig-2| ... | @@ -406,8 +406,6 @@ test "matching captures causes opaque equivalence" { | ... | @@ -406,8 +406,6 @@ test "matching captures causes opaque equivalence" { |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | test "reify enum where fields refers to part of array" { | 408 | test "reify enum where fields refers to part of array" { |
| 409 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 410 | |||
| 411 | const field_names: [3][]const u8 = .{ "foo", "bar", undefined }; | 409 | const field_names: [3][]const u8 = .{ "foo", "bar", undefined }; |
| 412 | const field_values: [3]u8 = .{ undefined, 0, 1 }; | 410 | const field_values: [3]u8 = .{ undefined, 0, 1 }; |
| 413 | const E = @Enum(u8, .exhaustive, field_names[0..2], field_values[1..3]); | 411 | const E = @Enum(u8, .exhaustive, field_names[0..2], field_values[1..3]); |
test/behavior/type_info.zig-4| ... | @@ -310,8 +310,6 @@ const TestStruct = struct { | ... | @@ -310,8 +310,6 @@ const TestStruct = struct { |
| 310 | }; | 310 | }; |
| 311 | 311 | ||
| 312 | test "type info: packed struct info" { | 312 | test "type info: packed struct info" { |
| 313 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 314 | |||
| 315 | try testPackedStruct(); | 313 | try testPackedStruct(); |
| 316 | try comptime testPackedStruct(); | 314 | try comptime testPackedStruct(); |
| 317 | } | 315 | } |
| ... | @@ -596,8 +594,6 @@ test "value from struct @typeInfo default_value_ptr can be loaded at comptime" { | ... | @@ -596,8 +594,6 @@ test "value from struct @typeInfo default_value_ptr can be loaded at comptime" { |
| 596 | } | 594 | } |
| 597 | 595 | ||
| 598 | test "type info of tuple of string literal default value" { | 596 | test "type info of tuple of string literal default value" { |
| 599 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 600 | |||
| 601 | const struct_info = @typeInfo(@TypeOf(.{"hi"})).@"struct"; | 597 | const struct_info = @typeInfo(@TypeOf(.{"hi"})).@"struct"; |
| 602 | const struct_field_attrs = struct_info.field_attrs[0]; | 598 | const struct_field_attrs = struct_info.field_attrs[0]; |
| 603 | const struct_field_type = struct_info.field_types[0]; | 599 | const struct_field_type = struct_info.field_types[0]; |
test/behavior/union.zig-4| ... | @@ -1109,8 +1109,6 @@ test "union with a large struct field" { | ... | @@ -1109,8 +1109,6 @@ test "union with a large struct field" { |
| 1109 | } | 1109 | } |
| 1110 | 1110 | ||
| 1111 | test "comptime equality of extern unions with same tag" { | 1111 | test "comptime equality of extern unions with same tag" { |
| 1112 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1113 | |||
| 1114 | const S = struct { | 1112 | const S = struct { |
| 1115 | const U = extern union { | 1113 | const U = extern union { |
| 1116 | a: i32, | 1114 | a: i32, |
| ... | @@ -1845,8 +1843,6 @@ test "inner struct initializer uses packed union layout" { | ... | @@ -1845,8 +1843,6 @@ test "inner struct initializer uses packed union layout" { |
| 1845 | } | 1843 | } |
| 1846 | 1844 | ||
| 1847 | test "extern union initialized via reintepreted struct field initializer" { | 1845 | test "extern union initialized via reintepreted struct field initializer" { |
| 1848 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1849 | |||
| 1850 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; | 1846 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1851 | 1847 | ||
| 1852 | const U = extern union { | 1848 | const U = extern union { |