From: Richard Henderson <[email protected]>

When we computed z_mask/o_mask for the deposit, we may accidentally
prove that the result is a constant.

If we let the rest of the code expand as-is, when can we get to the
end we'll see the constant, note that it's the same as the current
value, remove what we think is "the opcode" that computes this same
value.  But in this case we've been expanding deposit to multiple
opcodes and the removal of only the last opcode breaks the expansion.

Fix this by noting the constant result early, before expanding,
allowing the entire operation to be removed.

Cc: [email protected]
Fixes: 5f747705a4 ("tcg/optimize: Lower unsupported deposit during optimize")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4449
Reviewed-by: Jim MacArthur <[email protected]>
Signed-off-by: Richard Henderson <[email protected]>
(cherry picked from commit 0bc331d1c7d5cedc1dbe0bf21dc5f6be13c58fa4)
Signed-off-by: Michael Tokarev <[email protected]>

diff --git a/tcg/optimize.c b/tcg/optimize.c
index c266cfe99c9..891612e3126 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -1674,6 +1674,23 @@ static bool fold_deposit(OptContext *ctx, TCGOp *op)
     type_mask = MAKE_64BIT_MASK(0, width);
     len_mask = MAKE_64BIT_MASK(0, len);
 
+    /*
+     * Compute result masks before calling other fold_* subroutines
+     * which could modify the masks of our inputs.
+     */
+    z_mask = deposit64(t1->z_mask, ofs, len, t2->z_mask);
+    o_mask = deposit64(t1->o_mask, ofs, len, t2->o_mask);
+    if (ofs + len < width) {
+        s_mask = t1->s_mask & ~MAKE_64BIT_MASK(0, ofs + len);
+    } else {
+        s_mask = t2->s_mask << ofs;
+    }
+
+    /* Sometimes we prove a constant from non-constants. */
+    if (z_mask == o_mask) {
+        return tcg_opt_gen_movi(ctx, op, op->args[0], z_mask);
+    }
+
     /* Inserting all-zero into a value. */
     if ((t2->z_mask & len_mask) == 0) {
         op->opc = INDEX_op_and;
@@ -1706,18 +1723,6 @@ static bool fold_deposit(OptContext *ctx, TCGOp *op)
         return fold_or(ctx, op);
     }
 
-    /*
-     * Compute result masks before calling other fold_* subroutines
-     * which could modify the masks of our inputs.
-     */
-    z_mask = deposit64(t1->z_mask, ofs, len, t2->z_mask);
-    o_mask = deposit64(t1->o_mask, ofs, len, t2->o_mask);
-    if (ofs + len < width) {
-        s_mask = t1->s_mask & ~MAKE_64BIT_MASK(0, ofs + len);
-    } else {
-        s_mask = t2->s_mask << ofs;
-    }
-
     /* Inserting a value into zero. */
     if (ti_is_const_val(t1, 0)) {
         uint64_t need_mask;
-- 
2.47.3


Reply via email to