[llvm] 9614f69 - [InstCombine] Fold Xor with or disjoint (#105992)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 22 03:32:21 PDT 2024
Author: Amr Hesham
Date: 2024-09-22T12:32:17+02:00
New Revision: 9614f69b4b1ebaba7a8ad51d583844ebca99bb08
URL: https://github.com/llvm/llvm-project/commit/9614f69b4b1ebaba7a8ad51d583844ebca99bb08
DIFF: https://github.com/llvm/llvm-project/commit/9614f69b4b1ebaba7a8ad51d583844ebca99bb08.diff
LOG: [InstCombine] Fold Xor with or disjoint (#105992)
Implement a missing optimization fold `(X | Y) ^ M to (X ^ M) ^ Y` and
`(X | Y) ^ M to (Y ^ M) ^ X`
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/xor.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 4f557532f9f783..56aac0edc5335c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -4693,7 +4693,20 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
// calls in there are unnecessary as SimplifyDemandedInstructionBits should
// have already taken care of those cases.
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
- Value *M;
+ Value *X, *Y, *M;
+
+ // (X | Y) ^ M -> (X ^ M) ^ Y
+ // (X | Y) ^ M -> (Y ^ M) ^ X
+ if (match(&I, m_c_Xor(m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))),
+ m_Value(M)))) {
+ if (Value *XorAC =
+ simplifyBinOp(Instruction::Xor, X, M, SQ.getWithInstruction(&I)))
+ return BinaryOperator::CreateXor(XorAC, Y);
+
+ if (Value *XorBC = simplifyBinOp(Instruction::Xor, Y, M, SQ))
+ return BinaryOperator::CreateXor(XorBC, X);
+ }
+
if (match(&I, m_c_Xor(m_c_And(m_Not(m_Value(M)), m_Value()),
m_c_And(m_Deferred(M), m_Value())))) {
if (isGuaranteedNotToBeUndef(M))
@@ -4705,7 +4718,6 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
if (Instruction *Xor = visitMaskedMerge(I, Builder))
return Xor;
- Value *X, *Y;
Constant *C1;
if (match(Op1, m_Constant(C1))) {
Constant *C2;
diff --git a/llvm/test/Transforms/InstCombine/xor.ll b/llvm/test/Transforms/InstCombine/xor.ll
index ea7f7382ee7c8e..8308dc503d4da2 100644
--- a/llvm/test/Transforms/InstCombine/xor.ll
+++ b/llvm/test/Transforms/InstCombine/xor.ll
@@ -1485,3 +1485,182 @@ define i4 @PR96857_xor_without_noundef(i4 %val0, i4 %val1, i4 %val2) {
%val7 = xor i4 %val4, %val6
ret i4 %val7
}
+
+define i32 @or_disjoint_with_xor(i32 %a, i32 %b) {
+; CHECK-LABEL: @or_disjoint_with_xor(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i32 [[B:%.*]]
+;
+entry:
+ %or = or disjoint i32 %a, %b
+ %xor = xor i32 %or, %a
+ ret i32 %xor
+}
+
+define i32 @xor_with_or_disjoint_ab(i32 %a, i32 %b) {
+; CHECK-LABEL: @xor_with_or_disjoint_ab(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i32 [[B:%.*]]
+;
+entry:
+ %or = or disjoint i32 %a, %b
+ %xor = xor i32 %a, %or
+ ret i32 %xor
+}
+
+define i32 @xor_with_or_disjoint_ba(i32 %a, i32 %b) {
+; CHECK-LABEL: @xor_with_or_disjoint_ba(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i32 [[B:%.*]]
+;
+entry:
+ %or = or disjoint i32 %b, %a
+ %xor = xor i32 %b, %or
+ ret i32 %xor
+}
+
+define <2 x i32> @or_disjoint_with_xor_vec(<2 x i32> %a, < 2 x i32> %b) {
+; CHECK-LABEL: @or_disjoint_with_xor_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret <2 x i32> [[B:%.*]]
+;
+entry:
+ %or = or disjoint <2 x i32> %a, %b
+ %xor = xor <2 x i32> %or, %a
+ ret <2 x i32> %xor
+}
+
+define <2 x i32> @xor_with_or_disjoint_vec(<2 x i32> %a, < 2 x i32> %b) {
+; CHECK-LABEL: @xor_with_or_disjoint_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret <2 x i32> [[B:%.*]]
+;
+entry:
+ %or = or disjoint <2 x i32> %a, %b
+ %xor = xor <2 x i32> %a, %or
+ ret <2 x i32> %xor
+}
+
+define i32 @select_or_disjoint_xor(i32 %a, i1 %c) {
+; CHECK-LABEL: @select_or_disjoint_xor(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], i32 0, i32 4
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], 4
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[S]], [[SHL]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR]], 4
+; CHECK-NEXT: ret i32 [[XOR]]
+;
+entry:
+ %s = select i1 %c, i32 0, i32 4
+ %shl = shl i32 %a, 4
+ %or = or disjoint i32 %s, %shl
+ %xor = xor i32 %or, 4
+ ret i32 %xor
+}
+
+define <2 x i32> @select_or_disjoint_xor_vec(<2 x i32> %a, i1 %c) {
+; CHECK-LABEL: @select_or_disjoint_xor_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], <2 x i32> zeroinitializer, <2 x i32> <i32 4, i32 4>
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], <i32 4, i32 4>
+; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[S]], [[SHL]]
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[OR]], <i32 4, i32 4>
+; CHECK-NEXT: ret <2 x i32> [[XOR]]
+;
+entry:
+ %s = select i1 %c, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 4, i32 4>
+ %shl = shl <2 x i32> %a, <i32 4, i32 4>
+ %or = or <2 x i32> %s, %shl
+ %xor = xor <2 x i32> %or, <i32 4, i32 4>
+ ret <2 x i32> %xor
+}
+
+define i32 @select_or_disjoint_or(i32 %a, i1 %c) {
+; CHECK-LABEL: @select_or_disjoint_or(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], i32 0, i32 4
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], 4
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[S]], [[SHL]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[OR]], 4
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+entry:
+ %s = select i1 %c, i32 0, i32 4
+ %shl = shl i32 %a, 4
+ %or = or disjoint i32 %s, %shl
+ %add = add i32 %or, 4
+ ret i32 %add
+}
+
+define <2 x i32> @select_or_disjoint_or_vec(<2 x i32> %a, i1 %c) {
+; CHECK-LABEL: @select_or_disjoint_or_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], <2 x i32> zeroinitializer, <2 x i32> <i32 4, i32 4>
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], <i32 4, i32 4>
+; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[S]], [[SHL]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw <2 x i32> [[OR]], <i32 4, i32 4>
+; CHECK-NEXT: ret <2 x i32> [[ADD]]
+;
+entry:
+ %s = select i1 %c, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 4, i32 4>
+ %shl = shl <2 x i32> %a, <i32 4, i32 4>
+ %or = or <2 x i32> %s, %shl
+ %add = add <2 x i32> %or, <i32 4, i32 4>
+ ret <2 x i32> %add
+}
+
+define i32 @or_multi_use_disjoint_with_xor(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @or_multi_use_disjoint_with_xor(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[OR]], [[XOR]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+entry:
+ %or = or disjoint i32 %a, %b
+ %xor = xor i32 %or, %c
+ %add = add i32 %or, %xor
+ ret i32 %add
+}
+
+define <2 x i32> @or_multi_use_disjoint_with_xor_vec(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @or_multi_use_disjoint_with_xor_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[OR]], [[C:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[OR]], [[XOR]]
+; CHECK-NEXT: ret <2 x i32> [[ADD]]
+;
+entry:
+ %or = or disjoint <2 x i32> %a, %b
+ %xor = xor <2 x i32> %or, %c
+ %add = add <2 x i32> %or, %xor
+ ret <2 x i32> %add
+}
+
+define i32 @add_with_or(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @add_with_or(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[ADD]], [[C:%.*]]
+; CHECK-NEXT: ret i32 [[OR]]
+;
+entry:
+ %add = add i32 %a, %b
+ %or = or i32 %add, %c
+ ret i32 %or
+}
+
+define <2 x i32> @add_with_or_vec(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @add_with_or_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[ADD]], [[C:%.*]]
+; CHECK-NEXT: ret <2 x i32> [[OR]]
+;
+entry:
+ %add = add <2 x i32> %a, %b
+ %or = or <2 x i32> %add, %c
+ ret <2 x i32> %or
+}
More information about the llvm-commits
mailing list