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) {