diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 38c1c26445540..4203147bc6a54 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3502,15 +3502,13 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant( break; } case Instruction::Xor: - if (BO->hasOneUse()) { - if (Constant *BOC = dyn_cast(BOp1)) { - // For the xor case, we can xor two constants together, eliminating - // the explicit xor. - return new ICmpInst(Pred, BOp0, ConstantExpr::getXor(RHS, BOC)); - } else if (C.isZero()) { - // Replace ((xor A, B) != 0) with (A != B) - return new ICmpInst(Pred, BOp0, BOp1); - } + if (Constant *BOC = dyn_cast(BOp1)) { + // For the xor case, we can xor two constants together, eliminating + // the explicit xor. + return new ICmpInst(Pred, BOp0, ConstantExpr::getXor(RHS, BOC)); + } else if (C.isZero()) { + // Replace ((xor A, B) != 0) with (A != B) + return new ICmpInst(Pred, BOp0, BOp1); } break; case Instruction::Or: { diff --git a/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll b/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll index f5d5ef32c81e8..e8a78df6d5f75 100644 --- a/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll +++ b/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll @@ -88,7 +88,7 @@ define i1 @cmpeq_xor_cst1_commuted(i32 %a, i32 %b) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10 ; CHECK-NEXT: ret i1 [[CMP]] ; - %b2 = mul i32 %b, %b ; thwart complexity-based canonicalization + %b2 = mul i32 %b, %b ; thwart complexity-based canonicalization %c = xor i32 %a, 10 %cmp = icmp eq i32 %b2, %c ret i1 %cmp @@ -145,3 +145,43 @@ entry: %cmp = icmp ne <2 x i8> %xor, ret <2 x i1> %cmp } + +declare void @use.i8(i8) +define i1 @fold_xorC_eq0_multiuse(i8 %x, i8 %y) { +; CHECK-LABEL: @fold_xorC_eq0_multiuse( +; CHECK-NEXT: [[XX:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X]], [[Y]] +; CHECK-NEXT: call void @use.i8(i8 [[XX]]) +; CHECK-NEXT: ret i1 [[R]] +; + %xx = xor i8 %x, %y + %r = icmp eq i8 %xx, 0 + call void @use.i8(i8 %xx) + ret i1 %r +} + +define i1 @fold_xorC_eq1_multiuse_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @fold_xorC_eq1_multiuse_fail( +; CHECK-NEXT: [[XX:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XX]], 1 +; CHECK-NEXT: call void @use.i8(i8 [[XX]]) +; CHECK-NEXT: ret i1 [[R]] +; + %xx = xor i8 %x, %y + %r = icmp eq i8 %xx, 1 + call void @use.i8(i8 %xx) + ret i1 %r +} + +define i1 @fold_xorC_neC_multiuse(i8 %x) { +; CHECK-LABEL: @fold_xorC_neC_multiuse( +; CHECK-NEXT: [[XX:%.*]] = xor i8 [[X:%.*]], 45 +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 110 +; CHECK-NEXT: call void @use.i8(i8 [[XX]]) +; CHECK-NEXT: ret i1 [[R]] +; + %xx = xor i8 %x, 45 + %r = icmp ne i8 %xx, 67 + call void @use.i8(i8 %xx) + ret i1 %r +} diff --git a/llvm/test/Transforms/InstCombine/icmp-or.ll b/llvm/test/Transforms/InstCombine/icmp-or.ll index 1f9db5e5db9aa..b7fb6bb9bb828 100644 --- a/llvm/test/Transforms/InstCombine/icmp-or.ll +++ b/llvm/test/Transforms/InstCombine/icmp-or.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -passes='instcombine' -S | FileCheck %s declare void @use(i8) @@ -434,7 +434,7 @@ define i1 @icmp_or_xor_2_3_fail(i64 %x1, i64 %y1, i64 %x2, i64 %y2) { ; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[X2:%.*]], [[Y2:%.*]] ; CHECK-NEXT: [[OR:%.*]] = or i64 [[XOR]], [[XOR1]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[OR]], 0 -; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq i64 [[XOR]], 0 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq i64 [[X1]], [[Y1]] ; CHECK-NEXT: [[OR1:%.*]] = or i1 [[CMP]], [[CMP_1]] ; CHECK-NEXT: ret i1 [[OR1]] ; @@ -455,7 +455,7 @@ define i1 @icmp_or_xor_2_4_fail(i64 %x1, i64 %y1, i64 %x2, i64 %y2) { ; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[X2:%.*]], [[Y2:%.*]] ; CHECK-NEXT: [[OR:%.*]] = or i64 [[XOR]], [[XOR1]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[OR]], 0 -; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq i64 [[XOR1]], 0 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq i64 [[X2]], [[Y2]] ; CHECK-NEXT: [[OR1:%.*]] = or i1 [[CMP]], [[CMP_1]] ; CHECK-NEXT: ret i1 [[OR1]] ; @@ -955,7 +955,7 @@ define i1 @icmp_or_xor_with_sub_3_6(i64 %x1, i64 %y1, i64 %x2, i64 %y2, i64 %x3, define i1 @or_disjoint_with_constants(i8 %x) { ; CHECK-LABEL: @or_disjoint_with_constants( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP1:%.*]], 18 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 18 ; CHECK-NEXT: ret i1 [[CMP]] ; %or = or disjoint i8 %x, 1 @@ -966,8 +966,8 @@ define i1 @or_disjoint_with_constants(i8 %x) { define i1 @or_disjoint_with_constants2(i8 %x) { ; CHECK-LABEL: @or_disjoint_with_constants2( -; CHECK-NEXT: [[OR:%.*]] = or disjoint i8 [[TMP1:%.*]], 5 -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[TMP1]], 66 +; CHECK-NEXT: [[OR:%.*]] = or disjoint i8 [[X:%.*]], 5 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[X]], 66 ; CHECK-NEXT: call void @use(i8 [[OR]]) ; CHECK-NEXT: ret i1 [[CMP]] ; diff --git a/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll b/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll index cd05022b0d35d..e5906e7a96973 100644 --- a/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll +++ b/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll @@ -7,9 +7,9 @@ define zeroext i1 @test1(i32 %lhs, i32 %rhs) { ; CHECK-LABEL: @test1( -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[LHS:%.*]], 5 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[XOR]], 10 -; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[XOR]], [[RHS:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[LHS:%.*]], 15 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[LHS]], [[RHS:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 5 ; CHECK-NEXT: [[SEL:%.*]] = or i1 [[CMP1]], [[CMP2]] ; CHECK-NEXT: ret i1 [[SEL]] ; @@ -23,9 +23,9 @@ define zeroext i1 @test1(i32 %lhs, i32 %rhs) { define zeroext i1 @test1_logical(i32 %lhs, i32 %rhs) { ; CHECK-LABEL: @test1_logical( -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[LHS:%.*]], 5 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[XOR]], 10 -; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[XOR]], [[RHS:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[LHS:%.*]], 15 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[LHS]], [[RHS:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 5 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]] ; CHECK-NEXT: ret i1 [[SEL]] ; @@ -40,7 +40,7 @@ define zeroext i1 @test1_logical(i32 %lhs, i32 %rhs) { define zeroext i1 @test2(i32 %lhs, i32 %rhs) { ; CHECK-LABEL: @test2( ; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[LHS:%.*]], [[RHS:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[XOR]], 0 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[LHS]], [[RHS]] ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[XOR]], 32 ; CHECK-NEXT: [[SEL:%.*]] = xor i1 [[CMP1]], [[CMP2]] ; CHECK-NEXT: ret i1 [[SEL]] diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll index 846ede45028e2..b37e9175b26a5 100644 --- a/llvm/test/Transforms/InstCombine/select.ll +++ b/llvm/test/Transforms/InstCombine/select.ll @@ -4547,7 +4547,7 @@ define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) { define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @src_no_trans_select_xor_eq0_and_xor( ; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0 +; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]] ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]] ; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]] ; CHECK-NEXT: ret i32 [[COND]] @@ -4563,7 +4563,7 @@ define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) { define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @src_no_trans_select_xor_eq0_or_xor( ; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0 +; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]] ; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]] ; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[OR]], i32 [[XOR]] ; CHECK-NEXT: ret i32 [[COND]]