Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1595,14 +1595,15 @@ /// static bool CollectBitParts(Value *V, int OverallLeftShift, APInt BitMask, SmallVectorImpl &BitValues, - SmallVectorImpl &BitProvenance) { + SmallVectorImpl &BitProvenance, + SmallPtrSetImpl &OrValues) { if (Instruction *I = dyn_cast(V)) { // If this is an or instruction, it may be an inner node of the bswap. if (I->getOpcode() == Instruction::Or) return CollectBitParts(I->getOperand(0), OverallLeftShift, BitMask, - BitValues, BitProvenance) || + BitValues, BitProvenance, OrValues) || CollectBitParts(I->getOperand(1), OverallLeftShift, BitMask, - BitValues, BitProvenance); + BitValues, BitProvenance, OrValues); // If this is a logical shift by a constant, recurse with OverallLeftShift // and BitMask adjusted. @@ -1630,7 +1631,7 @@ return true; return CollectBitParts(I->getOperand(0), OverallLeftShift, BitMask, - BitValues, BitProvenance); + BitValues, BitProvenance, OrValues); } // If this is a logical 'and' with a mask that clears bits, clear the @@ -1658,7 +1659,7 @@ } return CollectBitParts(I->getOperand(0), OverallLeftShift, BitMask, - BitValues, BitProvenance); + BitValues, BitProvenance, OrValues); } } @@ -1672,6 +1673,15 @@ // Not a contiguous set range of bits! return true; + // If this covers all possible bits, we treat it specially. It means a value + // is being simply ORed into the result. We return it in OrValues and + // continue. + if (InputBitNo == 0 && InputBitLen == BitProvenance.size() && + OverallLeftShift == 0) { + OrValues.insert(V); + return false; + } + // We know we're moving a contiguous range of bits from the input to the // output. Record which bits in the output came from which bits in the input. unsigned DestBitNo = InputBitNo + OverallLeftShift; @@ -1720,7 +1730,8 @@ // Try to find all the pieces corresponding to the bswap. APInt BitMask = APInt::getAllOnesValue(BitValues.size()); - if (CollectBitParts(&I, 0, BitMask, BitValues, BitProvenance)) + SmallPtrSet OrValues; + if (CollectBitParts(&I, 0, BitMask, BitValues, BitProvenance, OrValues)) return nullptr; // Check to see if all of the bits come from the same value. @@ -1770,8 +1781,10 @@ SmallVector NewBitValues(BW, nullptr); SmallVector NewBitProvenance(BW, -1); APInt NewBitMask = APInt::getAllOnesValue(NewBitValues.size()); + SmallPtrSet NewOrValues; if (isa(OtherNode)) { - bool OK = !CollectBitParts(OtherNode, 0, BitMask, BitValues, BitProvenance); + bool OK = !CollectBitParts(OtherNode, 0, BitMask, BitValues, + BitProvenance, NewOrValues); if (OK) return nullptr; } @@ -1782,18 +1795,26 @@ // of the bits of the resulting value from the bitreverse/bswap. if (IgnoreMask.countPopulation() > BW / 2) return nullptr; + // We may have to OR in more values too. If we have more than one value to OR + // in, just bail out. + if (OrValues.size() > 1) + return nullptr; Module *M = I.getParent()->getParent()->getParent(); Function *F = Intrinsic::getDeclaration(M, Intrin, ITy); auto *CI = CallInst::Create(F, V); - if (!IgnoreMask.getBoolValue()) + if (!IgnoreMask.getBoolValue() && OrValues.empty()) return CI; auto *And = BinaryOperator::Create(Instruction::And, CI, ConstantInt::get(ITy, ~IgnoreMask)); CI->insertBefore(&I); - return And; + if (OrValues.empty()) + return And; + + And->insertBefore(&I); + return BinaryOperator::Create(Instruction::Or, And, *OrValues.begin()); } /// We have an expression of the form (A&C)|(B&D). Check if A is (cond?-1:0) Index: test/Transforms/InstCombine/bitreverse-or.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/bitreverse-or.ll @@ -0,0 +1,24 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +; This is a bitreverse that is orred into its original value: +; { +; i2 b = a; +; if (a & 1) b |= 2; +; if (a & 2) b |= 1; +; return b; +; } + +; CHECK-LABEL: @f +; CHECK: %[[x:.*]] = call i2 @llvm.bitreverse.i2(i2 %a) +; CHECK-NEXT: %[[Y:.*]] = or i2 %[[x]], %a +; CHECK-NEXT: ret i2 %[[Y]] +define i2 @f(i2 %a) { +entry: + %and = shl i2 %a, 1 + %0 = and i2 %and, 2 + %1 = or i2 %0, %a + %and1 = lshr i2 %a, 1 + %2 = and i2 %and1, 1 + %3 = or i2 %1, %2 + ret i2 %3 +}