1*82d56013Sjoerg //===- AssumeBundleQueries.cpp - tool to query assume bundles ---*- C++ -*-===//
2*82d56013Sjoerg //
3*82d56013Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*82d56013Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*82d56013Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*82d56013Sjoerg //
7*82d56013Sjoerg //===----------------------------------------------------------------------===//
8*82d56013Sjoerg
9*82d56013Sjoerg #define DEBUG_TYPE "assume-queries"
10*82d56013Sjoerg
11*82d56013Sjoerg #include "llvm/Analysis/AssumeBundleQueries.h"
12*82d56013Sjoerg #include "llvm/ADT/Statistic.h"
13*82d56013Sjoerg #include "llvm/Analysis/AssumptionCache.h"
14*82d56013Sjoerg #include "llvm/Analysis/ValueTracking.h"
15*82d56013Sjoerg #include "llvm/IR/Function.h"
16*82d56013Sjoerg #include "llvm/IR/InstIterator.h"
17*82d56013Sjoerg #include "llvm/IR/IntrinsicInst.h"
18*82d56013Sjoerg #include "llvm/IR/PatternMatch.h"
19*82d56013Sjoerg #include "llvm/Support/DebugCounter.h"
20*82d56013Sjoerg
21*82d56013Sjoerg using namespace llvm;
22*82d56013Sjoerg using namespace llvm::PatternMatch;
23*82d56013Sjoerg
24*82d56013Sjoerg STATISTIC(NumAssumeQueries, "Number of Queries into an assume assume bundles");
25*82d56013Sjoerg STATISTIC(
26*82d56013Sjoerg NumUsefullAssumeQueries,
27*82d56013Sjoerg "Number of Queries into an assume assume bundles that were satisfied");
28*82d56013Sjoerg
29*82d56013Sjoerg DEBUG_COUNTER(AssumeQueryCounter, "assume-queries-counter",
30*82d56013Sjoerg "Controls which assumes gets created");
31*82d56013Sjoerg
bundleHasArgument(const CallBase::BundleOpInfo & BOI,unsigned Idx)32*82d56013Sjoerg static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) {
33*82d56013Sjoerg return BOI.End - BOI.Begin > Idx;
34*82d56013Sjoerg }
35*82d56013Sjoerg
getValueFromBundleOpInfo(AssumeInst & Assume,const CallBase::BundleOpInfo & BOI,unsigned Idx)36*82d56013Sjoerg static Value *getValueFromBundleOpInfo(AssumeInst &Assume,
37*82d56013Sjoerg const CallBase::BundleOpInfo &BOI,
38*82d56013Sjoerg unsigned Idx) {
39*82d56013Sjoerg assert(bundleHasArgument(BOI, Idx) && "index out of range");
40*82d56013Sjoerg return (Assume.op_begin() + BOI.Begin + Idx)->get();
41*82d56013Sjoerg }
42*82d56013Sjoerg
hasAttributeInAssume(AssumeInst & Assume,Value * IsOn,StringRef AttrName,uint64_t * ArgVal)43*82d56013Sjoerg bool llvm::hasAttributeInAssume(AssumeInst &Assume, Value *IsOn,
44*82d56013Sjoerg StringRef AttrName, uint64_t *ArgVal) {
45*82d56013Sjoerg assert(Attribute::isExistingAttribute(AttrName) &&
46*82d56013Sjoerg "this attribute doesn't exist");
47*82d56013Sjoerg assert((ArgVal == nullptr || Attribute::doesAttrKindHaveArgument(
48*82d56013Sjoerg Attribute::getAttrKindFromName(AttrName))) &&
49*82d56013Sjoerg "requested value for an attribute that has no argument");
50*82d56013Sjoerg if (Assume.bundle_op_infos().empty())
51*82d56013Sjoerg return false;
52*82d56013Sjoerg
53*82d56013Sjoerg for (auto &BOI : Assume.bundle_op_infos()) {
54*82d56013Sjoerg if (BOI.Tag->getKey() != AttrName)
55*82d56013Sjoerg continue;
56*82d56013Sjoerg if (IsOn && (BOI.End - BOI.Begin <= ABA_WasOn ||
57*82d56013Sjoerg IsOn != getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn)))
58*82d56013Sjoerg continue;
59*82d56013Sjoerg if (ArgVal) {
60*82d56013Sjoerg assert(BOI.End - BOI.Begin > ABA_Argument);
61*82d56013Sjoerg *ArgVal =
62*82d56013Sjoerg cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument))
63*82d56013Sjoerg ->getZExtValue();
64*82d56013Sjoerg }
65*82d56013Sjoerg return true;
66*82d56013Sjoerg }
67*82d56013Sjoerg return false;
68*82d56013Sjoerg }
69*82d56013Sjoerg
fillMapFromAssume(AssumeInst & Assume,RetainedKnowledgeMap & Result)70*82d56013Sjoerg void llvm::fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result) {
71*82d56013Sjoerg for (auto &Bundles : Assume.bundle_op_infos()) {
72*82d56013Sjoerg std::pair<Value *, Attribute::AttrKind> Key{
73*82d56013Sjoerg nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())};
74*82d56013Sjoerg if (bundleHasArgument(Bundles, ABA_WasOn))
75*82d56013Sjoerg Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn);
76*82d56013Sjoerg
77*82d56013Sjoerg if (Key.first == nullptr && Key.second == Attribute::None)
78*82d56013Sjoerg continue;
79*82d56013Sjoerg if (!bundleHasArgument(Bundles, ABA_Argument)) {
80*82d56013Sjoerg Result[Key][&Assume] = {0, 0};
81*82d56013Sjoerg continue;
82*82d56013Sjoerg }
83*82d56013Sjoerg auto *CI = dyn_cast<ConstantInt>(
84*82d56013Sjoerg getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument));
85*82d56013Sjoerg if (!CI)
86*82d56013Sjoerg continue;
87*82d56013Sjoerg unsigned Val = CI->getZExtValue();
88*82d56013Sjoerg auto Lookup = Result.find(Key);
89*82d56013Sjoerg if (Lookup == Result.end() || !Lookup->second.count(&Assume)) {
90*82d56013Sjoerg Result[Key][&Assume] = {Val, Val};
91*82d56013Sjoerg continue;
92*82d56013Sjoerg }
93*82d56013Sjoerg Lookup->second[&Assume].Min = std::min(Val, Lookup->second[&Assume].Min);
94*82d56013Sjoerg Lookup->second[&Assume].Max = std::max(Val, Lookup->second[&Assume].Max);
95*82d56013Sjoerg }
96*82d56013Sjoerg }
97*82d56013Sjoerg
98*82d56013Sjoerg RetainedKnowledge
getKnowledgeFromBundle(AssumeInst & Assume,const CallBase::BundleOpInfo & BOI)99*82d56013Sjoerg llvm::getKnowledgeFromBundle(AssumeInst &Assume,
100*82d56013Sjoerg const CallBase::BundleOpInfo &BOI) {
101*82d56013Sjoerg RetainedKnowledge Result;
102*82d56013Sjoerg Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
103*82d56013Sjoerg if (bundleHasArgument(BOI, ABA_WasOn))
104*82d56013Sjoerg Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
105*82d56013Sjoerg auto GetArgOr1 = [&](unsigned Idx) -> unsigned {
106*82d56013Sjoerg if (auto *ConstInt = dyn_cast<ConstantInt>(
107*82d56013Sjoerg getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
108*82d56013Sjoerg return ConstInt->getZExtValue();
109*82d56013Sjoerg return 1;
110*82d56013Sjoerg };
111*82d56013Sjoerg if (BOI.End - BOI.Begin > ABA_Argument)
112*82d56013Sjoerg Result.ArgValue = GetArgOr1(0);
113*82d56013Sjoerg if (Result.AttrKind == Attribute::Alignment)
114*82d56013Sjoerg if (BOI.End - BOI.Begin > ABA_Argument + 1)
115*82d56013Sjoerg Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
116*82d56013Sjoerg return Result;
117*82d56013Sjoerg }
118*82d56013Sjoerg
getKnowledgeFromOperandInAssume(AssumeInst & Assume,unsigned Idx)119*82d56013Sjoerg RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume,
120*82d56013Sjoerg unsigned Idx) {
121*82d56013Sjoerg CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);
122*82d56013Sjoerg return getKnowledgeFromBundle(Assume, BOI);
123*82d56013Sjoerg }
124*82d56013Sjoerg
isAssumeWithEmptyBundle(AssumeInst & Assume)125*82d56013Sjoerg bool llvm::isAssumeWithEmptyBundle(AssumeInst &Assume) {
126*82d56013Sjoerg return none_of(Assume.bundle_op_infos(),
127*82d56013Sjoerg [](const CallBase::BundleOpInfo &BOI) {
128*82d56013Sjoerg return BOI.Tag->getKey() != IgnoreBundleTag;
129*82d56013Sjoerg });
130*82d56013Sjoerg }
131*82d56013Sjoerg
getBundleFromUse(const Use * U)132*82d56013Sjoerg static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) {
133*82d56013Sjoerg auto *Intr = dyn_cast<IntrinsicInst>(U->getUser());
134*82d56013Sjoerg if (!match(U->getUser(),
135*82d56013Sjoerg m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))
136*82d56013Sjoerg return nullptr;
137*82d56013Sjoerg return &Intr->getBundleOpInfoForOperand(U->getOperandNo());
138*82d56013Sjoerg }
139*82d56013Sjoerg
140*82d56013Sjoerg RetainedKnowledge
getKnowledgeFromUse(const Use * U,ArrayRef<Attribute::AttrKind> AttrKinds)141*82d56013Sjoerg llvm::getKnowledgeFromUse(const Use *U,
142*82d56013Sjoerg ArrayRef<Attribute::AttrKind> AttrKinds) {
143*82d56013Sjoerg CallInst::BundleOpInfo* Bundle = getBundleFromUse(U);
144*82d56013Sjoerg if (!Bundle)
145*82d56013Sjoerg return RetainedKnowledge::none();
146*82d56013Sjoerg RetainedKnowledge RK =
147*82d56013Sjoerg getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle);
148*82d56013Sjoerg if (llvm::is_contained(AttrKinds, RK.AttrKind))
149*82d56013Sjoerg return RK;
150*82d56013Sjoerg return RetainedKnowledge::none();
151*82d56013Sjoerg }
152*82d56013Sjoerg
153*82d56013Sjoerg RetainedKnowledge
getKnowledgeForValue(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,AssumptionCache * AC,function_ref<bool (RetainedKnowledge,Instruction *,const CallBase::BundleOpInfo *)> Filter)154*82d56013Sjoerg llvm::getKnowledgeForValue(const Value *V,
155*82d56013Sjoerg ArrayRef<Attribute::AttrKind> AttrKinds,
156*82d56013Sjoerg AssumptionCache *AC,
157*82d56013Sjoerg function_ref<bool(RetainedKnowledge, Instruction *,
158*82d56013Sjoerg const CallBase::BundleOpInfo *)>
159*82d56013Sjoerg Filter) {
160*82d56013Sjoerg NumAssumeQueries++;
161*82d56013Sjoerg if (!DebugCounter::shouldExecute(AssumeQueryCounter))
162*82d56013Sjoerg return RetainedKnowledge::none();
163*82d56013Sjoerg if (AC) {
164*82d56013Sjoerg for (AssumptionCache::ResultElem &Elem : AC->assumptionsFor(V)) {
165*82d56013Sjoerg auto *II = cast_or_null<AssumeInst>(Elem.Assume);
166*82d56013Sjoerg if (!II || Elem.Index == AssumptionCache::ExprResultIdx)
167*82d56013Sjoerg continue;
168*82d56013Sjoerg if (RetainedKnowledge RK = getKnowledgeFromBundle(
169*82d56013Sjoerg *II, II->bundle_op_info_begin()[Elem.Index])) {
170*82d56013Sjoerg if (V != RK.WasOn)
171*82d56013Sjoerg continue;
172*82d56013Sjoerg if (is_contained(AttrKinds, RK.AttrKind) &&
173*82d56013Sjoerg Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) {
174*82d56013Sjoerg NumUsefullAssumeQueries++;
175*82d56013Sjoerg return RK;
176*82d56013Sjoerg }
177*82d56013Sjoerg }
178*82d56013Sjoerg }
179*82d56013Sjoerg return RetainedKnowledge::none();
180*82d56013Sjoerg }
181*82d56013Sjoerg for (const auto &U : V->uses()) {
182*82d56013Sjoerg CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U);
183*82d56013Sjoerg if (!Bundle)
184*82d56013Sjoerg continue;
185*82d56013Sjoerg if (RetainedKnowledge RK =
186*82d56013Sjoerg getKnowledgeFromBundle(*cast<AssumeInst>(U.getUser()), *Bundle))
187*82d56013Sjoerg if (is_contained(AttrKinds, RK.AttrKind) &&
188*82d56013Sjoerg Filter(RK, cast<Instruction>(U.getUser()), Bundle)) {
189*82d56013Sjoerg NumUsefullAssumeQueries++;
190*82d56013Sjoerg return RK;
191*82d56013Sjoerg }
192*82d56013Sjoerg }
193*82d56013Sjoerg return RetainedKnowledge::none();
194*82d56013Sjoerg }
195*82d56013Sjoerg
getKnowledgeValidInContext(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,const Instruction * CtxI,const DominatorTree * DT,AssumptionCache * AC)196*82d56013Sjoerg RetainedKnowledge llvm::getKnowledgeValidInContext(
197*82d56013Sjoerg const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
198*82d56013Sjoerg const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) {
199*82d56013Sjoerg return getKnowledgeForValue(V, AttrKinds, AC,
200*82d56013Sjoerg [&](auto, Instruction *I, auto) {
201*82d56013Sjoerg return isValidAssumeForContext(I, CtxI, DT);
202*82d56013Sjoerg });
203*82d56013Sjoerg }
204