diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 7f2018b3a199..249f4a7710e0 100644 --- a/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -740,6 +740,93 @@ static Value *tryFactorization(BinaryOperator &I, const SimplifyQuery &SQ, return RetVal; } +// If `I` has one Const operand and the other matches `(ctpop (not x))`, +// replace `(ctpop (not x))` with `(sub nuw nsw BitWidth(x), (ctpop x))`. +// This is only useful is the new subtract can fold so we only handle the +// following cases: +// 1) (add/sub/disjoint_or C, (ctpop (not x)) +// -> (add/sub/disjoint_or C', (ctpop x)) +// 1) (cmp pred C, (ctpop (not x)) +// -> (cmp pred C', (ctpop x)) +Instruction *InstCombinerImpl::tryFoldInstWithCtpopWithNot(Instruction *I) { + unsigned Opc = I->getOpcode(); + unsigned ConstIdx = 1; + switch (Opc) { + default: + return nullptr; + // (ctpop (not x)) <-> (sub nuw nsw BitWidth(x) - (ctpop x)) + // We can fold the BitWidth(x) with add/sub/icmp as long the other operand + // is constant. + case Instruction::Sub: + ConstIdx = 0; + break; + case Instruction::ICmp: + // Signed predicates aren't correct in some edge cases like for i2 types, as + // well since (ctpop x) is known [0, log2(BitWidth(x))] almost all signed + // comparisons against it are simplfied to unsigned. + if (cast<ICmpInst>(I)->isSigned()) + return nullptr; + break; + case Instruction::Or: + if (!match(I, m_DisjointOr(m_Value(), m_Value()))) + return nullptr; + [[fallthrough]]; + case Instruction::Add: + break; + } + + Value *Op; + // Find ctpop. + if (!match(I->getOperand(1 - ConstIdx), + m_OneUse(m_Intrinsic<Intrinsic::ctpop>(m_Value(Op))))) + return nullptr; + + Constant *C; + // Check other operand is ImmConstant. + if (!match(I->getOperand(ConstIdx), m_ImmConstant(C))) + return nullptr; + + Type *Ty = Op->getType(); + Constant *BitWidthC = ConstantInt::get(Ty, Ty->getScalarSizeInBits()); + // Need extra check for icmp. Note if this check is true, it generally means + // the icmp will simplify to true/false. + if (Opc == Instruction::ICmp && !cast<ICmpInst>(I)->isEquality() && + !ConstantExpr::getICmp(ICmpInst::ICMP_UGT, C, BitWidthC)->isZeroValue()) + return nullptr; + + // Check we can invert `(not x)` for free. + bool Consumes = false; + if (!isFreeToInvert(Op, Op->hasOneUse(), Consumes) || !Consumes) + return nullptr; + Value *NotOp = getFreelyInverted(Op, Op->hasOneUse(), &Builder); + assert(NotOp != nullptr && + "Desync between isFreeToInvert and getFreelyInverted"); + + Value *CtpopOfNotOp = Builder.CreateIntrinsic(Ty, Intrinsic::ctpop, NotOp); + + Value *R = nullptr; + + // Do the transformation here to avoid potentially introducing an infinite + // loop. + switch (Opc) { + case Instruction::Sub: + R = Builder.CreateAdd(CtpopOfNotOp, ConstantExpr::getSub(C, BitWidthC)); + break; + case Instruction::Or: + case Instruction::Add: + R = Builder.CreateSub(ConstantExpr::getAdd(C, BitWidthC), CtpopOfNotOp); + break; + case Instruction::ICmp: + R = Builder.CreateICmp(cast<ICmpInst>(I)->getSwappedPredicate(), + CtpopOfNotOp, ConstantExpr::getSub(BitWidthC, C)); + break; + default: + llvm_unreachable("Unhandled Opcode"); + } + assert(R != nullptr); + return replaceInstUsesWith(*I, R); +} + // (Binop1 (Binop2 (logic_shift X, C), C1), (logic_shift Y, C)) // IFF // 1) the logic_shifts match @@ -4435,7 +4522,7 @@ bool InstCombinerImpl::run() { if (isa<PHINode>(I)) // PHI -> Non-PHI InsertPos = InstParent->getFirstInsertionPt(); else // Non-PHI -> PHI - InsertPos = InstParent->getFirstNonPHI()->getIterator(); + InsertPos = InstParent->getFirstNonPHIIt(); } Result->insertInto(InstParent, InsertPos); |