xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/AssumeBundleQueries.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //===- AssumeBundleQueries.cpp - tool to query assume bundles ---*- C++ -*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include "llvm/Analysis/AssumeBundleQueries.h"
105ffd83dbSDimitry Andric #include "llvm/ADT/Statistic.h"
115ffd83dbSDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
125ffd83dbSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
1381ad6265SDimitry Andric #include "llvm/IR/Instruction.h"
1481ad6265SDimitry Andric #include "llvm/IR/Instructions.h"
155ffd83dbSDimitry Andric #include "llvm/IR/IntrinsicInst.h"
165ffd83dbSDimitry Andric #include "llvm/IR/PatternMatch.h"
175ffd83dbSDimitry Andric #include "llvm/Support/DebugCounter.h"
185ffd83dbSDimitry Andric 
19fe6060f1SDimitry Andric #define DEBUG_TYPE "assume-queries"
20fe6060f1SDimitry Andric 
215ffd83dbSDimitry Andric using namespace llvm;
225ffd83dbSDimitry Andric using namespace llvm::PatternMatch;
235ffd83dbSDimitry Andric 
245ffd83dbSDimitry Andric STATISTIC(NumAssumeQueries, "Number of Queries into an assume assume bundles");
255ffd83dbSDimitry Andric STATISTIC(
265ffd83dbSDimitry Andric     NumUsefullAssumeQueries,
275ffd83dbSDimitry Andric     "Number of Queries into an assume assume bundles that were satisfied");
285ffd83dbSDimitry Andric 
295ffd83dbSDimitry Andric DEBUG_COUNTER(AssumeQueryCounter, "assume-queries-counter",
305ffd83dbSDimitry Andric               "Controls which assumes gets created");
315ffd83dbSDimitry Andric 
bundleHasArgument(const CallBase::BundleOpInfo & BOI,unsigned Idx)325ffd83dbSDimitry Andric static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) {
335ffd83dbSDimitry Andric   return BOI.End - BOI.Begin > Idx;
345ffd83dbSDimitry Andric }
355ffd83dbSDimitry Andric 
getValueFromBundleOpInfo(AssumeInst & Assume,const CallBase::BundleOpInfo & BOI,unsigned Idx)36fe6060f1SDimitry Andric static Value *getValueFromBundleOpInfo(AssumeInst &Assume,
375ffd83dbSDimitry Andric                                        const CallBase::BundleOpInfo &BOI,
385ffd83dbSDimitry Andric                                        unsigned Idx) {
395ffd83dbSDimitry Andric   assert(bundleHasArgument(BOI, Idx) && "index out of range");
405ffd83dbSDimitry Andric   return (Assume.op_begin() + BOI.Begin + Idx)->get();
415ffd83dbSDimitry Andric }
425ffd83dbSDimitry Andric 
hasAttributeInAssume(AssumeInst & Assume,Value * IsOn,StringRef AttrName,uint64_t * ArgVal)43fe6060f1SDimitry Andric bool llvm::hasAttributeInAssume(AssumeInst &Assume, Value *IsOn,
445ffd83dbSDimitry Andric                                 StringRef AttrName, uint64_t *ArgVal) {
455ffd83dbSDimitry Andric   assert(Attribute::isExistingAttribute(AttrName) &&
465ffd83dbSDimitry Andric          "this attribute doesn't exist");
47fe6060f1SDimitry Andric   assert((ArgVal == nullptr || Attribute::isIntAttrKind(
485ffd83dbSDimitry Andric                                    Attribute::getAttrKindFromName(AttrName))) &&
495ffd83dbSDimitry Andric          "requested value for an attribute that has no argument");
505ffd83dbSDimitry Andric   if (Assume.bundle_op_infos().empty())
515ffd83dbSDimitry Andric     return false;
525ffd83dbSDimitry Andric 
535ffd83dbSDimitry Andric   for (auto &BOI : Assume.bundle_op_infos()) {
545ffd83dbSDimitry Andric     if (BOI.Tag->getKey() != AttrName)
555ffd83dbSDimitry Andric       continue;
565ffd83dbSDimitry Andric     if (IsOn && (BOI.End - BOI.Begin <= ABA_WasOn ||
575ffd83dbSDimitry Andric                  IsOn != getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn)))
585ffd83dbSDimitry Andric       continue;
595ffd83dbSDimitry Andric     if (ArgVal) {
605ffd83dbSDimitry Andric       assert(BOI.End - BOI.Begin > ABA_Argument);
615ffd83dbSDimitry Andric       *ArgVal =
625ffd83dbSDimitry Andric           cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument))
635ffd83dbSDimitry Andric               ->getZExtValue();
645ffd83dbSDimitry Andric     }
655ffd83dbSDimitry Andric     return true;
665ffd83dbSDimitry Andric   }
675ffd83dbSDimitry Andric   return false;
685ffd83dbSDimitry Andric }
695ffd83dbSDimitry Andric 
fillMapFromAssume(AssumeInst & Assume,RetainedKnowledgeMap & Result)70fe6060f1SDimitry Andric void llvm::fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result) {
715ffd83dbSDimitry Andric   for (auto &Bundles : Assume.bundle_op_infos()) {
725ffd83dbSDimitry Andric     std::pair<Value *, Attribute::AttrKind> Key{
735ffd83dbSDimitry Andric         nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())};
745ffd83dbSDimitry Andric     if (bundleHasArgument(Bundles, ABA_WasOn))
755ffd83dbSDimitry Andric       Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn);
765ffd83dbSDimitry Andric 
775ffd83dbSDimitry Andric     if (Key.first == nullptr && Key.second == Attribute::None)
785ffd83dbSDimitry Andric       continue;
795ffd83dbSDimitry Andric     if (!bundleHasArgument(Bundles, ABA_Argument)) {
805ffd83dbSDimitry Andric       Result[Key][&Assume] = {0, 0};
815ffd83dbSDimitry Andric       continue;
825ffd83dbSDimitry Andric     }
83fe6060f1SDimitry Andric     auto *CI = dyn_cast<ConstantInt>(
84fe6060f1SDimitry Andric         getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument));
85fe6060f1SDimitry Andric     if (!CI)
86fe6060f1SDimitry Andric       continue;
87349cc55cSDimitry Andric     uint64_t Val = CI->getZExtValue();
885ffd83dbSDimitry Andric     auto Lookup = Result.find(Key);
895ffd83dbSDimitry Andric     if (Lookup == Result.end() || !Lookup->second.count(&Assume)) {
905ffd83dbSDimitry Andric       Result[Key][&Assume] = {Val, Val};
915ffd83dbSDimitry Andric       continue;
925ffd83dbSDimitry Andric     }
935ffd83dbSDimitry Andric     Lookup->second[&Assume].Min = std::min(Val, Lookup->second[&Assume].Min);
945ffd83dbSDimitry Andric     Lookup->second[&Assume].Max = std::max(Val, Lookup->second[&Assume].Max);
955ffd83dbSDimitry Andric   }
965ffd83dbSDimitry Andric }
975ffd83dbSDimitry Andric 
985ffd83dbSDimitry Andric RetainedKnowledge
getKnowledgeFromBundle(AssumeInst & Assume,const CallBase::BundleOpInfo & BOI)99fe6060f1SDimitry Andric llvm::getKnowledgeFromBundle(AssumeInst &Assume,
1005ffd83dbSDimitry Andric                              const CallBase::BundleOpInfo &BOI) {
1015ffd83dbSDimitry Andric   RetainedKnowledge Result;
102*5f757f3fSDimitry Andric   if (!DebugCounter::shouldExecute(AssumeQueryCounter))
103*5f757f3fSDimitry Andric     return Result;
104*5f757f3fSDimitry Andric 
1055ffd83dbSDimitry Andric   Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
1065ffd83dbSDimitry Andric   if (bundleHasArgument(BOI, ABA_WasOn))
1075ffd83dbSDimitry Andric     Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
108349cc55cSDimitry Andric   auto GetArgOr1 = [&](unsigned Idx) -> uint64_t {
109e8d8bef9SDimitry Andric     if (auto *ConstInt = dyn_cast<ConstantInt>(
110e8d8bef9SDimitry Andric             getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
111e8d8bef9SDimitry Andric       return ConstInt->getZExtValue();
112e8d8bef9SDimitry Andric     return 1;
113e8d8bef9SDimitry Andric   };
1145ffd83dbSDimitry Andric   if (BOI.End - BOI.Begin > ABA_Argument)
115e8d8bef9SDimitry Andric     Result.ArgValue = GetArgOr1(0);
116e8d8bef9SDimitry Andric   if (Result.AttrKind == Attribute::Alignment)
117e8d8bef9SDimitry Andric     if (BOI.End - BOI.Begin > ABA_Argument + 1)
118e8d8bef9SDimitry Andric       Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
1195ffd83dbSDimitry Andric   return Result;
1205ffd83dbSDimitry Andric }
1215ffd83dbSDimitry Andric 
getKnowledgeFromOperandInAssume(AssumeInst & Assume,unsigned Idx)122fe6060f1SDimitry Andric RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume,
1235ffd83dbSDimitry Andric                                                         unsigned Idx) {
1245ffd83dbSDimitry Andric   CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);
125fe6060f1SDimitry Andric   return getKnowledgeFromBundle(Assume, BOI);
1265ffd83dbSDimitry Andric }
1275ffd83dbSDimitry Andric 
isAssumeWithEmptyBundle(const AssumeInst & Assume)128*5f757f3fSDimitry Andric bool llvm::isAssumeWithEmptyBundle(const AssumeInst &Assume) {
1295ffd83dbSDimitry Andric   return none_of(Assume.bundle_op_infos(),
1305ffd83dbSDimitry Andric                  [](const CallBase::BundleOpInfo &BOI) {
1315ffd83dbSDimitry Andric                    return BOI.Tag->getKey() != IgnoreBundleTag;
1325ffd83dbSDimitry Andric                  });
1335ffd83dbSDimitry Andric }
1345ffd83dbSDimitry Andric 
getBundleFromUse(const Use * U)1355ffd83dbSDimitry Andric static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) {
1365ffd83dbSDimitry Andric   if (!match(U->getUser(),
1375ffd83dbSDimitry Andric              m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))
1385ffd83dbSDimitry Andric     return nullptr;
139fe6060f1SDimitry Andric   auto *Intr = cast<IntrinsicInst>(U->getUser());
1405ffd83dbSDimitry Andric   return &Intr->getBundleOpInfoForOperand(U->getOperandNo());
1415ffd83dbSDimitry Andric }
1425ffd83dbSDimitry Andric 
1435ffd83dbSDimitry Andric RetainedKnowledge
getKnowledgeFromUse(const Use * U,ArrayRef<Attribute::AttrKind> AttrKinds)1445ffd83dbSDimitry Andric llvm::getKnowledgeFromUse(const Use *U,
1455ffd83dbSDimitry Andric                           ArrayRef<Attribute::AttrKind> AttrKinds) {
1465ffd83dbSDimitry Andric   CallInst::BundleOpInfo* Bundle = getBundleFromUse(U);
1475ffd83dbSDimitry Andric   if (!Bundle)
1485ffd83dbSDimitry Andric     return RetainedKnowledge::none();
1495ffd83dbSDimitry Andric   RetainedKnowledge RK =
150fe6060f1SDimitry Andric       getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle);
151fe6060f1SDimitry Andric   if (llvm::is_contained(AttrKinds, RK.AttrKind))
1525ffd83dbSDimitry Andric     return RK;
1535ffd83dbSDimitry Andric   return RetainedKnowledge::none();
1545ffd83dbSDimitry Andric }
1555ffd83dbSDimitry Andric 
1565ffd83dbSDimitry Andric RetainedKnowledge
getKnowledgeForValue(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,AssumptionCache * AC,function_ref<bool (RetainedKnowledge,Instruction *,const CallBase::BundleOpInfo *)> Filter)1575ffd83dbSDimitry Andric llvm::getKnowledgeForValue(const Value *V,
1585ffd83dbSDimitry Andric                            ArrayRef<Attribute::AttrKind> AttrKinds,
1595ffd83dbSDimitry Andric                            AssumptionCache *AC,
1605ffd83dbSDimitry Andric                            function_ref<bool(RetainedKnowledge, Instruction *,
1615ffd83dbSDimitry Andric                                              const CallBase::BundleOpInfo *)>
1625ffd83dbSDimitry Andric                                Filter) {
1635ffd83dbSDimitry Andric   NumAssumeQueries++;
1645ffd83dbSDimitry Andric   if (AC) {
1655ffd83dbSDimitry Andric     for (AssumptionCache::ResultElem &Elem : AC->assumptionsFor(V)) {
16606c3fb27SDimitry Andric       auto *II = cast_or_null<AssumeInst>(Elem.Assume);
1675ffd83dbSDimitry Andric       if (!II || Elem.Index == AssumptionCache::ExprResultIdx)
1685ffd83dbSDimitry Andric         continue;
1695ffd83dbSDimitry Andric       if (RetainedKnowledge RK = getKnowledgeFromBundle(
170e8d8bef9SDimitry Andric               *II, II->bundle_op_info_begin()[Elem.Index])) {
171e8d8bef9SDimitry Andric         if (V != RK.WasOn)
172e8d8bef9SDimitry Andric           continue;
1735ffd83dbSDimitry Andric         if (is_contained(AttrKinds, RK.AttrKind) &&
1745ffd83dbSDimitry Andric             Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) {
1755ffd83dbSDimitry Andric           NumUsefullAssumeQueries++;
1765ffd83dbSDimitry Andric           return RK;
1775ffd83dbSDimitry Andric         }
1785ffd83dbSDimitry Andric       }
179e8d8bef9SDimitry Andric     }
1805ffd83dbSDimitry Andric     return RetainedKnowledge::none();
1815ffd83dbSDimitry Andric   }
1825ffd83dbSDimitry Andric   for (const auto &U : V->uses()) {
1835ffd83dbSDimitry Andric     CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U);
1845ffd83dbSDimitry Andric     if (!Bundle)
1855ffd83dbSDimitry Andric       continue;
1865ffd83dbSDimitry Andric     if (RetainedKnowledge RK =
187fe6060f1SDimitry Andric             getKnowledgeFromBundle(*cast<AssumeInst>(U.getUser()), *Bundle))
1885ffd83dbSDimitry Andric       if (is_contained(AttrKinds, RK.AttrKind) &&
1895ffd83dbSDimitry Andric           Filter(RK, cast<Instruction>(U.getUser()), Bundle)) {
1905ffd83dbSDimitry Andric         NumUsefullAssumeQueries++;
1915ffd83dbSDimitry Andric         return RK;
1925ffd83dbSDimitry Andric       }
1935ffd83dbSDimitry Andric   }
1945ffd83dbSDimitry Andric   return RetainedKnowledge::none();
1955ffd83dbSDimitry Andric }
1965ffd83dbSDimitry Andric 
getKnowledgeValidInContext(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,const Instruction * CtxI,const DominatorTree * DT,AssumptionCache * AC)1975ffd83dbSDimitry Andric RetainedKnowledge llvm::getKnowledgeValidInContext(
1985ffd83dbSDimitry Andric     const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
1995ffd83dbSDimitry Andric     const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) {
2005ffd83dbSDimitry Andric   return getKnowledgeForValue(V, AttrKinds, AC,
2015ffd83dbSDimitry Andric                               [&](auto, Instruction *I, auto) {
2025ffd83dbSDimitry Andric                                 return isValidAssumeForContext(I, CtxI, DT);
2035ffd83dbSDimitry Andric                               });
2045ffd83dbSDimitry Andric }
205