https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122534
Uroš Bizjak <ubizjak at gmail dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
Last reconfirmed| |2025-11-03
Ever confirmed|0 |1
Assignee|unassigned at gcc dot gnu.org |ubizjak at gmail dot com
Target Milestone|--- |16.0
Status|UNCONFIRMED |ASSIGNED
--- Comment #1 from Uroš Bizjak <ubizjak at gmail dot com> ---
(In reply to Andrew Pinski from comment #0)
> Now if we merged this during combine it would have worked.
>
> Combine tries to combine them but we get:
>
> ```
> Trying 12 -> 13:
> 12: {r106:DI=r99:DI&[r100:DI*0x8+r103:DI];clobber flags:CC;}
> REG_UNUSED flags:CC
> 13: flags:CCZ=cmp(r106:DI,0)
> REG_DEAD r106:DI
> Failed to match this instruction:
> (set (reg:CCZ 17 flags)
> (compare:CCZ (and:DI (reg:DI 99 [ shifttmp_6 ])
> (mem:DI (plus:DI (mult:DI (reg/v:DI 100 [ i ])
> (const_int 8 [0x8]))
> (reg/v/f:DI 103 [ p ])) [1 MEM[(long long unsigned int
> *)p_8(D) + i_14 * 8]+0 S8 A64]))
> (const_int 0 [0])))
> ```
We have:
(define_insn "*anddi_1<nf_name>"
[(set (match_operand:DI 0 "nonimmediate_operand" "...")
(and:DI
(match_operand:DI 1 "nonimmediate_operand" "...")
(match_operand:DI 2 "x86_64_szext_general_operand" "...")))]
and:
(define_insn "*testdi_1"
[(set (reg FLAGS_REG)
(compare
(and:DI
(match_operand:DI 0 "nonimmediate_operand" "%r,rm")
(match_operand:DI 1 "x86_64_szext_nonmemory_operand" "Z,re"))
(const_int 0)))]
Note that *testdi_1 does not accept memory operand for operand 1. Intel ISA
reference does not list "TEST mem, reg" as valid, but assembler is clever
enough to swap the commutative operands by itself, so:
testq (%rdi,%rax,8), %rdx
testq %rdx, (%rdi,%rax,8)
both assemble to:
0: 48 85 14 c7 test %rdx,(%rdi,%rax,8)
4: 48 85 14 c7 test %rdx,(%rdi,%rax,8)
So, simply swap operands in ix86_canonicalize_comparison when MEM operand is in
the wrong place:
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 6b6febc8870..c28032bf437 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -598,6 +598,15 @@ ix86_canonicalize_comparison (int *code, rtx *op0, rtx
*op1,
}
}
+ if (!op0_preserve_value
+ && GET_CODE (*op0) == AND
+ && MEM_P (XEXP (*op0, 1)))
+ {
+ std::swap (XEXP (*op0, 0), XEXP (*op0, 1));
+ *code = (int) swap_condition ((enum rtx_code) *code);
+ return;
+ }
+
/* SUB (a, b) underflows precisely when a < b. Convert
(compare (minus (a b)) a) to (compare (a b))
to match *sub<mode>_3 pattern. */