aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp89
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);