Sema: Improve comptime arithmetic undef handling

This commit expands on the foundations laid by https://github.com/ziglang/zig/pull/23177
and moves even more `Sema`-only functionality from `Value`
to `Sema.arith`. Specifically all shift and bitwise operations,
`@truncate`, `@bitReverse` and `@byteSwap` have been moved and
adapted to the new rules around `undefined`.

Especially the comptime shift operations have been basically
rewritten, fixing many open issues in the process.

New rules applied to operators:
* `<<`, `@shlExact`, `@shlWithOverflow`, `>>`, `@shrExact`: compile error if any operand is undef
* `<<|`, `~`, `^`, `@truncate`, `@bitReverse`, `@byteSwap`: return undef if any operand is undef
* `&`, `|`: Return undef if both operands are undef, turn undef into actual `0xAA` bytes otherwise

Additionally this commit canonicalizes the representation of
aggregates with all-undefined members in the `InternPool` by
disallowing them and enforcing the usage of a single typed
`undef` value instead. This reduces the amount of edge cases
and fixes a bunch of bugs related to partially undefined vecs.

List of operations directly affected by this patch:
* `<<`, `<<|`, `@shlExact`, `@shlWithOverflow`
* `>>`, `@shrExact`
* `&`, `|`, `~`, `^` and their atomic rmw + reduce pendants
* `@truncate`, `@bitReverse`, `@byteSwap`
This commit is contained in:
Justus Klausecker
2025-08-03 13:43:03 +02:00
parent 749f10af49
commit d0586da18e
22 changed files with 5446 additions and 4759 deletions

View File

@@ -154,12 +154,6 @@ test "Saturating Shift Left where lhs is of a computed type" {
try expect(value.exponent == 0);
}
comptime {
var image: [1]u8 = undefined;
_ = &image;
_ = @shlExact(@as(u16, image[0]), 8);
}
test "Saturating Shift Left" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
@@ -202,3 +196,10 @@ test "Saturating Shift Left" {
try expectEqual(170141183460469231731687303715884105727, S.shlSat(@as(i128, 0x2fe6bc5448c55ce18252e2c9d4477750), 0x31));
try expectEqual(0, S.shlSat(@as(i128, 0), 127));
}
test "shift by partially undef vector" {
comptime {
const a: @Vector(1, u8) = .{undefined};
_ = a >> @splat(4);
}
}

View File

@@ -30,7 +30,9 @@ export fn d(rhs: @Vector(3, i32)) void {
//
// :2:25: error: shift by negative amount '-1'
// :7:12: error: shift by negative amount '-2'
// :11:47: error: shift by negative amount '-3' at index '0'
// :16:27: error: shift by negative amount '-4' at index '1'
// :11:47: error: shift by negative amount '-3'
// :11:47: note: when computing vector element at index '0'
// :16:27: error: shift by negative amount '-4'
// :16:27: note: when computing vector element at index '1'
// :20:25: error: shift by signed type 'i32'
// :24:40: error: shift by signed type '@Vector(3, i32)'

View File

@@ -0,0 +1,10 @@
export fn f() usize {
const a = comptime 0 <<| (1 << @bitSizeOf(usize));
return a;
}
// error
// backend=stage2,llvm
// target=x86_64-linux
//
// :2:30: error: this implementation only supports comptime shift amounts of up to 2^64 - 1 bits

View File

@@ -7,4 +7,4 @@ comptime {
// backend=stage2
// target=native
//
// :2:15: error: operation caused overflow
// :2:25: error: overflow of integer type 'u8' with value '340'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff