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"
135ffd83dbSDimitry Andric #include "llvm/IR/Function.h"
145ffd83dbSDimitry Andric #include "llvm/IR/InstIterator.h"
155ffd83dbSDimitry Andric #include "llvm/IR/IntrinsicInst.h"
165ffd83dbSDimitry Andric #include "llvm/IR/PatternMatch.h"
175ffd83dbSDimitry Andric #include "llvm/Support/DebugCounter.h"
185ffd83dbSDimitry Andric
19*5f7ddb14SDimitry Andric #define DEBUG_TYPE "assume-queries"
20*5f7ddb14SDimitry 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)36*5f7ddb14SDimitry 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)43*5f7ddb14SDimitry 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");
47*5f7ddb14SDimitry 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)70*5f7ddb14SDimitry 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 }
83*5f7ddb14SDimitry Andric auto *CI = dyn_cast<ConstantInt>(
84*5f7ddb14SDimitry Andric getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument));
85*5f7ddb14SDimitry Andric if (!CI)
86*5f7ddb14SDimitry Andric continue;
87*5f7ddb14SDimitry Andric unsigned 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)99*5f7ddb14SDimitry 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);
105af732203SDimitry Andric auto GetArgOr1 = [&](unsigned Idx) -> unsigned {
106af732203SDimitry Andric if (auto *ConstInt = dyn_cast<ConstantInt>(
107af732203SDimitry Andric getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
108af732203SDimitry Andric return ConstInt->getZExtValue();
109af732203SDimitry Andric return 1;
110af732203SDimitry Andric };
1115ffd83dbSDimitry Andric if (BOI.End - BOI.Begin > ABA_Argument)
112af732203SDimitry Andric Result.ArgValue = GetArgOr1(0);
113af732203SDimitry Andric if (Result.AttrKind == Attribute::Alignment)
114af732203SDimitry Andric if (BOI.End - BOI.Begin > ABA_Argument + 1)
115af732203SDimitry Andric Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
1165ffd83dbSDimitry Andric return Result;
1175ffd83dbSDimitry Andric }
1185ffd83dbSDimitry Andric
getKnowledgeFromOperandInAssume(AssumeInst & Assume,unsigned Idx)119*5f7ddb14SDimitry Andric RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume,
1205ffd83dbSDimitry Andric unsigned Idx) {
1215ffd83dbSDimitry Andric CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);
122*5f7ddb14SDimitry Andric return getKnowledgeFromBundle(Assume, BOI);
1235ffd83dbSDimitry Andric }
1245ffd83dbSDimitry Andric
isAssumeWithEmptyBundle(AssumeInst & Assume)125*5f7ddb14SDimitry 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
getBundleFromUse(const Use * U)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;
136*5f7ddb14SDimitry Andric auto *Intr = cast<IntrinsicInst>(U->getUser());
1375ffd83dbSDimitry Andric return &Intr->getBundleOpInfoForOperand(U->getOperandNo());
1385ffd83dbSDimitry Andric }
1395ffd83dbSDimitry Andric
1405ffd83dbSDimitry Andric RetainedKnowledge
getKnowledgeFromUse(const Use * U,ArrayRef<Attribute::AttrKind> AttrKinds)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 =
147*5f7ddb14SDimitry Andric getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle);
148*5f7ddb14SDimitry Andric if (llvm::is_contained(AttrKinds, RK.AttrKind))
1495ffd83dbSDimitry Andric return RK;
1505ffd83dbSDimitry Andric return RetainedKnowledge::none();
1515ffd83dbSDimitry Andric }
1525ffd83dbSDimitry Andric
1535ffd83dbSDimitry Andric RetainedKnowledge
getKnowledgeForValue(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,AssumptionCache * AC,function_ref<bool (RetainedKnowledge,Instruction *,const CallBase::BundleOpInfo *)> Filter)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)) {
165*5f7ddb14SDimitry 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(
169af732203SDimitry Andric *II, II->bundle_op_info_begin()[Elem.Index])) {
170af732203SDimitry Andric if (V != RK.WasOn)
171af732203SDimitry 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 }
178af732203SDimitry 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 =
186*5f7ddb14SDimitry 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
getKnowledgeValidInContext(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,const Instruction * CtxI,const DominatorTree * DT,AssumptionCache * AC)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