:p
atchew
Login
Previously, we would produce an incorrect smask in this case: t1.smask = 0xffffffff80000000 shr_i32 t0,t1,$0x1 t0.smask = 0xffffffffc0000000 because `do_constant_folding` would produce `smask = 0x40000000` which was passed unchanged to `fold_masks_zos` which would then update with `s_mask |= INT32_MIN;`, producing the incorrect result above. Reproducer (i386 assembly): .text .globl _start _start: movw $0x4000, %ax addw %ax, %ax cwtl shrl %eax xorl %ebx, %ebx cmpw $-0x3fff, %ax setnl %bl movl $1, %eax int $0x80 Signed-off-by: Jacob Young <jacobly@ziglang.org> --- tcg/optimize.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index XXXXXXX..XXXXXXX 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -XXX,XX +XXX,XX @@ static bool fold_shift(OptContext *ctx, TCGOp *op) o_mask = do_constant_folding(op->opc, ctx->type, o_mask, sh); s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh); + /* + * If the bit shifted into the result sign was not in the + * input s_mask, then no bits are known to match it. + */ + if ((int64_t)s_mask >= 0) { + s_mask = 0; + } + return fold_masks_zos(ctx, op, z_mask, o_mask, s_mask); } -- 2.55.0
Skip s_mask computation for logical right shift. Cc: qemu-stable@nongnu.org Fixes: 93a967fbb57 ("tcg/optimize: Propagate sign info for shifting") Reported-by: Jacob Young <jacobly@ziglang.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- tcg/optimize.c | 11 ++++++++++- tests/tcg/i386/test-i386-opt-shr.c | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/i386/test-i386-opt-shr.c diff --git a/tcg/optimize.c b/tcg/optimize.c index XXXXXXX..XXXXXXX 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -XXX,XX +XXX,XX @@ 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); - s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh); + if (op->opc == INDEX_op_shr) { + /* + * Logical right shift will force the sign bit zero. + * 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); } diff --git a/tests/tcg/i386/test-i386-opt-shr.c b/tests/tcg/i386/test-i386-opt-shr.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/tcg/i386/test-i386-opt-shr.c @@ -XXX,XX +XXX,XX @@ +#include <assert.h> + +int main() +{ +#ifndef __x86_64__ + char test; + + asm("movw $0x4000, %%ax\n\t" + "addw %%ax, %%ax\n\t" + "cwtl\n\t" + "shrl %%eax\n\t" + "cmpw $-0x3fff, %%ax\n\t" + "setnl %%al" + : "=a"(test)); + assert(!test); +#endif + return 0; +} -- 2.43.0