4040#include " llvm/Transforms/Utils/Cloning.h"
4141#include " llvm/Transforms/Utils/ValueMapper.h"
4242
43+ #include < cstdint>
4344#include < optional>
4445#include < string>
4546
@@ -57,7 +58,7 @@ static cl::opt<unsigned>
5758 cl::desc(" Maximum number of rows to keep in constraint system" ));
5859
5960static cl::opt<unsigned > MaxColumns (
60- " constraint-elimination-max-cols" , cl::init(16 ), cl::Hidden,
61+ " constraint-elimination-max-cols" , cl::init(64 ), cl::Hidden,
6162 cl::desc(" Maximum number of columns to keep in constraint system" ));
6263
6364static cl::opt<bool > DumpReproducers (
@@ -269,16 +270,16 @@ struct ConstraintTy {
269270// / based on signed-ness, certain conditions can be transferred between the two
270271// / systems.
271272class ConstraintInfo {
272-
273273 ConstraintSystem UnsignedCS;
274274 ConstraintSystem SignedCS;
275275
276276 const DataLayout &DL;
277277
278278public:
279- ConstraintInfo (const DataLayout &DL, ArrayRef<Value *> FunctionArgs)
280- : UnsignedCS(FunctionArgs, MaxColumns),
281- SignedCS (FunctionArgs, MaxColumns), DL(DL) {
279+ ConstraintInfo (const DataLayout &DL, ArrayRef<Value *> FunctionArgs,
280+ unsigned MaxRows, unsigned MaxColumns)
281+ : UnsignedCS(FunctionArgs, MaxRows, MaxColumns),
282+ SignedCS (FunctionArgs, MaxRows, MaxColumns), DL(DL) {
282283 auto &Value2Index = getValue2Index (false );
283284 // Add Arg > -1 constraints to unsigned system for all function arguments.
284285 for (Value *Arg : FunctionArgs) {
@@ -307,6 +308,7 @@ class ConstraintInfo {
307308 void popLastNVariables (bool Signed, unsigned N) {
308309 getCS (Signed).popLastNVariables (N);
309310 }
311+ const DataLayout &getDataLayout () const { return DL; }
310312
311313 bool doesHold (CmpInst::Predicate Pred, Value *A, Value *B) const ;
312314
@@ -1495,7 +1497,7 @@ removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
14951497// / Check if either the first condition of an AND or OR is implied by the
14961498// / (negated in case of OR) second condition or vice versa.
14971499static bool checkOrAndOpImpliedByOther (
1498- FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule,
1500+ const FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule,
14991501 SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
15001502 SmallVectorImpl<StackEntry> &DFSInStack) {
15011503
@@ -1675,21 +1677,85 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
16751677 return Changed;
16761678}
16771679
1678- static bool eliminateConstraints (Function &F, DominatorTree &DT, LoopInfo &LI,
1679- ScalarEvolution &SE,
1680- OptimizationRemarkEmitter &ORE) {
1681- bool Changed = false ;
1680+ // / Performs a dry run of AddFact, computing a conservative estimate of the
1681+ // / number of new variables introduced.
1682+ static void dryRunAddFact (CmpInst::Predicate Pred, Value *A, Value *B,
1683+ const ConstraintInfo &Info, unsigned &EstimatedRows,
1684+ unsigned &EstimatedColumns) {
1685+ auto UpdateEstimate = [&Info, &EstimatedRows, &EstimatedColumns](
1686+ CmpInst::Predicate Pred, Value *A, Value *B) {
1687+ SmallVector<Value *> NewVars;
1688+ auto R = Info.getConstraint (Pred, A, B, NewVars);
1689+
1690+ // We offset it by 1 due to logic in addFact.
1691+ unsigned NewEstimate =
1692+ count_if (R.Coefficients , [](int64_t C) { return C != 0 ; }) + 1 ;
1693+
1694+ ++EstimatedRows;
1695+ EstimatedColumns = std::max (EstimatedColumns, NewEstimate);
1696+ };
1697+
1698+ UpdateEstimate (Pred, A, B);
1699+
1700+ // What follows is a dry-run of transferToOtherSystem.
1701+ auto IsKnownNonNegative = [&Info](Value *V) {
1702+ return Info.doesHold (CmpInst::ICMP_SGE, V,
1703+ ConstantInt::get (V->getType (), 0 )) ||
1704+ isKnownNonNegative (V, Info.getDataLayout (),
1705+ /* Depth=*/ MaxAnalysisRecursionDepth - 1 );
1706+ };
1707+
1708+ if (!A->getType ()->isIntegerTy ())
1709+ return ;
1710+
1711+ switch (Pred) {
1712+ default :
1713+ break ;
1714+ case CmpInst::ICMP_ULT:
1715+ case CmpInst::ICMP_ULE:
1716+ if (IsKnownNonNegative (B)) {
1717+ UpdateEstimate (CmpInst::ICMP_SGE, A, ConstantInt::get (B->getType (), 0 ));
1718+ UpdateEstimate (CmpInst::getSignedPredicate (Pred), A, B);
1719+ }
1720+ break ;
1721+ case CmpInst::ICMP_UGE:
1722+ case CmpInst::ICMP_UGT:
1723+ if (IsKnownNonNegative (A)) {
1724+ UpdateEstimate (CmpInst::ICMP_SGE, B, ConstantInt::get (B->getType (), 0 ));
1725+ UpdateEstimate (CmpInst::getSignedPredicate (Pred), A, B);
1726+ }
1727+ break ;
1728+ case CmpInst::ICMP_SLT:
1729+ if (IsKnownNonNegative (A))
1730+ UpdateEstimate (CmpInst::ICMP_ULT, A, B);
1731+ break ;
1732+ case CmpInst::ICMP_SGT:
1733+ if (Info.doesHold (CmpInst::ICMP_SGE, B, ConstantInt::get (B->getType (), -1 )))
1734+ UpdateEstimate (CmpInst::ICMP_UGE, A, ConstantInt::get (B->getType (), 0 ));
1735+ if (IsKnownNonNegative (B))
1736+ UpdateEstimate (CmpInst::ICMP_UGT, A, B);
1737+ break ;
1738+ case CmpInst::ICMP_SGE:
1739+ if (IsKnownNonNegative (B))
1740+ UpdateEstimate (CmpInst::ICMP_UGE, A, B);
1741+ break ;
1742+ }
1743+ }
1744+
1745+ // / Performs a dry run of the transform, computing a conservative estimate of
1746+ // / the total number of columns we need in the underlying storage.
1747+ static std::tuple<State, unsigned , unsigned >
1748+ dryRun (Function &F, DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE) {
16821749 DT.updateDFSNumbers ();
16831750 SmallVector<Value *> FunctionArgs;
16841751 for (Value &Arg : F.args ())
16851752 FunctionArgs.push_back (&Arg);
1686- ConstraintInfo Info (F.getDataLayout (), FunctionArgs);
16871753 State S (DT, LI, SE);
1688- std::unique_ptr<Module> ReproducerModule (
1689- DumpReproducers ? new Module (F.getName (), F.getContext ()) : nullptr );
1754+ unsigned EstimatedColumns = FunctionArgs.size () + 1 ;
1755+ unsigned EstimatedRows = 1 ;
1756+ ConstraintInfo Info (F.getDataLayout (), FunctionArgs, EstimatedRows,
1757+ EstimatedColumns);
16901758
1691- // First, collect conditions implied by branches and blocks with their
1692- // Dominator DFS in and out numbers.
16931759 for (BasicBlock &BB : F) {
16941760 if (!DT.getNode (&BB))
16951761 continue ;
@@ -1729,12 +1795,87 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
17291795 return A.NumIn < B.NumIn ;
17301796 });
17311797
1798+ for (const FactOrCheck &CB : S.WorkList ) {
1799+ ICmpInst::Predicate Pred;
1800+ Value *A, *B;
1801+ if (CB.isCheck ()) {
1802+ // What follows is a dry-run of checkOrAndOpImpliedByOther, without
1803+ // assuming that instructions have been simplified, as they would have
1804+ // during the course of normal operation.
1805+ auto *ContextInst = CB.getContextInst ();
1806+ if (auto *Cmp =
1807+ dyn_cast_or_null<ICmpInst>(CB.getInstructionToSimplify ())) {
1808+ unsigned OtherOpIdx = ContextInst->getOperand (0 ) == Cmp ? 1 : 0 ;
1809+ if (match (ContextInst, m_LogicalOp ()) &&
1810+ match (ContextInst->getOperand (OtherOpIdx),
1811+ m_ICmp (Pred, m_Value (A), m_Value (B)))) {
1812+ if (match (ContextInst, m_LogicalOr ()))
1813+ Pred = CmpInst::getInversePredicate (Pred);
1814+ dryRunAddFact (Pred, A, B, Info, EstimatedRows, EstimatedColumns);
1815+ }
1816+ }
1817+ continue ;
1818+ }
1819+ if (!CB.isConditionFact ()) {
1820+ Value *X;
1821+ if (match (CB.Inst , m_Intrinsic<Intrinsic::abs>(m_Value (X)))) {
1822+ if (cast<ConstantInt>(CB.Inst ->getOperand (1 ))->isOne ())
1823+ dryRunAddFact (CmpInst::ICMP_SGE, CB.Inst ,
1824+ ConstantInt::get (CB.Inst ->getType (), 0 ), Info,
1825+ EstimatedRows, EstimatedColumns);
1826+ dryRunAddFact (CmpInst::ICMP_SGE, CB.Inst , X, Info, EstimatedRows,
1827+ EstimatedColumns);
1828+ continue ;
1829+ }
1830+
1831+ if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst )) {
1832+ Pred = ICmpInst::getNonStrictPredicate (MinMax->getPredicate ());
1833+ dryRunAddFact (Pred, MinMax, MinMax->getLHS (), Info, EstimatedRows,
1834+ EstimatedColumns);
1835+ dryRunAddFact (Pred, MinMax, MinMax->getRHS (), Info, EstimatedRows,
1836+ EstimatedColumns);
1837+ continue ;
1838+ }
1839+ }
1840+
1841+ if (CB.isConditionFact ()) {
1842+ Pred = CB.Cond .Pred ;
1843+ A = CB.Cond .Op0 ;
1844+ B = CB.Cond .Op1 ;
1845+ } else {
1846+ bool Matched = match (CB.Inst , m_Intrinsic<Intrinsic::assume>(
1847+ m_ICmp (Pred, m_Value (A), m_Value (B))));
1848+ (void )Matched;
1849+ assert (Matched && " Must have an assume intrinsic with a icmp operand" );
1850+ }
1851+ dryRunAddFact (Pred, A, B, Info, EstimatedRows, EstimatedColumns);
1852+ }
1853+ return {S, EstimatedRows, EstimatedColumns};
1854+ }
1855+
1856+ static bool eliminateConstraints (Function &F, DominatorTree &DT, LoopInfo &LI,
1857+ ScalarEvolution &SE,
1858+ OptimizationRemarkEmitter &ORE) {
1859+ bool Changed = false ;
1860+ DT.updateDFSNumbers ();
1861+ SmallVector<Value *> FunctionArgs;
1862+ for (Value &Arg : F.args ())
1863+ FunctionArgs.push_back (&Arg);
1864+ const auto &[S, EstimatedRows, EstimatedColumns] = dryRun (F, DT, LI, SE);
1865+ if (EstimatedRows > MaxRows || EstimatedColumns > MaxColumns)
1866+ return false ;
1867+
1868+ ConstraintInfo Info (F.getDataLayout (), FunctionArgs, EstimatedRows,
1869+ EstimatedColumns);
1870+ std::unique_ptr<Module> ReproducerModule (
1871+ DumpReproducers ? new Module (F.getName (), F.getContext ()) : nullptr );
1872+
17321873 SmallVector<Instruction *> ToRemove;
17331874
17341875 // Finally, process ordered worklist and eliminate implied conditions.
17351876 SmallVector<StackEntry, 16 > DFSInStack;
17361877 SmallVector<ReproducerEntry> ReproducerCondStack;
1737- for (FactOrCheck &CB : S.WorkList ) {
1878+ for (const FactOrCheck &CB : S.WorkList ) {
17381879 // First, pop entries from the stack that are out-of-scope for CB. Remove
17391880 // the corresponding entry from the constraint system.
17401881 while (!DFSInStack.empty ()) {
0 commit comments