[llvm] [InstCombineSimplifyDemanded] Fold xor into or based on condition (PR #151870)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 3 08:50:11 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Panagiotis Karouzakis (karouzakisp)

<details>
<summary>Changes</summary>

This patch folds a XOR operation into an OR one, if the conditions are valid.

(X & C1) ^ C2 --> (X & C1) | C2 iff(C1 & C2) == 0

This is always legal.

Alive proof: https://alive2.llvm.org/ce/z/3P2jdP


---
Full diff: https://github.com/llvm/llvm-project/pull/151870.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp (+11) 
- (added) llvm/test/Transforms/InstCombine/xor-into-or.ll (+15) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 0e3436d12702d..c24e831722a54 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -335,6 +335,17 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Instruction *I,
       return InsertNewInstWith(And, I->getIterator());
     }
 
+    // If all of the demanded bits on one side are known, and all of the set
+    // bits on that side are also known to not be set on the other side, turn
+    // this into an OR, as we know the bits will not affect the result. e.g (X &
+    // C1) ^ C2 --> (X & C1) | C2 iff(C1 & C2) == 0
+    if (DemandedMask.isSubsetOf(RHSKnown.Zero | RHSKnown.One) &&
+        (RHSKnown.One.isSubsetOf(LHSKnown.Zero))) {
+      Instruction *Or =
+          BinaryOperator::CreateOr(I->getOperand(0), I->getOperand(1));
+      return InsertNewInstWith(Or, I->getIterator());
+    }
+
     // If the RHS is a constant, see if we can change it. Don't alter a -1
     // constant because that's a canonical 'not' op, and that is better for
     // combining, SCEV, and codegen.
diff --git a/llvm/test/Transforms/InstCombine/xor-into-or.ll b/llvm/test/Transforms/InstCombine/xor-into-or.ll
new file mode 100644
index 0000000000000..b647941b9645c
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/xor-into-or.ll
@@ -0,0 +1,15 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i8 @a(i8 %x) nounwind {
+; CHECK-LABEL: @a(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[REM:%.*]] = and i8 [[X:%.*]], -120
+; CHECK-NEXT:    [[XOR:%.*]] = or disjoint i8 [[REM]], 36
+; CHECK-NEXT:    ret i8 [[XOR]]
+;
+entry:
+  %rem = and i8 %x, 136
+  %xor = xor i8 %rem, 36
+  ret i8 %xor
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/151870


More information about the llvm-commits mailing list