xref: /llvm-project/llvm/include/llvm/Analysis/AssumeBundleQueries.h (revision 0da2ba811ac8a01509bc533428941fb9519c0715)
1 //===- AssumeBundleQueries.h - utilis to query assume bundles ---*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contain tools to query into assume bundles. assume bundles can be
10 // built using utilities from Transform/Utils/AssumeBundleBuilder.h
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_ANALYSIS_ASSUMEBUNDLEQUERIES_H
15 #define LLVM_ANALYSIS_ASSUMEBUNDLEQUERIES_H
16 
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/IR/IntrinsicInst.h"
19 
20 namespace llvm {
21 class AssumptionCache;
22 class DominatorTree;
23 class Instruction;
24 
25 /// Index of elements in the operand bundle.
26 /// If the element exist it is guaranteed to be what is specified in this enum
27 /// but it may not exist.
28 enum AssumeBundleArg {
29   ABA_WasOn = 0,
30   ABA_Argument = 1,
31 };
32 
33 /// Query the operand bundle of an llvm.assume to find a single attribute of
34 /// the specified kind applied on a specified Value.
35 ///
36 /// This has a non-constant complexity. It should only be used when a single
37 /// attribute is going to be queried.
38 ///
39 /// Return true iff the queried attribute was found.
40 /// If ArgVal is set. the argument will be stored to ArgVal.
41 bool hasAttributeInAssume(AssumeInst &Assume, Value *IsOn, StringRef AttrName,
42                           uint64_t *ArgVal = nullptr);
43 inline bool hasAttributeInAssume(AssumeInst &Assume, Value *IsOn,
44                                  Attribute::AttrKind Kind,
45                                  uint64_t *ArgVal = nullptr) {
46   return hasAttributeInAssume(Assume, IsOn,
47                               Attribute::getNameFromAttrKind(Kind), ArgVal);
48 }
49 
50 template<> struct DenseMapInfo<Attribute::AttrKind> {
51   static Attribute::AttrKind getEmptyKey() {
52     return Attribute::EmptyKey;
53   }
54   static Attribute::AttrKind getTombstoneKey() {
55     return Attribute::TombstoneKey;
56   }
57   static unsigned getHashValue(Attribute::AttrKind AK) {
58     return hash_combine(AK);
59   }
60   static bool isEqual(Attribute::AttrKind LHS, Attribute::AttrKind RHS) {
61     return LHS == RHS;
62   }
63 };
64 
65 /// The map Key contains the Value on for which the attribute is valid and
66 /// the Attribute that is valid for that value.
67 /// If the Attribute is not on any value, the Value is nullptr.
68 using RetainedKnowledgeKey = std::pair<Value *, Attribute::AttrKind>;
69 
70 struct MinMax {
71   uint64_t Min;
72   uint64_t Max;
73 };
74 
75 /// A mapping from intrinsics (=`llvm.assume` calls) to a value range
76 /// (=knowledge) that is encoded in them. How the value range is interpreted
77 /// depends on the RetainedKnowledgeKey that was used to get this out of the
78 /// RetainedKnowledgeMap.
79 using Assume2KnowledgeMap = DenseMap<AssumeInst *, MinMax>;
80 
81 using RetainedKnowledgeMap =
82     DenseMap<RetainedKnowledgeKey, Assume2KnowledgeMap>;
83 
84 /// Insert into the map all the informations contained in the operand bundles of
85 /// the llvm.assume. This should be used instead of hasAttributeInAssume when
86 /// many queries are going to be made on the same llvm.assume.
87 /// String attributes are not inserted in the map.
88 /// If the IR changes the map will be outdated.
89 void fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result);
90 
91 /// Represent one information held inside an operand bundle of an llvm.assume.
92 /// AttrKind is the property that holds.
93 /// WasOn if not null is that Value for which AttrKind holds.
94 /// ArgValue is optionally an argument of the attribute.
95 /// For example if we know that %P has an alignment of at least four:
96 ///  - AttrKind will be Attribute::Alignment.
97 ///  - WasOn will be %P.
98 ///  - ArgValue will be 4.
99 struct RetainedKnowledge {
100   Attribute::AttrKind AttrKind = Attribute::None;
101   uint64_t ArgValue = 0;
102   Value *WasOn = nullptr;
103   bool operator==(RetainedKnowledge Other) const {
104     return AttrKind == Other.AttrKind && WasOn == Other.WasOn &&
105            ArgValue == Other.ArgValue;
106   }
107   bool operator!=(RetainedKnowledge Other) const { return !(*this == Other); }
108   /// This is only intended for use in std::min/std::max between attribute that
109   /// only differ in ArgValue.
110   bool operator<(RetainedKnowledge Other) const {
111     assert(((AttrKind == Other.AttrKind && WasOn == Other.WasOn) ||
112             AttrKind == Attribute::None || Other.AttrKind == Attribute::None) &&
113            "This is only intend for use in min/max to select the best for "
114            "RetainedKnowledge that is otherwise equal");
115     return ArgValue < Other.ArgValue;
116   }
117   operator bool() const { return AttrKind != Attribute::None; }
118   static RetainedKnowledge none() { return RetainedKnowledge{}; }
119 };
120 
121 /// Retreive the information help by Assume on the operand at index Idx.
122 /// Assume should be an llvm.assume and Idx should be in the operand bundle.
123 RetainedKnowledge getKnowledgeFromOperandInAssume(AssumeInst &Assume,
124                                                   unsigned Idx);
125 
126 /// Retreive the information help by the Use U of an llvm.assume. the use should
127 /// be in the operand bundle.
128 inline RetainedKnowledge getKnowledgeFromUseInAssume(const Use *U) {
129   return getKnowledgeFromOperandInAssume(*cast<AssumeInst>(U->getUser()),
130                                          U->getOperandNo());
131 }
132 
133 /// Tag in operand bundle indicating that this bundle should be ignored.
134 constexpr StringRef IgnoreBundleTag = "ignore";
135 
136 /// Return true iff the operand bundles of the provided llvm.assume doesn't
137 /// contain any valuable information. This is true when:
138 ///  - The operand bundle is empty
139 ///  - The operand bundle only contains information about dropped values or
140 ///    constant folded values.
141 ///
142 /// the argument to the call of llvm.assume may still be useful even if the
143 /// function returned true.
144 bool isAssumeWithEmptyBundle(const AssumeInst &Assume);
145 
146 /// Return a valid Knowledge associated to the Use U if its Attribute kind is
147 /// in AttrKinds.
148 RetainedKnowledge getKnowledgeFromUse(const Use *U,
149                                       ArrayRef<Attribute::AttrKind> AttrKinds);
150 
151 /// Return a valid Knowledge associated to the Value V if its Attribute kind is
152 /// in AttrKinds and it matches the Filter.
153 RetainedKnowledge getKnowledgeForValue(
154     const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
155     AssumptionCache *AC = nullptr,
156     function_ref<bool(RetainedKnowledge, Instruction *,
157                             const CallBase::BundleOpInfo *)>
158         Filter = [](auto...) { return true; });
159 
160 /// Return a valid Knowledge associated to the Value V if its Attribute kind is
161 /// in AttrKinds and the knowledge is suitable to be used in the context of
162 /// CtxI.
163 RetainedKnowledge getKnowledgeValidInContext(
164     const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
165     const Instruction *CtxI, const DominatorTree *DT = nullptr,
166     AssumptionCache *AC = nullptr);
167 
168 /// This extracts the Knowledge from an element of an operand bundle.
169 /// This is mostly for use in the assume builder.
170 RetainedKnowledge getKnowledgeFromBundle(AssumeInst &Assume,
171                                          const CallBase::BundleOpInfo &BOI);
172 
173 } // namespace llvm
174 
175 #endif
176