MLIR 23.0.0git
ValueBoundsOpInterface.h
Go to the documentation of this file.
1//===- ValueBoundsOpInterface.h - Value Bounds ------------------*- 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#ifndef MLIR_INTERFACES_VALUEBOUNDSOPINTERFACE_H_
10#define MLIR_INTERFACES_VALUEBOUNDSOPINTERFACE_H_
11
13#include "mlir/IR/Builders.h"
15#include "mlir/IR/Value.h"
17#include "llvm/ADT/SetVector.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/Support/ExtensibleRTTI.h"
20
21#include <queue>
22
23namespace mlir {
24class OffsetSizeAndStrideOpInterface;
25
26/// A hyperrectangular slice, represented as a list of offsets, sizes and
27/// strides.
29public:
33
34 /// Create a hyperrectangular slice with unit strides.
37
38 /// Infer a hyperrectangular slice from `OffsetSizeAndStrideOpInterface`.
39 HyperrectangularSlice(OffsetSizeAndStrideOpInterface op);
40
41 ArrayRef<OpFoldResult> getMixedOffsets() const { return mixedOffsets; }
42 ArrayRef<OpFoldResult> getMixedSizes() const { return mixedSizes; }
43 ArrayRef<OpFoldResult> getMixedStrides() const { return mixedStrides; }
44
45private:
46 SmallVector<OpFoldResult> mixedOffsets;
48 SmallVector<OpFoldResult> mixedStrides;
49};
50
51// Inline size chosen empirically based on compilation profiling.
52// Profiled: 488K calls, avg=1.5+-0.5. N=2 covers >90% of cases inline.
54
55/// A helper class to be used with `ValueBoundsOpInterface`. This class stores a
56/// constraint system and mapping of constrained variables to index-typed
57/// values or dimension sizes of shaped values.
58///
59/// Interface implementations of `ValueBoundsOpInterface` use `addBounds` to
60/// insert constraints about their results and/or region block arguments into
61/// the constraint set in the form of an AffineExpr. When a bound should be
62/// expressed in terms of another value/dimension, `getExpr` can be used to
63/// retrieve an AffineExpr that represents the specified value/dimension.
64///
65/// When a value/dimension is retrieved for the first time through `getExpr`,
66/// it is added to an internal worklist. See `computeBound` for more details.
67///
68/// Note: Any modification of existing IR invalides the data stored in this
69/// class. Adding new operations is allowed.
71 : public llvm::RTTIExtends<ValueBoundsConstraintSet, llvm::RTTIRoot> {
72protected:
73 /// Helper class that builds a bound for a shaped value dimension or
74 /// index-typed value.
76 public:
77 /// Specify a dimension, assuming that the underlying value is a shaped
78 /// value.
80
81 // These overloaded operators add lower/upper/equality bounds.
82 void operator<(AffineExpr expr);
83 void operator<=(AffineExpr expr);
84 void operator>(AffineExpr expr);
85 void operator>=(AffineExpr expr);
86 void operator==(AffineExpr expr);
87 void operator<(OpFoldResult ofr);
88 void operator<=(OpFoldResult ofr);
89 void operator>(OpFoldResult ofr);
90 void operator>=(OpFoldResult ofr);
91 void operator==(OpFoldResult ofr);
92 void operator<(int64_t i);
93 void operator<=(int64_t i);
94 void operator>(int64_t i);
95 void operator>=(int64_t i);
96 void operator==(int64_t i);
97
98 protected:
101 : cstr(cstr), value(value) {}
102
103 private:
104 BoundBuilder(const BoundBuilder &) = delete;
105 BoundBuilder &operator=(const BoundBuilder &) = delete;
106 bool operator==(const BoundBuilder &) = delete;
107 bool operator!=(const BoundBuilder &) = delete;
108
110 Value value;
111 std::optional<int64_t> dim;
112 };
113
114public:
115 static char ID;
116
117 /// A variable that can be added to the constraint set as a "column". The
118 /// value bounds infrastructure can compute bounds for variables and compare
119 /// two variables.
120 ///
121 /// Internally, a variable is represented as an affine map and operands.
122 class Variable {
123 public:
124 /// Construct a variable for an index-typed attribute or SSA value.
126
127 /// Construct a variable for an index-typed SSA value.
128 Variable(Value indexValue);
129
130 /// Construct a variable for a dimension of a shaped value.
131 Variable(Value shapedValue, int64_t dim);
132
133 /// Construct a variable for an index-typed attribute/SSA value or for a
134 /// dimension of a shaped value. A non-null dimension must be provided if
135 /// and only if `ofr` is a shaped value.
136 Variable(OpFoldResult ofr, std::optional<int64_t> dim);
137
138 /// Construct a variable for a map and its operands.
139 Variable(AffineMap map, ArrayRef<Variable> mapOperands);
140 Variable(AffineMap map, ValueRange mapOperands);
141
142 MLIRContext *getContext() const { return map.getContext(); }
143
144 /// Returns the affine map.
145 AffineMap getMap() const { return map; }
146
147 /// Returns the map operands.
148 ValueDimList &getOperands() { return mapOperands; }
149 const ValueDimList &getOperands() const { return mapOperands; }
150
151 private:
153 AffineMap map;
154 ValueDimList mapOperands;
155 };
156
157 /// The stop condition when traversing the backward slice of a shaped value/
158 /// index-type value. The traversal continues until the stop condition
159 /// evaluates to "true" for a value.
160 ///
161 /// The first parameter of the function is the shaped value/index-typed
162 /// value. The second parameter is the dimension in case of a shaped value.
163 /// The third parameter is this constraint set.
164 using StopConditionFn = std::function<bool(
165 Value, std::optional<int64_t> /*dim*/, ValueBoundsConstraintSet &cstr)>;
166
167 /// Compute a bound for the given variable. The computed bound is stored in
168 /// `resultMap`. The operands of the bound are stored in `mapOperands`. An
169 /// operand is either an index-type SSA value or a shaped value and a
170 /// dimension.
171 ///
172 /// The bound is computed in terms of values/dimensions for which
173 /// `stopCondition` evaluates to "true". To that end, the backward slice
174 /// (reverse use-def chain) of the given value is visited in a worklist-driven
175 /// manner and the constraint set is populated according to
176 /// `ValueBoundsOpInterface` for each visited value.
177 ///
178 /// By default, lower/equal bounds are closed and upper bounds are open. If
179 /// `closedUB` is set to "true", upper bounds are also closed.
180 static LogicalResult
181 computeBound(AffineMap &resultMap, ValueDimList &mapOperands,
182 presburger::BoundType type, const Variable &var,
183 StopConditionFn stopCondition, bool closedUB = false);
184
185 /// Compute a bound in terms of the values/dimensions in `dependencies`. The
186 /// computed bound consists of only constant terms and dependent values (or
187 /// dimension sizes thereof).
188 static LogicalResult
189 computeDependentBound(AffineMap &resultMap, ValueDimList &mapOperands,
190 presburger::BoundType type, const Variable &var,
191 ValueDimList dependencies, bool closedUB = false);
192
193 /// Compute a bound in that is independent of all values in `independencies`.
194 ///
195 /// Independencies are the opposite of dependencies. The computed bound does
196 /// not contain any SSA values that are part of `independencies`. E.g., this
197 /// function can be used to make ops hoistable from loops. To that end, ops
198 /// must be made independent of loop induction variables (in the case of "for"
199 /// loops). Loop induction variables are the independencies; they may not
200 /// appear in the computed bound.
201 static LogicalResult
202 computeIndependentBound(AffineMap &resultMap, ValueDimList &mapOperands,
203 presburger::BoundType type, const Variable &var,
204 ValueRange independencies, bool closedUB = false);
205
206 /// Compute a constant bound for the given variable.
207 ///
208 /// This function traverses the backward slice of the given operands in a
209 /// worklist-driven manner until `stopCondition` evaluates to "true". The
210 /// constraint set is populated according to `ValueBoundsOpInterface` for each
211 /// visited value. (No constraints are added for values for which the stop
212 /// condition evaluates to "true".)
213 ///
214 /// The stop condition is optional: If none is specified, the backward slice
215 /// is traversed in a breadth-first manner until a constant bound could be
216 /// computed.
217 ///
218 /// By default, lower/equal bounds are closed and upper bounds are open. If
219 /// `closedUB` is set to "true", upper bounds are also closed.
220 static FailureOr<int64_t>
222 const StopConditionFn &stopCondition = nullptr,
223 bool closedUB = false);
224
225 /// Compute a constant delta between the given two values. Return "failure"
226 /// if a constant delta could not be determined.
227 ///
228 /// `dim1`/`dim2` must be `nullopt` if and only if `value1`/`value2` are
229 /// index-typed.
230 static FailureOr<int64_t>
231 computeConstantDelta(Value value1, Value value2,
232 std::optional<int64_t> dim1 = std::nullopt,
233 std::optional<int64_t> dim2 = std::nullopt);
234
235 /// Traverse the IR starting from the given value/dim and populate constraints
236 /// as long as the stop condition holds. Also process all values/dims that are
237 /// already on the worklist.
238 void populateConstraints(Value value, std::optional<int64_t> dim);
239
240 /// Comparison operator for `ValueBoundsConstraintSet::compare`.
242
243 /// Populate constraints for lhs/rhs (until the stop condition is met). Then,
244 /// try to prove that, based on the current state of this constraint set
245 /// (i.e., without analyzing additional IR or adding new constraints), the
246 /// "lhs" value/dim is LE/LT/EQ/GT/GE than the "rhs" value/dim.
247 ///
248 /// Return "true" if the specified relation between the two values/dims was
249 /// proven to hold. Return "false" if the specified relation could not be
250 /// proven. This could be because the specified relation does in fact not hold
251 /// or because there is not enough information in the constraint set. In other
252 /// words, if we do not know for sure, this function returns "false".
253 bool populateAndCompare(const Variable &lhs, ComparisonOperator cmp,
254 const Variable &rhs);
255
256 /// Return "true" if "lhs cmp rhs" was proven to hold. Return "false" if the
257 /// specified relation could not be proven. This could be because the
258 /// specified relation does in fact not hold or because there is not enough
259 /// information in the constraint set. In other words, if we do not know for
260 /// sure, this function returns "false".
261 ///
262 /// This function keeps traversing the backward slice of lhs/rhs until could
263 /// prove the relation or until it ran out of IR.
264 static bool compare(const Variable &lhs, ComparisonOperator cmp,
265 const Variable &rhs);
266 /// This function is similar to `ValueBoundsConstraintSet::compare`, except
267 /// that it returns false if `!(lhs cmp rhs)`, and `failure` if neither the
268 /// relation nor its inverse relation could be proven.
269 static llvm::FailureOr<bool> strongCompare(const Variable &lhs,
271 const Variable &rhs);
272
273 /// Compute whether the given variables are equal. Return "failure" if
274 /// equality could not be determined.
275 static FailureOr<bool> areEqual(const Variable &var1, const Variable &var2);
276
277 /// Return "true" if the given slices are guaranteed to be overlapping.
278 /// Return "false" if the given slices are guaranteed to be non-overlapping.
279 /// Return "failure" if unknown.
280 ///
281 /// Slices are overlapping if for all dimensions:
282 /// * offset1 + size1 * stride1 <= offset2
283 /// * and offset2 + size2 * stride2 <= offset1
284 ///
285 /// Slice are non-overlapping if the above constraint is not satisfied for
286 /// at least one dimension.
287 static FailureOr<bool>
289 const HyperrectangularSlice &slice2);
290
291 /// Return "true" if the given slices are guaranteed to be equivalent.
292 /// Return "false" if the given slices are guaranteed to be non-equivalent.
293 /// Return "failure" if unknown.
294 ///
295 /// Slices are equivalent if their offsets, sizes and strices are equal.
296 static FailureOr<bool>
298 const HyperrectangularSlice &slice2);
299
300 /// Add a bound for the given index-typed value or shaped value. This function
301 /// returns a builder that adds the bound.
302 BoundBuilder bound(Value value) { return BoundBuilder(*this, value); }
303
304 /// Return an expression that represents the given index-typed value or shaped
305 /// value dimension. If this value/dimension was not used so far, it is added
306 /// to the worklist.
307 ///
308 /// `dim` must be `nullopt` if and only if the given value is of index type.
309 AffineExpr getExpr(Value value, std::optional<int64_t> dim = std::nullopt);
310
311 /// Return an expression that represents a constant or index-typed SSA value.
312 /// In case of a value, if this value was not used so far, it is added to the
313 /// worklist.
315
316 /// Return an expression that represents a constant.
317 AffineExpr getExpr(int64_t constant);
318
319 /// Debugging only: Dump the constraint set and the column-to-value/dim
320 /// mapping to llvm::errs.
321 void dump() const;
322
323protected:
324 /// Dimension identifier to indicate a value is index-typed. This is used for
325 /// internal data structures/API only.
326 static constexpr int64_t kIndexValue = -1;
327
328 /// An index-typed value or the dimension of a shaped-type value.
329 using ValueDim = std::pair<Value, int64_t>;
330
334
335 /// Return "true" if, based on the current state of the constraint system,
336 /// "lhs cmp rhs" was proven to hold. Return "false" if the specified relation
337 /// could not be proven. This could be because the specified relation does in
338 /// fact not hold or because there is not enough information in the constraint
339 /// set. In other words, if we do not know for sure, this function returns
340 /// "false".
341 ///
342 /// This function does not analyze any IR and does not populate any additional
343 /// constraints.
344 bool comparePos(int64_t lhsPos, ComparisonOperator cmp, int64_t rhsPos);
345
346 /// Return "true" if, based on the current state of the constraint system,
347 /// "lhs cmp rhs" was proven to hold. It returns "false" if "!(lhs cmp rhs)"
348 /// can be proven. Otherwise, it returns `failure` if neither the relation nor
349 /// its inverse relation could be proven.
350 ///
351 /// This function does not analyze any IR and does not populate any additional
352 /// constraints.
353 llvm::FailureOr<bool> strongComparePos(int64_t lhsPos, ComparisonOperator cmp,
354 int64_t rhsPos);
355
356 /// Given an affine map with a single result (and map operands), add a new
357 /// column to the constraint set that represents the result of the map.
358 /// Traverse additional IR starting from the map operands as needed (as long
359 /// as the stop condition is not satisfied). Also process all values/dims that
360 /// are already on the worklist. Return the position of the newly added
361 /// column.
363
364 /// Iteratively process all elements on the worklist until an index-typed
365 /// value or shaped value meets `stopCondition`. Such values are not processed
366 /// any further.
367 void processWorklist();
368
369 /// Bound the given column in the underlying constraint set by the given
370 /// expression.
371 void addBound(presburger::BoundType type, int64_t pos, AffineExpr expr);
372
373 /// Return the column position of the given value/dimension. Asserts that the
374 /// value/dimension exists in the constraint set.
375 int64_t getPos(Value value, std::optional<int64_t> dim = std::nullopt) const;
376
377 /// Return an affine expression that represents column `pos` in the constraint
378 /// set.
380
381 /// Return "true" if the given value/dim is mapped (i.e., has a corresponding
382 /// column in the constraint system).
383 bool isMapped(Value value, std::optional<int64_t> dim = std::nullopt) const;
384
385 /// Insert a value/dimension into the constraint set. If `isSymbol` is set to
386 /// "false", a dimension is added. The value/dimension is added to the
387 /// worklist if `addToWorklist` is set.
388 ///
389 /// Note: There are certain affine restrictions wrt. dimensions. E.g., they
390 /// cannot be multiplied. Furthermore, bounds can only be queried for
391 /// dimensions but not for symbols.
392 int64_t insert(Value value, std::optional<int64_t> dim, bool isSymbol = true,
393 bool addToWorklist = true);
394
395 /// Insert an anonymous column into the constraint set. The column is not
396 /// bound to any value/dimension. If `isSymbol` is set to "false", a dimension
397 /// is added.
398 ///
399 /// Note: There are certain affine restrictions wrt. dimensions. E.g., they
400 /// cannot be multiplied. Furthermore, bounds can only be queried for
401 /// dimensions but not for symbols.
402 int64_t insert(bool isSymbol = true);
403
404 /// Insert the given affine map and its bound operands as a new column in the
405 /// constraint system. Return the position of the new column. Any operands
406 /// that were not analyzed yet are put on the worklist.
407 int64_t insert(AffineMap map, const ValueDimList &operands,
408 bool isSymbol = true);
409 int64_t insert(const Variable &var, bool isSymbol = true);
410
411 /// Project out the given column in the constraint set.
412 void projectOut(int64_t pos);
413
414 /// Project out all columns for which the condition holds.
415 void projectOut(function_ref<bool(ValueDim)> condition);
416
417 void projectOutAnonymous(std::optional<int64_t> except = std::nullopt);
418
419 /// Mapping of columns to values/shape dimensions.
420 // Inline size chosen empirically based on compilation profiling.
421 // Profiled: 2.1M calls, avg=3.0+-1.9. N=4 covers ~70% of cases inline.
423 /// Reverse mapping of values/shape dimensions to columns.
425
426 /// Worklist of values/shape dimensions that have not been processed yet.
427 std::queue<int64_t> worklist;
428
429 /// Constraint system of equalities and inequalities.
431
432 /// Builder for constructing affine expressions.
434
435 /// The current stop condition function.
437
438 /// Should conservative bounds be added for semi-affine expressions.
440};
441
442} // namespace mlir
443
444#include "mlir/Interfaces/ValueBoundsOpInterface.h.inc"
445
446#endif // MLIR_INTERFACES_VALUEBOUNDSOPINTERFACE_H_
lhs
Base type for affine expression.
Definition AffineExpr.h:68
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
FlatLinearConstraints is an extension of IntegerPolyhedron.
A hyperrectangular slice, represented as a list of offsets, sizes and strides.
HyperrectangularSlice(ArrayRef< OpFoldResult > offsets, ArrayRef< OpFoldResult > sizes, ArrayRef< OpFoldResult > strides)
ArrayRef< OpFoldResult > getMixedStrides() const
ArrayRef< OpFoldResult > getMixedSizes() const
ArrayRef< OpFoldResult > getMixedOffsets() const
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
This class represents a single result from folding an operation.
Helper class that builds a bound for a shaped value dimension or index-typed value.
BoundBuilder(ValueBoundsConstraintSet &cstr, Value value)
BoundBuilder & operator[](int64_t dim)
Specify a dimension, assuming that the underlying value is a shaped value.
A variable that can be added to the constraint set as a "column".
ValueDimList & getOperands()
Returns the map operands.
Variable(OpFoldResult ofr)
Construct a variable for an index-typed attribute or SSA value.
AffineMap getMap() const
Returns the affine map.
static bool compare(const Variable &lhs, ComparisonOperator cmp, const Variable &rhs)
Return "true" if "lhs cmp rhs" was proven to hold.
static FailureOr< bool > areEqual(const Variable &var1, const Variable &var2)
Compute whether the given variables are equal.
DenseMap< ValueDim, int64_t > valueDimToPosition
Reverse mapping of values/shape dimensions to columns.
void processWorklist()
Iteratively process all elements on the worklist until an index-typed value or shaped value meets sto...
bool addConservativeSemiAffineBounds
Should conservative bounds be added for semi-affine expressions.
AffineExpr getExpr(Value value, std::optional< int64_t > dim=std::nullopt)
Return an expression that represents the given index-typed value or shaped value dimension.
static LogicalResult computeIndependentBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, const Variable &var, ValueRange independencies, bool closedUB=false)
Compute a bound in that is independent of all values in independencies.
static FailureOr< bool > areEquivalentSlices(MLIRContext *ctx, const HyperrectangularSlice &slice1, const HyperrectangularSlice &slice2)
Return "true" if the given slices are guaranteed to be equivalent.
void projectOut(int64_t pos)
Project out the given column in the constraint set.
std::function< bool( Value, std::optional< int64_t >, ValueBoundsConstraintSet &cstr)> StopConditionFn
The stop condition when traversing the backward slice of a shaped value/ index-type value.
ValueBoundsConstraintSet(MLIRContext *ctx, const StopConditionFn &stopCondition, bool addConservativeSemiAffineBounds=false)
static FailureOr< int64_t > computeConstantDelta(Value value1, Value value2, std::optional< int64_t > dim1=std::nullopt, std::optional< int64_t > dim2=std::nullopt)
Compute a constant delta between the given two values.
static llvm::FailureOr< bool > strongCompare(const Variable &lhs, ComparisonOperator cmp, const Variable &rhs)
This function is similar to ValueBoundsConstraintSet::compare, except that it returns false if !...
void addBound(presburger::BoundType type, int64_t pos, AffineExpr expr)
Bound the given column in the underlying constraint set by the given expression.
StopConditionFn stopCondition
The current stop condition function.
ComparisonOperator
Comparison operator for ValueBoundsConstraintSet::compare.
BoundBuilder bound(Value value)
Add a bound for the given index-typed value or shaped value.
static LogicalResult computeBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, const Variable &var, StopConditionFn stopCondition, bool closedUB=false)
Compute a bound for the given variable.
int64_t getPos(Value value, std::optional< int64_t > dim=std::nullopt) const
Return the column position of the given value/dimension.
int64_t insert(Value value, std::optional< int64_t > dim, bool isSymbol=true, bool addToWorklist=true)
Insert a value/dimension into the constraint set.
bool comparePos(int64_t lhsPos, ComparisonOperator cmp, int64_t rhsPos)
Return "true" if, based on the current state of the constraint system, "lhs cmp rhs" was proven to ho...
SmallVector< std::optional< ValueDim >, 4 > positionToValueDim
Mapping of columns to values/shape dimensions.
void dump() const
Debugging only: Dump the constraint set and the column-to-value/dim mapping to llvm::errs.
std::queue< int64_t > worklist
Worklist of values/shape dimensions that have not been processed yet.
FlatLinearConstraints cstr
Constraint system of equalities and inequalities.
bool isMapped(Value value, std::optional< int64_t > dim=std::nullopt) const
Return "true" if the given value/dim is mapped (i.e., has a corresponding column in the constraint sy...
llvm::FailureOr< bool > strongComparePos(int64_t lhsPos, ComparisonOperator cmp, int64_t rhsPos)
Return "true" if, based on the current state of the constraint system, "lhs cmp rhs" was proven to ho...
AffineExpr getPosExpr(int64_t pos)
Return an affine expression that represents column pos in the constraint set.
void projectOutAnonymous(std::optional< int64_t > except=std::nullopt)
static FailureOr< bool > areOverlappingSlices(MLIRContext *ctx, const HyperrectangularSlice &slice1, const HyperrectangularSlice &slice2)
Return "true" if the given slices are guaranteed to be overlapping.
std::pair< Value, int64_t > ValueDim
An index-typed value or the dimension of a shaped-type value.
void populateConstraints(Value value, std::optional< int64_t > dim)
Traverse the IR starting from the given value/dim and populate constraints as long as the stop condit...
Builder builder
Builder for constructing affine expressions.
bool populateAndCompare(const Variable &lhs, ComparisonOperator cmp, const Variable &rhs)
Populate constraints for lhs/rhs (until the stop condition is met).
static FailureOr< int64_t > computeConstantBound(presburger::BoundType type, const Variable &var, const StopConditionFn &stopCondition=nullptr, bool closedUB=false)
Compute a constant bound for the given variable.
static constexpr int64_t kIndexValue
Dimension identifier to indicate a value is index-typed.
static LogicalResult computeDependentBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, const Variable &var, ValueDimList dependencies, bool closedUB=false)
Compute a bound in terms of the values/dimensions in dependencies.
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
BoundType
The type of bound: equal, lower bound or upper bound.
Include the generated interface declarations.
bool operator!=(RegionBranchPoint lhs, RegionBranchPoint rhs)
SmallVector< std::pair< Value, std::optional< int64_t > >, 2 > ValueDimList
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147