Skip to content

Commit e158add

Browse files
authored
[InstCombine] Canonicalize icmp eq/ne (A ^ C), B to icmp eq/ne (A ^ B), C (#67273)
This patch canonicalizes `icmp eq/ne (A ^ Cst), B` to `icmp eq/ne (A ^ B), Cst` since the latter form exposes more optimizations. Proof: https://alive2.llvm.org/ce/z/9DbhGc Fixes #65968.
1 parent 31631d3 commit e158add

File tree

3 files changed

+25
-19
lines changed

3 files changed

+25
-19
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5440,6 +5440,14 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
54405440
Pred, A,
54415441
Builder.CreateIntrinsic(Op0->getType(), Intrinsic::fshl, {A, A, B}));
54425442

5443+
// Canonicalize:
5444+
// icmp eq/ne OneUse(A ^ Cst), B --> icmp eq/ne (A ^ B), Cst
5445+
Constant *Cst;
5446+
if (match(&I, m_c_ICmp(PredUnused,
5447+
m_OneUse(m_Xor(m_Value(A), m_ImmConstant(Cst))),
5448+
m_Value(B))))
5449+
return new ICmpInst(Pred, Builder.CreateXor(A, B), Cst);
5450+
54435451
return nullptr;
54445452
}
54455453

llvm/test/Transforms/InstCombine/icmp-equality-xor.ll

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
declare void @use(i32)
55
define i1 @cmpeq_xor_cst1(i32 %a, i32 %b) {
66
; CHECK-LABEL: @cmpeq_xor_cst1(
7-
; CHECK-NEXT: [[C:%.*]] = xor i32 [[A:%.*]], 10
8-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], [[B:%.*]]
7+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
8+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10
99
; CHECK-NEXT: ret i1 [[CMP]]
1010
;
1111
%c = xor i32 %a, 10
@@ -37,8 +37,8 @@ define i1 @cmpeq_xor_cst3(i32 %a, i32 %b) {
3737

3838
define i1 @cmpne_xor_cst1(i32 %a, i32 %b) {
3939
; CHECK-LABEL: @cmpne_xor_cst1(
40-
; CHECK-NEXT: [[C:%.*]] = xor i32 [[A:%.*]], 10
41-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[C]], [[B:%.*]]
40+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
41+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP1]], 10
4242
; CHECK-NEXT: ret i1 [[CMP]]
4343
;
4444
%c = xor i32 %a, 10
@@ -83,19 +83,21 @@ define i1 @cmpeq_xor_cst1_multiuse(i32 %a, i32 %b) {
8383

8484
define i1 @cmpeq_xor_cst1_commuted(i32 %a, i32 %b) {
8585
; CHECK-LABEL: @cmpeq_xor_cst1_commuted(
86-
; CHECK-NEXT: [[C:%.*]] = xor i32 [[A:%.*]], 10
87-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], [[B:%.*]]
86+
; CHECK-NEXT: [[B2:%.*]] = mul i32 [[B:%.*]], [[B]]
87+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B2]], [[A:%.*]]
88+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10
8889
; CHECK-NEXT: ret i1 [[CMP]]
8990
;
91+
%b2 = mul i32 %b, %b ; thwart complexity-based canonicalization
9092
%c = xor i32 %a, 10
91-
%cmp = icmp eq i32 %b, %c
93+
%cmp = icmp eq i32 %b2, %c
9294
ret i1 %cmp
9395
}
9496

9597
define <2 x i1> @cmpeq_xor_cst1_vec(<2 x i32> %a, <2 x i32> %b) {
9698
; CHECK-LABEL: @cmpeq_xor_cst1_vec(
97-
; CHECK-NEXT: [[C:%.*]] = xor <2 x i32> [[A:%.*]], <i32 10, i32 11>
98-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[C]], [[B:%.*]]
99+
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[A:%.*]], [[B:%.*]]
100+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 10, i32 11>
99101
; CHECK-NEXT: ret <2 x i1> [[CMP]]
100102
;
101103
%c = xor <2 x i32> %a, <i32 10, i32 11>
@@ -106,10 +108,8 @@ define <2 x i1> @cmpeq_xor_cst1_vec(<2 x i32> %a, <2 x i32> %b) {
106108
; tests from PR65968
107109
define i1 @foo1(i32 %x, i32 %y) {
108110
; CHECK-LABEL: @foo1(
109-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], -2147483648
110-
; CHECK-NEXT: [[NEG:%.*]] = and i32 [[Y:%.*]], -2147483648
111-
; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[NEG]], -2147483648
112-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[AND1]]
111+
; CHECK-NEXT: [[NEG1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
112+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NEG1]], 0
113113
; CHECK-NEXT: ret i1 [[CMP]]
114114
;
115115
%and = and i32 %x, -2147483648
@@ -121,10 +121,8 @@ define i1 @foo1(i32 %x, i32 %y) {
121121

122122
define i1 @foo2(i32 %x, i32 %y) {
123123
; CHECK-LABEL: @foo2(
124-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], -2147483648
125-
; CHECK-NEXT: [[NEG:%.*]] = and i32 [[Y:%.*]], -2147483648
126-
; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[NEG]], -2147483648
127-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[AND1]]
124+
; CHECK-NEXT: [[NEG1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
125+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NEG1]], 0
128126
; CHECK-NEXT: ret i1 [[CMP]]
129127
;
130128
%and = and i32 %x, -2147483648

llvm/test/Transforms/InstCombine/icmp-or.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ define i1 @eq_const_mask_not_same(i8 %x, i8 %y) {
172172
define i1 @eq_const_mask_wrong_opcode(i8 %x, i8 %y) {
173173
; CHECK-LABEL: @eq_const_mask_wrong_opcode(
174174
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 5
175-
; CHECK-NEXT: [[B1:%.*]] = xor i8 [[Y:%.*]], 5
176-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[B0]], [[B1]]
175+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[B0]], [[Y:%.*]]
176+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP1]], 5
177177
; CHECK-NEXT: ret i1 [[CMP]]
178178
;
179179
%b0 = or i8 %x, 5

0 commit comments

Comments
 (0)