xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/AssumeBundleQueries.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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"
13*81ad6265SDimitry Andric #include "llvm/IR/Instruction.h"
14*81ad6265SDimitry 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 
325ffd83dbSDimitry Andric static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) {
335ffd83dbSDimitry Andric   return BOI.End - BOI.Begin > Idx;
345ffd83dbSDimitry Andric }
355ffd83dbSDimitry Andric 
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 
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 
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
99fe6060f1SDimitry Andric llvm::getKnowledgeFromBundle(AssumeInst &Assume,
1005ffd83dbSDimitry Andric                              const CallBase::BundleOpInfo &BOI) {
1015ffd83dbSDimitry Andric   RetainedKnowledge Result;
1025ffd83dbSDimitry Andric   Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
1035ffd83dbSDimitry Andric   if (bundleHasArgument(BOI, ABA_WasOn))
1045ffd83dbSDimitry Andric     Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
105349cc55cSDimitry Andric   auto GetArgOr1 = [&](unsigned Idx) -> uint64_t {
106e8d8bef9SDimitry Andric     if (auto *ConstInt = dyn_cast<ConstantInt>(
107e8d8bef9SDimitry Andric             getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
108e8d8bef9SDimitry Andric       return ConstInt->getZExtValue();
109e8d8bef9SDimitry Andric     return 1;
110e8d8bef9SDimitry Andric   };
1115ffd83dbSDimitry Andric   if (BOI.End - BOI.Begin > ABA_Argument)
112e8d8bef9SDimitry Andric     Result.ArgValue = GetArgOr1(0);
113e8d8bef9SDimitry Andric   if (Result.AttrKind == Attribute::Alignment)
114e8d8bef9SDimitry Andric     if (BOI.End - BOI.Begin > ABA_Argument + 1)
115e8d8bef9SDimitry Andric       Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
1165ffd83dbSDimitry Andric   return Result;
1175ffd83dbSDimitry Andric }
1185ffd83dbSDimitry Andric 
119fe6060f1SDimitry Andric RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume,
1205ffd83dbSDimitry Andric                                                         unsigned Idx) {
1215ffd83dbSDimitry Andric   CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);
122fe6060f1SDimitry Andric   return getKnowledgeFromBundle(Assume, BOI);
1235ffd83dbSDimitry Andric }
1245ffd83dbSDimitry Andric 
125fe6060f1SDimitry Andric bool llvm::isAssumeWithEmptyBundle(AssumeInst &Assume) {
1265ffd83dbSDimitry Andric   return none_of(Assume.bundle_op_infos(),
1275ffd83dbSDimitry Andric                  [](const CallBase::BundleOpInfo &BOI) {
1285ffd83dbSDimitry Andric                    return BOI.Tag->getKey() != IgnoreBundleTag;
1295ffd83dbSDimitry Andric                  });
1305ffd83dbSDimitry Andric }
1315ffd83dbSDimitry Andric 
1325ffd83dbSDimitry Andric static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) {
1335ffd83dbSDimitry Andric   if (!match(U->getUser(),
1345ffd83dbSDimitry Andric              m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))
1355ffd83dbSDimitry Andric     return nullptr;
136fe6060f1SDimitry Andric   auto *Intr = cast<IntrinsicInst>(U->getUser());
1375ffd83dbSDimitry Andric   return &Intr->getBundleOpInfoForOperand(U->getOperandNo());
1385ffd83dbSDimitry Andric }
1395ffd83dbSDimitry Andric 
1405ffd83dbSDimitry Andric RetainedKnowledge
1415ffd83dbSDimitry Andric llvm::getKnowledgeFromUse(const Use *U,
1425ffd83dbSDimitry Andric                           ArrayRef<Attribute::AttrKind> AttrKinds) {
1435ffd83dbSDimitry Andric   CallInst::BundleOpInfo* Bundle = getBundleFromUse(U);
1445ffd83dbSDimitry Andric   if (!Bundle)
1455ffd83dbSDimitry Andric     return RetainedKnowledge::none();
1465ffd83dbSDimitry Andric   RetainedKnowledge RK =
147fe6060f1SDimitry Andric       getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle);
148fe6060f1SDimitry Andric   if (llvm::is_contained(AttrKinds, RK.AttrKind))
1495ffd83dbSDimitry Andric     return RK;
1505ffd83dbSDimitry Andric   return RetainedKnowledge::none();
1515ffd83dbSDimitry Andric }
1525ffd83dbSDimitry Andric 
1535ffd83dbSDimitry Andric RetainedKnowledge
1545ffd83dbSDimitry Andric llvm::getKnowledgeForValue(const Value *V,
1555ffd83dbSDimitry Andric                            ArrayRef<Attribute::AttrKind> AttrKinds,
1565ffd83dbSDimitry Andric                            AssumptionCache *AC,
1575ffd83dbSDimitry Andric                            function_ref<bool(RetainedKnowledge, Instruction *,
1585ffd83dbSDimitry Andric                                              const CallBase::BundleOpInfo *)>
1595ffd83dbSDimitry Andric                                Filter) {
1605ffd83dbSDimitry Andric   NumAssumeQueries++;
1615ffd83dbSDimitry Andric   if (!DebugCounter::shouldExecute(AssumeQueryCounter))
1625ffd83dbSDimitry Andric     return RetainedKnowledge::none();
1635ffd83dbSDimitry Andric   if (AC) {
1645ffd83dbSDimitry Andric     for (AssumptionCache::ResultElem &Elem : AC->assumptionsFor(V)) {
165fe6060f1SDimitry Andric       auto *II = cast_or_null<AssumeInst>(Elem.Assume);
1665ffd83dbSDimitry Andric       if (!II || Elem.Index == AssumptionCache::ExprResultIdx)
1675ffd83dbSDimitry Andric         continue;
1685ffd83dbSDimitry Andric       if (RetainedKnowledge RK = getKnowledgeFromBundle(
169e8d8bef9SDimitry Andric               *II, II->bundle_op_info_begin()[Elem.Index])) {
170e8d8bef9SDimitry Andric         if (V != RK.WasOn)
171e8d8bef9SDimitry Andric           continue;
1725ffd83dbSDimitry Andric         if (is_contained(AttrKinds, RK.AttrKind) &&
1735ffd83dbSDimitry Andric             Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) {
1745ffd83dbSDimitry Andric           NumUsefullAssumeQueries++;
1755ffd83dbSDimitry Andric           return RK;
1765ffd83dbSDimitry Andric         }
1775ffd83dbSDimitry Andric       }
178e8d8bef9SDimitry Andric     }
1795ffd83dbSDimitry Andric     return RetainedKnowledge::none();
1805ffd83dbSDimitry Andric   }
1815ffd83dbSDimitry Andric   for (const auto &U : V->uses()) {
1825ffd83dbSDimitry Andric     CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U);
1835ffd83dbSDimitry Andric     if (!Bundle)
1845ffd83dbSDimitry Andric       continue;
1855ffd83dbSDimitry Andric     if (RetainedKnowledge RK =
186fe6060f1SDimitry Andric             getKnowledgeFromBundle(*cast<AssumeInst>(U.getUser()), *Bundle))
1875ffd83dbSDimitry Andric       if (is_contained(AttrKinds, RK.AttrKind) &&
1885ffd83dbSDimitry Andric           Filter(RK, cast<Instruction>(U.getUser()), Bundle)) {
1895ffd83dbSDimitry Andric         NumUsefullAssumeQueries++;
1905ffd83dbSDimitry Andric         return RK;
1915ffd83dbSDimitry Andric       }
1925ffd83dbSDimitry Andric   }
1935ffd83dbSDimitry Andric   return RetainedKnowledge::none();
1945ffd83dbSDimitry Andric }
1955ffd83dbSDimitry Andric 
1965ffd83dbSDimitry Andric RetainedKnowledge llvm::getKnowledgeValidInContext(
1975ffd83dbSDimitry Andric     const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
1985ffd83dbSDimitry Andric     const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) {
1995ffd83dbSDimitry Andric   return getKnowledgeForValue(V, AttrKinds, AC,
2005ffd83dbSDimitry Andric                               [&](auto, Instruction *I, auto) {
2015ffd83dbSDimitry Andric                                 return isValidAssumeForContext(I, CtxI, DT);
2025ffd83dbSDimitry Andric                               });
2035ffd83dbSDimitry Andric }
204