1 //===- AssumeBundleQueries.cpp - tool to query assume bundles ---*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Analysis/AssumeBundleQueries.h"
10 #include "llvm/ADT/Statistic.h"
11 #include "llvm/Analysis/AssumptionCache.h"
12 #include "llvm/Analysis/ValueTracking.h"
13 #include "llvm/IR/Instruction.h"
14 #include "llvm/IR/Instructions.h"
15 #include "llvm/IR/IntrinsicInst.h"
16 #include "llvm/IR/PatternMatch.h"
17 #include "llvm/Support/DebugCounter.h"
19 #define DEBUG_TYPE "assume-queries"
22 using namespace llvm::PatternMatch
;
24 STATISTIC(NumAssumeQueries
, "Number of Queries into an assume assume bundles");
26 NumUsefullAssumeQueries
,
27 "Number of Queries into an assume assume bundles that were satisfied");
29 DEBUG_COUNTER(AssumeQueryCounter
, "assume-queries-counter",
30 "Controls which assumes gets created");
32 static bool bundleHasArgument(const CallBase::BundleOpInfo
&BOI
, unsigned Idx
) {
33 return BOI
.End
- BOI
.Begin
> Idx
;
36 static Value
*getValueFromBundleOpInfo(AssumeInst
&Assume
,
37 const CallBase::BundleOpInfo
&BOI
,
39 assert(bundleHasArgument(BOI
, Idx
) && "index out of range");
40 return (Assume
.op_begin() + BOI
.Begin
+ Idx
)->get();
43 bool llvm::hasAttributeInAssume(AssumeInst
&Assume
, Value
*IsOn
,
44 StringRef AttrName
, uint64_t *ArgVal
) {
45 assert(Attribute::isExistingAttribute(AttrName
) &&
46 "this attribute doesn't exist");
47 assert((ArgVal
== nullptr || Attribute::isIntAttrKind(
48 Attribute::getAttrKindFromName(AttrName
))) &&
49 "requested value for an attribute that has no argument");
50 if (Assume
.bundle_op_infos().empty())
53 for (auto &BOI
: Assume
.bundle_op_infos()) {
54 if (BOI
.Tag
->getKey() != AttrName
)
56 if (IsOn
&& (BOI
.End
- BOI
.Begin
<= ABA_WasOn
||
57 IsOn
!= getValueFromBundleOpInfo(Assume
, BOI
, ABA_WasOn
)))
60 assert(BOI
.End
- BOI
.Begin
> ABA_Argument
);
62 cast
<ConstantInt
>(getValueFromBundleOpInfo(Assume
, BOI
, ABA_Argument
))
70 void llvm::fillMapFromAssume(AssumeInst
&Assume
, RetainedKnowledgeMap
&Result
) {
71 for (auto &Bundles
: Assume
.bundle_op_infos()) {
72 std::pair
<Value
*, Attribute::AttrKind
> Key
{
73 nullptr, Attribute::getAttrKindFromName(Bundles
.Tag
->getKey())};
74 if (bundleHasArgument(Bundles
, ABA_WasOn
))
75 Key
.first
= getValueFromBundleOpInfo(Assume
, Bundles
, ABA_WasOn
);
77 if (Key
.first
== nullptr && Key
.second
== Attribute::None
)
79 if (!bundleHasArgument(Bundles
, ABA_Argument
)) {
80 Result
[Key
][&Assume
] = {0, 0};
83 auto *CI
= dyn_cast
<ConstantInt
>(
84 getValueFromBundleOpInfo(Assume
, Bundles
, ABA_Argument
));
87 uint64_t Val
= CI
->getZExtValue();
88 auto Lookup
= Result
.find(Key
);
89 if (Lookup
== Result
.end() || !Lookup
->second
.count(&Assume
)) {
90 Result
[Key
][&Assume
] = {Val
, Val
};
93 Lookup
->second
[&Assume
].Min
= std::min(Val
, Lookup
->second
[&Assume
].Min
);
94 Lookup
->second
[&Assume
].Max
= std::max(Val
, Lookup
->second
[&Assume
].Max
);
99 llvm::getKnowledgeFromBundle(AssumeInst
&Assume
,
100 const CallBase::BundleOpInfo
&BOI
) {
101 RetainedKnowledge Result
;
102 if (!DebugCounter::shouldExecute(AssumeQueryCounter
))
105 Result
.AttrKind
= Attribute::getAttrKindFromName(BOI
.Tag
->getKey());
106 if (bundleHasArgument(BOI
, ABA_WasOn
))
107 Result
.WasOn
= getValueFromBundleOpInfo(Assume
, BOI
, ABA_WasOn
);
108 auto GetArgOr1
= [&](unsigned Idx
) -> uint64_t {
109 if (auto *ConstInt
= dyn_cast
<ConstantInt
>(
110 getValueFromBundleOpInfo(Assume
, BOI
, ABA_Argument
+ Idx
)))
111 return ConstInt
->getZExtValue();
114 if (BOI
.End
- BOI
.Begin
> ABA_Argument
)
115 Result
.ArgValue
= GetArgOr1(0);
116 if (Result
.AttrKind
== Attribute::Alignment
)
117 if (BOI
.End
- BOI
.Begin
> ABA_Argument
+ 1)
118 Result
.ArgValue
= MinAlign(Result
.ArgValue
, GetArgOr1(1));
122 RetainedKnowledge
llvm::getKnowledgeFromOperandInAssume(AssumeInst
&Assume
,
124 CallBase::BundleOpInfo BOI
= Assume
.getBundleOpInfoForOperand(Idx
);
125 return getKnowledgeFromBundle(Assume
, BOI
);
128 bool llvm::isAssumeWithEmptyBundle(const AssumeInst
&Assume
) {
129 return none_of(Assume
.bundle_op_infos(),
130 [](const CallBase::BundleOpInfo
&BOI
) {
131 return BOI
.Tag
->getKey() != IgnoreBundleTag
;
135 static CallInst::BundleOpInfo
*getBundleFromUse(const Use
*U
) {
136 if (!match(U
->getUser(),
137 m_Intrinsic
<Intrinsic::assume
>(m_Unless(m_Specific(U
->get())))))
139 auto *Intr
= cast
<IntrinsicInst
>(U
->getUser());
140 return &Intr
->getBundleOpInfoForOperand(U
->getOperandNo());
144 llvm::getKnowledgeFromUse(const Use
*U
,
145 ArrayRef
<Attribute::AttrKind
> AttrKinds
) {
146 CallInst::BundleOpInfo
* Bundle
= getBundleFromUse(U
);
148 return RetainedKnowledge::none();
149 RetainedKnowledge RK
=
150 getKnowledgeFromBundle(*cast
<AssumeInst
>(U
->getUser()), *Bundle
);
151 if (llvm::is_contained(AttrKinds
, RK
.AttrKind
))
153 return RetainedKnowledge::none();
157 llvm::getKnowledgeForValue(const Value
*V
,
158 ArrayRef
<Attribute::AttrKind
> AttrKinds
,
160 function_ref
<bool(RetainedKnowledge
, Instruction
*,
161 const CallBase::BundleOpInfo
*)>
165 for (AssumptionCache::ResultElem
&Elem
: AC
->assumptionsFor(V
)) {
166 auto *II
= cast_or_null
<AssumeInst
>(Elem
.Assume
);
167 if (!II
|| Elem
.Index
== AssumptionCache::ExprResultIdx
)
169 if (RetainedKnowledge RK
= getKnowledgeFromBundle(
170 *II
, II
->bundle_op_info_begin()[Elem
.Index
])) {
173 if (is_contained(AttrKinds
, RK
.AttrKind
) &&
174 Filter(RK
, II
, &II
->bundle_op_info_begin()[Elem
.Index
])) {
175 NumUsefullAssumeQueries
++;
180 return RetainedKnowledge::none();
182 for (const auto &U
: V
->uses()) {
183 CallInst::BundleOpInfo
* Bundle
= getBundleFromUse(&U
);
186 if (RetainedKnowledge RK
=
187 getKnowledgeFromBundle(*cast
<AssumeInst
>(U
.getUser()), *Bundle
))
188 if (is_contained(AttrKinds
, RK
.AttrKind
) &&
189 Filter(RK
, cast
<Instruction
>(U
.getUser()), Bundle
)) {
190 NumUsefullAssumeQueries
++;
194 return RetainedKnowledge::none();
197 RetainedKnowledge
llvm::getKnowledgeValidInContext(
198 const Value
*V
, ArrayRef
<Attribute::AttrKind
> AttrKinds
,
199 const Instruction
*CtxI
, const DominatorTree
*DT
, AssumptionCache
*AC
) {
200 return getKnowledgeForValue(V
, AttrKinds
, AC
,
201 [&](auto, Instruction
*I
, auto) {
202 return isValidAssumeForContext(I
, CtxI
, DT
);