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: [email protected]
Fixes: 93a967fbb57 ("tcg/optimize: Propagate sign info for shifting")
Assisted-by: Claude Opus 5 (Anthropic)
Signed-off-by: Dominic P <[email protected]>
---
tcg/optimize.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 1e4d2a0a42..27b7682bd5 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -2703,9 +2703,12 @@ 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) {
+ if (op->opc == INDEX_op_shr ||
+ op->opc == INDEX_op_rotl ||
+ op->opc == 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.
*/
--
2.55.0