Skip to content

Commit

Permalink
[InstCombine] Canonicalize icmp eq/ne (A ^ C), B to `icmp eq/ne (A …
Browse files Browse the repository at this point in the history
…^ 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.
  • Loading branch information
dtcxzyw committed Sep 26, 2023
1 parent 31631d3 commit e158add
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 19 deletions.
8 changes: 8 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5440,6 +5440,14 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
Pred, A,
Builder.CreateIntrinsic(Op0->getType(), Intrinsic::fshl, {A, A, B}));

// Canonicalize:
// icmp eq/ne OneUse(A ^ Cst), B --> icmp eq/ne (A ^ B), Cst
Constant *Cst;
if (match(&I, m_c_ICmp(PredUnused,
m_OneUse(m_Xor(m_Value(A), m_ImmConstant(Cst))),
m_Value(B))))
return new ICmpInst(Pred, Builder.CreateXor(A, B), Cst);

return nullptr;
}

Expand Down
32 changes: 15 additions & 17 deletions llvm/test/Transforms/InstCombine/icmp-equality-xor.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
declare void @use(i32)
define i1 @cmpeq_xor_cst1(i32 %a, i32 %b) {
; CHECK-LABEL: @cmpeq_xor_cst1(
; CHECK-NEXT: [[C:%.*]] = xor i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], [[B:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10
; CHECK-NEXT: ret i1 [[CMP]]
;
%c = xor i32 %a, 10
Expand Down Expand Up @@ -37,8 +37,8 @@ define i1 @cmpeq_xor_cst3(i32 %a, i32 %b) {

define i1 @cmpne_xor_cst1(i32 %a, i32 %b) {
; CHECK-LABEL: @cmpne_xor_cst1(
; CHECK-NEXT: [[C:%.*]] = xor i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[C]], [[B:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP1]], 10
; CHECK-NEXT: ret i1 [[CMP]]
;
%c = xor i32 %a, 10
Expand Down Expand Up @@ -83,19 +83,21 @@ define i1 @cmpeq_xor_cst1_multiuse(i32 %a, i32 %b) {

define i1 @cmpeq_xor_cst1_commuted(i32 %a, i32 %b) {
; CHECK-LABEL: @cmpeq_xor_cst1_commuted(
; CHECK-NEXT: [[C:%.*]] = xor i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], [[B:%.*]]
; CHECK-NEXT: [[B2:%.*]] = mul i32 [[B:%.*]], [[B]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B2]], [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10
; CHECK-NEXT: ret i1 [[CMP]]
;
%b2 = mul i32 %b, %b ; thwart complexity-based canonicalization
%c = xor i32 %a, 10
%cmp = icmp eq i32 %b, %c
%cmp = icmp eq i32 %b2, %c
ret i1 %cmp
}

define <2 x i1> @cmpeq_xor_cst1_vec(<2 x i32> %a, <2 x i32> %b) {
; CHECK-LABEL: @cmpeq_xor_cst1_vec(
; CHECK-NEXT: [[C:%.*]] = xor <2 x i32> [[A:%.*]], <i32 10, i32 11>
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[C]], [[B:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 10, i32 11>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%c = xor <2 x i32> %a, <i32 10, i32 11>
Expand All @@ -106,10 +108,8 @@ define <2 x i1> @cmpeq_xor_cst1_vec(<2 x i32> %a, <2 x i32> %b) {
; tests from PR65968
define i1 @foo1(i32 %x, i32 %y) {
; CHECK-LABEL: @foo1(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], -2147483648
; CHECK-NEXT: [[NEG:%.*]] = and i32 [[Y:%.*]], -2147483648
; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[NEG]], -2147483648
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[AND1]]
; CHECK-NEXT: [[NEG1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NEG1]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%and = and i32 %x, -2147483648
Expand All @@ -121,10 +121,8 @@ define i1 @foo1(i32 %x, i32 %y) {

define i1 @foo2(i32 %x, i32 %y) {
; CHECK-LABEL: @foo2(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], -2147483648
; CHECK-NEXT: [[NEG:%.*]] = and i32 [[Y:%.*]], -2147483648
; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[NEG]], -2147483648
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[AND1]]
; CHECK-NEXT: [[NEG1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NEG1]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%and = and i32 %x, -2147483648
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/InstCombine/icmp-or.ll
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ define i1 @eq_const_mask_not_same(i8 %x, i8 %y) {
define i1 @eq_const_mask_wrong_opcode(i8 %x, i8 %y) {
; CHECK-LABEL: @eq_const_mask_wrong_opcode(
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 5
; CHECK-NEXT: [[B1:%.*]] = xor i8 [[Y:%.*]], 5
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[B0]], [[B1]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[B0]], [[Y:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP1]], 5
; CHECK-NEXT: ret i1 [[CMP]]
;
%b0 = or i8 %x, 5
Expand Down

0 comments on commit e158add

Please sign in to comment.