authorgravatar for rpkak@noreply.codeberg.orgrpkak <rpkak@noreply.codeberg.org> 2026-10-05 09:13:33+02:00
committergravatar for rpkak@noreply.codeberg.orgrpkak <rpkak@noreply.codeberg.org> 2026-10-05 09:50:58+02:00
log1f154f0893c6ad5fadbe76d85bfd921a5446e13c
tree1bb09bbb8ab36871f1956d27360b9af347c33af3
parent5e754304de220c24dc63975970b672c928bab998
signature Signed by SSH key SHA256:A2g6ATENrgLKQcUdthsn72P0njmQxnHSimzwnyJsZzo

Sema: emit shr instead of shr_exact when @shrExact is used and wantSafety is true

The safety check of @shrExact is to shift the result the same amount back to the left and compare if this matches the input of the @shrExact. But since the 'lshr exact' llvm instruction was used, llvm was allowed to assume, that the result of the left-shift matches the input.

1 files changed, 18 insertions(+), 21 deletions(-)

src/Sema.zig+18-21
...@@ -1231,8 +1231,8 @@ fn analyzeBodyInner(...@@ -1231,8 +1231,8 @@ fn analyzeBodyInner(
1231 .ref => try sema.zirRef(block, inst),1231 .ref => try sema.zirRef(block, inst),
1232 .deref => try sema.zirDeref(block, inst),1232 .deref => try sema.zirDeref(block, inst),
1233 .ref_deref => try sema.zirRefDeref(block, inst),1233 .ref_deref => try sema.zirRefDeref(block, inst),
1234 .shr => try sema.zirShr(block, inst, .shr),1234 .shr => try sema.zirShr(block, inst, false),
1235 .shr_exact => try sema.zirShr(block, inst, .shr_exact),1235 .shr_exact => try sema.zirShr(block, inst, true),
1236 .slice_end => try sema.zirSliceEnd(block, inst),1236 .slice_end => try sema.zirSliceEnd(block, inst),
1237 .slice_sentinel => try sema.zirSliceSentinel(block, inst),1237 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
1238 .slice_start => try sema.zirSliceStart(block, inst),1238 .slice_start => try sema.zirSliceStart(block, inst),
...@@ -13176,7 +13176,7 @@ fn zirShr(...@@ -13176,7 +13176,7 @@ fn zirShr(
13176 sema: *Sema,13176 sema: *Sema,
13177 block: *Block,13177 block: *Block,
13178 inst: Zir.Inst.Index,13178 inst: Zir.Inst.Index,
13179 air_tag: Air.Inst.Tag,13179 exact: bool,
13180) CompileError!Air.Inst.Ref {13180) CompileError!Air.Inst.Ref {
13181 const pt = sema.pt;13181 const pt = sema.pt;
13182 const zcu = pt.zcu;13182 const zcu = pt.zcu;
...@@ -13188,16 +13188,15 @@ fn zirShr(...@@ -13188,16 +13188,15 @@ fn zirShr(
13188 const rhs_ty = sema.typeOf(rhs);13188 const rhs_ty = sema.typeOf(rhs);
1318913189
13190 const src = block.nodeOffset(inst_data.src_node);13190 const src = block.nodeOffset(inst_data.src_node);
13191 const lhs_src = switch (air_tag) {13191 const lhs_src = if (exact)
13192 .shr => block.src(.{ .node_offset_bin_lhs = inst_data.src_node }),13192 block.builtinCallArgSrc(inst_data.src_node, 0)
13193 .shr_exact => block.builtinCallArgSrc(inst_data.src_node, 0),13193 else
13194 else => unreachable,13194 block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
13195 };13195
13196 const rhs_src = switch (air_tag) {13196 const rhs_src = if (exact)
13197 .shr => block.src(.{ .node_offset_bin_rhs = inst_data.src_node }),13197 block.builtinCallArgSrc(inst_data.src_node, 1)
13198 .shr_exact => block.builtinCallArgSrc(inst_data.src_node, 1),13198 else
13199 else => unreachable,13199 block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
13200 };
1320113200
13202 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);13201 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
13203 const scalar_ty = lhs_ty.scalarType(zcu);13202 const scalar_ty = lhs_ty.scalarType(zcu);
...@@ -13208,11 +13207,7 @@ fn zirShr(...@@ -13208,11 +13207,7 @@ fn zirShr(
13208 const runtime_src = rs: {13207 const runtime_src = rs: {
13209 if (maybe_rhs_val) |rhs_val| {13208 if (maybe_rhs_val) |rhs_val| {
13210 if (maybe_lhs_val) |lhs_val| {13209 if (maybe_lhs_val) |lhs_val| {
13211 return .fromValue(try arith.shr(sema, block, lhs_ty, rhs_ty, lhs_val, rhs_val, src, lhs_src, rhs_src, switch (air_tag) {13210 return .fromValue(try arith.shr(sema, block, lhs_ty, rhs_ty, lhs_val, rhs_val, src, lhs_src, rhs_src, if (exact) .shr_exact else .shr));
13212 .shr => .shr,
13213 .shr_exact => .shr_exact,
13214 else => unreachable,
13215 }));
13216 }13211 }
13217 if (rhs_val.isUndef(zcu)) {13212 if (rhs_val.isUndef(zcu)) {
13218 return sema.failWithUseOfUndef(block, rhs_src, null);13213 return sema.failWithUseOfUndef(block, rhs_src, null);
...@@ -13269,8 +13264,10 @@ fn zirShr(...@@ -13269,8 +13264,10 @@ fn zirShr(
13269 break :rs rhs_src;13264 break :rs rhs_src;
13270 };13265 };
13271 try sema.requireRuntimeBlock(block, src, runtime_src);13266 try sema.requireRuntimeBlock(block, src, runtime_src);
13272 const result = try block.addBinOp(air_tag, lhs, rhs);13267
13273 if (block.wantSafety()) {13268 const safety = block.wantSafety();
13269 const result = try block.addBinOp(if (!exact or safety) .shr else .shr_exact, lhs, rhs);
13270 if (safety) {
13274 const bit_count = scalar_ty.intInfo(zcu).bits;13271 const bit_count = scalar_ty.intInfo(zcu).bits;
13275 if (!std.math.isPowerOfTwo(bit_count)) {13272 if (!std.math.isPowerOfTwo(bit_count)) {
13276 const bit_count_val = try pt.intValue(rhs_ty.scalarType(zcu), bit_count);13273 const bit_count_val = try pt.intValue(rhs_ty.scalarType(zcu), bit_count);
...@@ -13286,7 +13283,7 @@ fn zirShr(...@@ -13286,7 +13283,7 @@ fn zirShr(
13286 try sema.addSafetyCheck(block, src, ok, .shift_rhs_too_big);13283 try sema.addSafetyCheck(block, src, ok, .shift_rhs_too_big);
13287 }13284 }
1328813285
13289 if (air_tag == .shr_exact) {13286 if (exact) {
13290 const back = try block.addBinOp(.shl, result, rhs);13287 const back = try block.addBinOp(.shl, result, rhs);
1329113288
13292 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {13289 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {