aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorJustus Klausecker <justus@klausecker.de>2025-08-08 19:27:14 +0200
committerJustus Klausecker <justus@klausecker.de>2025-08-12 16:33:58 +0200
commitf0ffe30f2f155616e894c9890c0b22f7a6cfbaab (patch)
tree0c97f083d8e80251f1b9ae57d611fd6cc7976fbc /src/Sema.zig
parent8f5ec2a1fb957f4cd0895064d7ff7534ea306f71 (diff)
downloadzig-f0ffe30f2f155616e894c9890c0b22f7a6cfbaab.tar.gz
zig-f0ffe30f2f155616e894c9890c0b22f7a6cfbaab.zip
add undef shift tests ; mirror `zirShl` logic for `@shlWithOverflow`
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig72
1 files changed, 57 insertions, 15 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index e8df22c334..ac07552874 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -13718,6 +13718,7 @@ fn zirShl(
.shl, .shl_exact => try sema.checkAllScalarsDefined(block, lhs_src, lhs_val),
else => unreachable,
}
+ if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs;
}
}
break :rs rhs_src;
@@ -13884,6 +13885,7 @@ fn zirShr(
}
if (maybe_lhs_val) |lhs_val| {
try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);
+ if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs;
}
}
break :rs rhs_src;
@@ -15615,24 +15617,67 @@ fn zirOverflowArithmetic(
}
},
.shl_with_overflow => {
+ // If either of the arguments is undefined, IB is possible and we return an error.
// If lhs is zero, the result is zero and no overflow occurred.
- // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
+ // If rhs is zero, the result is lhs and no overflow occurred.
// Oterhwise if either of the arguments is undefined, both results are undefined.
- if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef(zcu) and (try lhs_val.compareAllWithZeroSema(.eq, pt))) {
- break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
- }
- }
+ const scalar_ty = lhs_ty.scalarType(zcu);
if (maybe_rhs_val) |rhs_val| {
- if (!rhs_val.isUndef(zcu) and (try rhs_val.compareAllWithZeroSema(.eq, pt))) {
- break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
- }
- }
- if (maybe_lhs_val) |lhs_val| {
- if (maybe_rhs_val) |rhs_val| {
+ if (maybe_lhs_val) |lhs_val| {
const result = try arith.shlWithOverflow(sema, block, lhs_ty, lhs_val, rhs_val, lhs_src, rhs_src);
break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
}
+ if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, null);
+ const bits = scalar_ty.intInfo(zcu).bits;
+ switch (rhs_ty.zigTypeTag(zcu)) {
+ .int, .comptime_int => {
+ switch (try rhs_val.orderAgainstZeroSema(pt)) {
+ .gt => {
+ var rhs_space: Value.BigIntSpace = undefined;
+ const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt);
+ if (rhs_bigint.orderAgainstScalar(bits) != .lt) {
+ return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);
+ }
+ },
+ .eq => break :result .{ .overflow_bit = .zero_u1, .inst = lhs },
+ .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, null),
+ }
+ },
+ .vector => {
+ var any_positive: bool = false;
+ for (0..rhs_ty.vectorLen(zcu)) |elem_idx| {
+ const rhs_elem = try rhs_val.elemValue(pt, elem_idx);
+ if (rhs_elem.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, elem_idx);
+ switch (try rhs_elem.orderAgainstZeroSema(pt)) {
+ .gt => {
+ var rhs_elem_space: Value.BigIntSpace = undefined;
+ const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt);
+ if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {
+ return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);
+ }
+ any_positive = true;
+ },
+ .eq => {},
+ .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_elem, elem_idx),
+ }
+ }
+ if (!any_positive) break :result .{ .overflow_bit = .zero_u1, .inst = lhs };
+ },
+ else => unreachable,
+ }
+ if (try rhs_val.compareAllWithZeroSema(.eq, pt)) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
+ }
+ } else {
+ if (scalar_ty.toIntern() == .comptime_int_type) {
+ return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{});
+ }
+ if (maybe_lhs_val) |lhs_val| {
+ try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);
+ if (try lhs_val.compareAllWithZeroSema(.eq, pt)) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
+ }
+ }
}
},
else => unreachable,
@@ -15646,9 +15691,6 @@ fn zirOverflowArithmetic(
else => unreachable,
};
- const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src;
- try sema.requireRuntimeBlock(block, src, runtime_src);
-
return block.addInst(.{
.tag = air_tag,
.data = .{ .ty_pl = .{