Commit d228536a51 for qemu.org
commit d228536a5142cdd4b28e4feda74fa4859290787f
Author: Dominic P <gcc@gcc.dp11.uk>
Date: Wed Sep 30 19:51:22 2026 +0100
tcg/optimize: Do not derive s_mask from rotated s_mask
fold_shift computes s_mask for a rotate by a constant by rotating the
input s_mask. The result is not a sign mask. For TCG_TYPE_I32,
fold_masks_zosa_int then ORs in INT32_MIN, which can make it look like
one: after sextract_i32 x,0,8 (s_mask ...ffffff80), rotr_i32 by 1 gives
0x7fffffc0, which becomes ...ffffffc0. A following sextract_i32 0,8
is then folded to a mov. rotl_i32 by 31 fails the same way.
ARM, qemu-arm exits 255 instead of 7 (correct with -one-insn-per-tb):
ldr r1, [r2] @ *r2 == 3
sxtb r1, r1
ror r1, r1, #1
sxtb r1, r1 @ dropped
cmp r1, #0
movle r0, #255
movgt r0, #7
i386, the same with rotl_i32:
movsbl %al, %eax
roll $31, %eax
movsbl %al, %eax # dropped
Handle rotates like the logical right shift and let fold_masks_zo
recompute s_mask from z_mask and o_mask.
Cc: qemu-stable@nongnu.org
Fixes: 93a967fbb57 ("tcg/optimize: Propagate sign info for shifting")
Signed-off-by: Dominic P <gcc@gcc.dp11.uk>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-ID: <20260930185124.3036980-2-gcc@gcc.dp11.uk>
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 1e4d2a0a42..c631f690af 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -2703,17 +2703,26 @@ static bool fold_shift(OptContext *ctx, TCGOp *op)
z_mask = do_constant_folding(op->opc, ctx->type, z_mask, sh);
o_mask = do_constant_folding(op->opc, ctx->type, o_mask, sh);
- if (op->opc == INDEX_op_shr) {
+ switch (op->opc) {
+ case INDEX_op_shr:
+ case INDEX_op_rotl:
+ case INDEX_op_rotr:
/*
- * Logical right shift will force the sign bit zero.
+ * Logical right shift will force the sign bit zero, and
+ * a rotate may move bits unrelated to the sign into it.
* Don't bother computing s_mask and let fold_masks
* recompute from z_mask.
*/
return fold_masks_zo(ctx, op, z_mask, o_mask);
- }
- s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh);
- return fold_masks_zos(ctx, op, z_mask, o_mask, s_mask);
+ case INDEX_op_sar:
+ case INDEX_op_shl:
+ s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh);
+ return fold_masks_zos(ctx, op, z_mask, o_mask, s_mask);
+
+ default:
+ g_assert_not_reached();
+ }
}
switch (op->opc) {