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 +}