MLIR  21.0.0git
SparseAnalysis.h
Go to the documentation of this file.
1 //===- SparseAnalysis.h - Sparse data-flow analysis -----------------------===//
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 implements sparse data-flow analysis using the data-flow analysis
10 // framework. The analysis is forward and conditional and uses the results of
11 // dead code analysis to prune dead code during the analysis.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef MLIR_ANALYSIS_DATAFLOW_SPARSEANALYSIS_H
16 #define MLIR_ANALYSIS_DATAFLOW_SPARSEANALYSIS_H
17 
19 #include "mlir/IR/SymbolTable.h"
22 #include "llvm/ADT/SmallPtrSet.h"
23 
24 namespace mlir {
25 namespace dataflow {
26 
27 //===----------------------------------------------------------------------===//
28 // AbstractSparseLattice
29 //===----------------------------------------------------------------------===//
30 
31 /// This class represents an abstract lattice. A lattice contains information
32 /// about an SSA value and is what's propagated across the IR by sparse
33 /// data-flow analysis.
35 public:
36  /// Lattices can only be created for values.
38 
39  /// Return the value this lattice is located at.
40  Value getAnchor() const { return cast<Value>(AnalysisState::getAnchor()); }
41 
42  /// Join the information contained in 'rhs' into this lattice. Returns
43  /// if the value of the lattice changed.
44  virtual ChangeResult join(const AbstractSparseLattice &rhs) {
46  }
47 
48  /// Meet (intersect) the information in this lattice with 'rhs'. Returns
49  /// if the value of the lattice changed.
50  virtual ChangeResult meet(const AbstractSparseLattice &rhs) {
52  }
53 
54  /// When the lattice gets updated, propagate an update to users of the value
55  /// using its use-def chain to subscribed analyses.
56  void onUpdate(DataFlowSolver *solver) const override;
57 
58  /// Subscribe an analysis to updates of the lattice. When the lattice changes,
59  /// subscribed analyses are re-invoked on all users of the value. This is
60  /// more efficient than relying on the dependency map.
62  useDefSubscribers.insert(analysis);
63  }
64 
65 private:
66  /// A set of analyses that should be updated when this lattice changes.
69  useDefSubscribers;
70 };
71 
72 //===----------------------------------------------------------------------===//
73 // Lattice
74 //===----------------------------------------------------------------------===//
75 
76 /// This class represents a lattice holding a specific value of type `ValueT`.
77 /// Lattice values (`ValueT`) are required to adhere to the following:
78 ///
79 /// * static ValueT join(const ValueT &lhs, const ValueT &rhs);
80 /// - This method conservatively joins the information held by `lhs`
81 /// and `rhs` into a new value. This method is required to be monotonic.
82 /// * bool operator==(const ValueT &rhs) const;
83 ///
84 template <typename ValueT>
86 public:
88 
89  /// Return the value this lattice is located at.
90  Value getAnchor() const { return cast<Value>(anchor); }
91 
92  /// Return the value held by this lattice. This requires that the value is
93  /// initialized.
94  ValueT &getValue() { return value; }
95  const ValueT &getValue() const {
96  return const_cast<Lattice<ValueT> *>(this)->getValue();
97  }
98 
100 
101  /// Join the information contained in the 'rhs' lattice into this
102  /// lattice. Returns if the state of the current lattice changed.
103  ChangeResult join(const AbstractSparseLattice &rhs) override {
104  return join(static_cast<const LatticeT &>(rhs).getValue());
105  }
106 
107  /// Meet (intersect) the information contained in the 'rhs' lattice with
108  /// this lattice. Returns if the state of the current lattice changed.
109  ChangeResult meet(const AbstractSparseLattice &rhs) override {
110  return meet(static_cast<const LatticeT &>(rhs).getValue());
111  }
112 
113  /// Join the information contained in the 'rhs' value into this
114  /// lattice. Returns if the state of the current lattice changed.
115  ChangeResult join(const ValueT &rhs) {
116  // Otherwise, join rhs with the current optimistic value.
117  ValueT newValue = ValueT::join(value, rhs);
118  assert(ValueT::join(newValue, value) == newValue &&
119  "expected `join` to be monotonic");
120  assert(ValueT::join(newValue, rhs) == newValue &&
121  "expected `join` to be monotonic");
122 
123  // Update the current optimistic value if something changed.
124  if (newValue == value)
125  return ChangeResult::NoChange;
126 
127  value = newValue;
128  return ChangeResult::Change;
129  }
130 
131  /// Trait to check if `T` provides a `meet` method. Needed since for forward
132  /// analysis, lattices will only have a `join`, no `meet`, but we want to use
133  /// the same `Lattice` class for both directions.
134  template <typename T, typename... Args>
135  using has_meet = decltype(&T::meet);
136  template <typename T>
137  using lattice_has_meet = llvm::is_detected<has_meet, T>;
138 
139  /// Meet (intersect) the information contained in the 'rhs' value with this
140  /// lattice. Returns if the state of the current lattice changed. If the
141  /// lattice elements don't have a `meet` method, this is a no-op (see below.)
142  template <typename VT,
143  std::enable_if_t<lattice_has_meet<VT>::value> * = nullptr>
144  ChangeResult meet(const VT &rhs) {
145  ValueT newValue = ValueT::meet(value, rhs);
146  assert(ValueT::meet(newValue, value) == newValue &&
147  "expected `meet` to be monotonic");
148  assert(ValueT::meet(newValue, rhs) == newValue &&
149  "expected `meet` to be monotonic");
150 
151  // Update the current optimistic value if something changed.
152  if (newValue == value)
153  return ChangeResult::NoChange;
154 
155  value = newValue;
156  return ChangeResult::Change;
157  }
158 
159  template <typename VT,
160  std::enable_if_t<!lattice_has_meet<VT>::value> * = nullptr>
161  ChangeResult meet(const VT &rhs) {
162  return ChangeResult::NoChange;
163  }
164 
165  /// Print the lattice element.
166  void print(raw_ostream &os) const override { value.print(os); }
167 
168 private:
169  /// The currently computed value that is optimistically assumed to be true.
170  ValueT value;
171 };
172 
173 //===----------------------------------------------------------------------===//
174 // AbstractSparseForwardDataFlowAnalysis
175 //===----------------------------------------------------------------------===//
176 
177 /// Base class for sparse forward data-flow analyses. A sparse analysis
178 /// implements a transfer function on operations from the lattices of the
179 /// operands to the lattices of the results. This analysis will propagate
180 /// lattices across control-flow edges and the callgraph using liveness
181 /// information.
182 ///
183 /// Visit a program point in sparse forward data-flow analysis will invoke the
184 /// transfer function of the operation preceding the program point iterator.
185 /// Visit a program point at the begining of block will visit the block itself.
187 public:
188  /// Initialize the analysis by visiting every owner of an SSA value: all
189  /// operations and blocks.
190  LogicalResult initialize(Operation *top) override;
191 
192  /// Visit a program point. If this is at beginning of block and all
193  /// control-flow predecessors or callsites are known, then the arguments
194  /// lattices are propagated from them. If this is after call operation or an
195  /// operation with region control-flow, then its result lattices are set
196  /// accordingly. Otherwise, the operation transfer function is invoked.
197  LogicalResult visit(ProgramPoint *point) override;
198 
199 protected:
201 
202  /// The operation transfer function. Given the operand lattices, this
203  /// function is expected to set the result lattices.
204  virtual LogicalResult
207  ArrayRef<AbstractSparseLattice *> resultLattices) = 0;
208 
209  /// The transfer function for calls to external functions.
210  virtual void visitExternalCallImpl(
211  CallOpInterface call,
213  ArrayRef<AbstractSparseLattice *> resultLattices) = 0;
214 
215  /// Given an operation with region control-flow, the lattices of the operands,
216  /// and a region successor, compute the lattice values for block arguments
217  /// that are not accounted for by the branching control flow (ex. the bounds
218  /// of loops).
220  Operation *op, const RegionSuccessor &successor,
221  ArrayRef<AbstractSparseLattice *> argLattices, unsigned firstIndex) = 0;
222 
223  /// Get the lattice element of a value.
225 
226  /// Get a read-only lattice element for a value and add it as a dependency to
227  /// a program point.
229  Value value);
230 
231  /// Set the given lattice element(s) at control flow entry point(s).
232  virtual void setToEntryState(AbstractSparseLattice *lattice) = 0;
234 
235  /// Join the lattice element and propagate and update if it changed.
236  void join(AbstractSparseLattice *lhs, const AbstractSparseLattice &rhs);
237 
238 private:
239  /// Recursively initialize the analysis on nested operations and blocks.
240  LogicalResult initializeRecursively(Operation *op);
241 
242  /// Visit an operation. If this is a call operation or an operation with
243  /// region control-flow, then its result lattices are set accordingly.
244  /// Otherwise, the operation transfer function is invoked.
245  LogicalResult visitOperation(Operation *op);
246 
247  /// Visit a block to compute the lattice values of its arguments. If this is
248  /// an entry block, then the argument values are determined from the block's
249  /// "predecessors" as set by `PredecessorState`. The predecessors can be
250  /// region terminators or callable callsites. Otherwise, the values are
251  /// determined from block predecessors.
252  void visitBlock(Block *block);
253 
254  /// Visit a program point `point` with predecessors within a region branch
255  /// operation `branch`, which can either be the entry block of one of the
256  /// regions or the parent operation itself, and set either the argument or
257  /// parent result lattices.
258  /// This method can be overridden to control precisely how the region
259  /// successors of `branch` are visited. For example in order to precisely
260  /// control the order in which predecessor operand lattices are propagated
261  /// from. An override is responsible for visiting all the known predecessors
262  /// and propagating therefrom.
263  virtual void
264  visitRegionSuccessors(ProgramPoint *point, RegionBranchOpInterface branch,
265  RegionBranchPoint successor,
267 };
268 
269 //===----------------------------------------------------------------------===//
270 // SparseForwardDataFlowAnalysis
271 //===----------------------------------------------------------------------===//
272 
273 /// A sparse forward data-flow analysis for propagating SSA value lattices
274 /// across the IR by implementing transfer functions for operations.
275 ///
276 /// `StateT` is expected to be a subclass of `AbstractSparseLattice`.
277 template <typename StateT>
280  static_assert(
281  std::is_base_of<AbstractSparseLattice, StateT>::value,
282  "analysis state class expected to subclass AbstractSparseLattice");
283 
284 public:
287 
288  /// Visit an operation with the lattices of its operands. This function is
289  /// expected to set the lattices of the operation's results.
290  virtual LogicalResult visitOperation(Operation *op,
291  ArrayRef<const StateT *> operands,
292  ArrayRef<StateT *> results) = 0;
293 
294  /// Visit a call operation to an externally defined function given the
295  /// lattices of its arguments.
296  virtual void visitExternalCall(CallOpInterface call,
297  ArrayRef<const StateT *> argumentLattices,
298  ArrayRef<StateT *> resultLattices) {
299  setAllToEntryStates(resultLattices);
300  }
301 
302  /// Given an operation with possible region control-flow, the lattices of the
303  /// operands, and a region successor, compute the lattice values for block
304  /// arguments that are not accounted for by the branching control flow (ex.
305  /// the bounds of loops). By default, this method marks all such lattice
306  /// elements as having reached a pessimistic fixpoint. `firstIndex` is the
307  /// index of the first element of `argLattices` that is set by control-flow.
309  const RegionSuccessor &successor,
310  ArrayRef<StateT *> argLattices,
311  unsigned firstIndex) {
312  setAllToEntryStates(argLattices.take_front(firstIndex));
313  setAllToEntryStates(argLattices.drop_front(
314  firstIndex + successor.getSuccessorInputs().size()));
315  }
316 
317 protected:
318  /// Get the lattice element for a value.
319  StateT *getLatticeElement(Value value) override {
320  return getOrCreate<StateT>(value);
321  }
322 
323  /// Get the lattice element for a value and create a dependency on the
324  /// provided program point.
325  const StateT *getLatticeElementFor(ProgramPoint *point, Value value) {
326  return static_cast<const StateT *>(
328  value));
329  }
330 
331  /// Set the given lattice element(s) at control flow entry point(s).
332  virtual void setToEntryState(StateT *lattice) = 0;
335  {reinterpret_cast<AbstractSparseLattice *const *>(lattices.begin()),
336  lattices.size()});
337  }
338 
339 private:
340  /// Type-erased wrappers that convert the abstract lattice operands to derived
341  /// lattices and invoke the virtual hooks operating on the derived lattices.
342  LogicalResult visitOperationImpl(
344  ArrayRef<AbstractSparseLattice *> resultLattices) override {
345  return visitOperation(
346  op,
347  {reinterpret_cast<const StateT *const *>(operandLattices.begin()),
348  operandLattices.size()},
349  {reinterpret_cast<StateT *const *>(resultLattices.begin()),
350  resultLattices.size()});
351  }
352  void visitExternalCallImpl(
353  CallOpInterface call,
354  ArrayRef<const AbstractSparseLattice *> argumentLattices,
355  ArrayRef<AbstractSparseLattice *> resultLattices) override {
357  call,
358  {reinterpret_cast<const StateT *const *>(argumentLattices.begin()),
359  argumentLattices.size()},
360  {reinterpret_cast<StateT *const *>(resultLattices.begin()),
361  resultLattices.size()});
362  }
363  void visitNonControlFlowArgumentsImpl(
364  Operation *op, const RegionSuccessor &successor,
365  ArrayRef<AbstractSparseLattice *> argLattices,
366  unsigned firstIndex) override {
368  op, successor,
369  {reinterpret_cast<StateT *const *>(argLattices.begin()),
370  argLattices.size()},
371  firstIndex);
372  }
373  void setToEntryState(AbstractSparseLattice *lattice) override {
374  return setToEntryState(reinterpret_cast<StateT *>(lattice));
375  }
376 };
377 
378 //===----------------------------------------------------------------------===//
379 // AbstractSparseBackwardDataFlowAnalysis
380 //===----------------------------------------------------------------------===//
381 
382 /// Base class for sparse backward data-flow analyses. Similar to
383 /// AbstractSparseForwardDataFlowAnalysis, but walks bottom to top.
385 public:
386  /// Initialize the analysis by visiting the operation and everything nested
387  /// under it.
388  LogicalResult initialize(Operation *top) override;
389 
390  /// Visit a program point. If it is after call operation or an operation with
391  /// block or region control-flow, then operand lattices are set accordingly.
392  /// Otherwise, invokes the operation transfer function (`visitOperationImpl`).
393  LogicalResult visit(ProgramPoint *point) override;
394 
395 protected:
397  DataFlowSolver &solver, SymbolTableCollection &symbolTable);
398 
399  /// The operation transfer function. Given the result lattices, this
400  /// function is expected to set the operand lattices.
401  virtual LogicalResult visitOperationImpl(
402  Operation *op, ArrayRef<AbstractSparseLattice *> operandLattices,
403  ArrayRef<const AbstractSparseLattice *> resultLattices) = 0;
404 
405  /// The transfer function for calls to external functions.
406  virtual void visitExternalCallImpl(
407  CallOpInterface call, ArrayRef<AbstractSparseLattice *> operandLattices,
408  ArrayRef<const AbstractSparseLattice *> resultLattices) = 0;
409 
410  // Visit operands on branch instructions that are not forwarded.
411  virtual void visitBranchOperand(OpOperand &operand) = 0;
412 
413  // Visit operands on call instructions that are not forwarded.
414  virtual void visitCallOperand(OpOperand &operand) = 0;
415 
416  /// Set the given lattice element(s) at control flow exit point(s).
417  virtual void setToExitState(AbstractSparseLattice *lattice) = 0;
418 
419  /// Set the given lattice element(s) at control flow exit point(s).
421 
422  /// Get the lattice element for a value.
424 
425  /// Get the lattice elements for a range of values.
427 
428  /// Join the lattice element and propagate and update if it changed.
429  void meet(AbstractSparseLattice *lhs, const AbstractSparseLattice &rhs);
430 
431 private:
432  /// Recursively initialize the analysis on nested operations and blocks.
433  LogicalResult initializeRecursively(Operation *op);
434 
435  /// Visit an operation. If this is a call operation or an operation with
436  /// region control-flow, then its operand lattices are set accordingly.
437  /// Otherwise, the operation transfer function is invoked.
438  LogicalResult visitOperation(Operation *op);
439 
440  /// Visit a block.
441  void visitBlock(Block *block);
442 
443  /// Visit an op with regions (like e.g. `scf.while`)
444  void visitRegionSuccessors(RegionBranchOpInterface branch,
446 
447  /// Visit a `RegionBranchTerminatorOpInterface` to compute the lattice values
448  /// of its operands, given its parent op `branch`. The lattice value of an
449  /// operand is determined based on the corresponding arguments in
450  /// `terminator`'s region successor(s).
451  void visitRegionSuccessorsFromTerminator(
452  RegionBranchTerminatorOpInterface terminator,
453  RegionBranchOpInterface branch);
454 
455  /// Get the lattice element for a value, and also set up
456  /// dependencies so that the analysis on the given ProgramPoint is re-invoked
457  /// if the value changes.
458  const AbstractSparseLattice *getLatticeElementFor(ProgramPoint *point,
459  Value value);
460 
461  /// Get the lattice elements for a range of values, and also set up
462  /// dependencies so that the analysis on the given ProgramPoint is re-invoked
463  /// if any of the values change.
465  getLatticeElementsFor(ProgramPoint *point, ValueRange values);
466 
467  SymbolTableCollection &symbolTable;
468 };
469 
470 //===----------------------------------------------------------------------===//
471 // SparseBackwardDataFlowAnalysis
472 //===----------------------------------------------------------------------===//
473 
474 /// A sparse (backward) data-flow analysis for propagating SSA value lattices
475 /// backwards across the IR by implementing transfer functions for operations.
476 ///
477 /// `StateT` is expected to be a subclass of `AbstractSparseLattice`.
478 ///
479 /// Visit a program point in sparse backward data-flow analysis will invoke the
480 /// transfer function of the operation preceding the program point iterator.
481 /// Visit a program point at the begining of block will visit the block itself.
482 template <typename StateT>
485 public:
487  SymbolTableCollection &symbolTable)
488  : AbstractSparseBackwardDataFlowAnalysis(solver, symbolTable) {}
489 
490  /// Visit an operation with the lattices of its results. This function is
491  /// expected to set the lattices of the operation's operands.
492  virtual LogicalResult visitOperation(Operation *op,
493  ArrayRef<StateT *> operands,
494  ArrayRef<const StateT *> results) = 0;
495 
496  /// Visit a call to an external function. This function is expected to set
497  /// lattice values of the call operands. By default, calls `visitCallOperand`
498  /// for all operands.
499  virtual void visitExternalCall(CallOpInterface call,
500  ArrayRef<StateT *> argumentLattices,
501  ArrayRef<const StateT *> resultLattices) {
502  (void)argumentLattices;
503  (void)resultLattices;
504  for (OpOperand &operand : call->getOpOperands()) {
505  visitCallOperand(operand);
506  }
507  };
508 
509 protected:
510  /// Get the lattice element for a value.
511  StateT *getLatticeElement(Value value) override {
512  return getOrCreate<StateT>(value);
513  }
514 
515  /// Set the given lattice element(s) at control flow exit point(s).
516  virtual void setToExitState(StateT *lattice) = 0;
517  void setToExitState(AbstractSparseLattice *lattice) override {
518  return setToExitState(reinterpret_cast<StateT *>(lattice));
519  }
522  {reinterpret_cast<AbstractSparseLattice *const *>(lattices.begin()),
523  lattices.size()});
524  }
525 
526 private:
527  /// Type-erased wrappers that convert the abstract lattice operands to derived
528  /// lattices and invoke the virtual hooks operating on the derived lattices.
529  LogicalResult visitOperationImpl(
530  Operation *op, ArrayRef<AbstractSparseLattice *> operandLattices,
531  ArrayRef<const AbstractSparseLattice *> resultLattices) override {
532  return visitOperation(
533  op,
534  {reinterpret_cast<StateT *const *>(operandLattices.begin()),
535  operandLattices.size()},
536  {reinterpret_cast<const StateT *const *>(resultLattices.begin()),
537  resultLattices.size()});
538  }
539 
540  void visitExternalCallImpl(
541  CallOpInterface call, ArrayRef<AbstractSparseLattice *> operandLattices,
542  ArrayRef<const AbstractSparseLattice *> resultLattices) override {
544  call,
545  {reinterpret_cast<StateT *const *>(operandLattices.begin()),
546  operandLattices.size()},
547  {reinterpret_cast<const StateT *const *>(resultLattices.begin()),
548  resultLattices.size()});
549  }
550 };
551 
552 } // end namespace dataflow
553 } // end namespace mlir
554 
555 #endif // MLIR_ANALYSIS_DATAFLOW_SPARSEANALYSIS_H
Base class for generic analysis states.
LatticeAnchor getAnchor() const
Returns the lattice anchor this state is located at.
LatticeAnchor anchor
The lattice anchor to which the state belongs.
Block represents an ordered list of Operations.
Definition: Block.h:33
Base class for all data-flow analyses.
The general data-flow analysis solver.
This class represents an operand of an operation.
Definition: Value.h:267
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
This class represents a successor of a region.
ValueRange getSuccessorInputs() const
Return the inputs to the successor that are remapped by the exit values of the current region.
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:283
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Base class for sparse backward data-flow analyses.
virtual void setToExitState(AbstractSparseLattice *lattice)=0
Set the given lattice element(s) at control flow exit point(s).
SmallVector< AbstractSparseLattice * > getLatticeElements(ValueRange values)
Get the lattice elements for a range of values.
AbstractSparseBackwardDataFlowAnalysis(DataFlowSolver &solver, SymbolTableCollection &symbolTable)
virtual void visitBranchOperand(OpOperand &operand)=0
virtual void visitCallOperand(OpOperand &operand)=0
LogicalResult visit(ProgramPoint *point) override
Visit a program point.
void meet(AbstractSparseLattice *lhs, const AbstractSparseLattice &rhs)
Join the lattice element and propagate and update if it changed.
virtual void visitExternalCallImpl(CallOpInterface call, ArrayRef< AbstractSparseLattice * > operandLattices, ArrayRef< const AbstractSparseLattice * > resultLattices)=0
The transfer function for calls to external functions.
virtual AbstractSparseLattice * getLatticeElement(Value value)=0
Get the lattice element for a value.
LogicalResult initialize(Operation *top) override
Initialize the analysis by visiting the operation and everything nested under it.
void setAllToExitStates(ArrayRef< AbstractSparseLattice * > lattices)
Set the given lattice element(s) at control flow exit point(s).
virtual LogicalResult visitOperationImpl(Operation *op, ArrayRef< AbstractSparseLattice * > operandLattices, ArrayRef< const AbstractSparseLattice * > resultLattices)=0
The operation transfer function.
Base class for sparse forward data-flow analyses.
LogicalResult visit(ProgramPoint *point) override
Visit a program point.
LogicalResult initialize(Operation *top) override
Initialize the analysis by visiting every owner of an SSA value: all operations and blocks.
virtual AbstractSparseLattice * getLatticeElement(Value value)=0
Get the lattice element of a value.
virtual void visitExternalCallImpl(CallOpInterface call, ArrayRef< const AbstractSparseLattice * > argumentLattices, ArrayRef< AbstractSparseLattice * > resultLattices)=0
The transfer function for calls to external functions.
void setAllToEntryStates(ArrayRef< AbstractSparseLattice * > lattices)
virtual void setToEntryState(AbstractSparseLattice *lattice)=0
Set the given lattice element(s) at control flow entry point(s).
const AbstractSparseLattice * getLatticeElementFor(ProgramPoint *point, Value value)
Get a read-only lattice element for a value and add it as a dependency to a program point.
virtual void visitNonControlFlowArgumentsImpl(Operation *op, const RegionSuccessor &successor, ArrayRef< AbstractSparseLattice * > argLattices, unsigned firstIndex)=0
Given an operation with region control-flow, the lattices of the operands, and a region successor,...
virtual LogicalResult visitOperationImpl(Operation *op, ArrayRef< const AbstractSparseLattice * > operandLattices, ArrayRef< AbstractSparseLattice * > resultLattices)=0
The operation transfer function.
void join(AbstractSparseLattice *lhs, const AbstractSparseLattice &rhs)
Join the lattice element and propagate and update if it changed.
This class represents an abstract lattice.
void onUpdate(DataFlowSolver *solver) const override
When the lattice gets updated, propagate an update to users of the value using its use-def chain to s...
virtual ChangeResult join(const AbstractSparseLattice &rhs)
Join the information contained in 'rhs' into this lattice.
virtual ChangeResult meet(const AbstractSparseLattice &rhs)
Meet (intersect) the information in this lattice with 'rhs'.
Value getAnchor() const
Return the value this lattice is located at.
void useDefSubscribe(DataFlowAnalysis *analysis)
Subscribe an analysis to updates of the lattice.
AbstractSparseLattice(Value value)
Lattices can only be created for values.
This class represents a lattice holding a specific value of type ValueT.
ChangeResult join(const ValueT &rhs)
Join the information contained in the 'rhs' value into this lattice.
Value getAnchor() const
Return the value this lattice is located at.
void print(raw_ostream &os) const override
Print the lattice element.
ChangeResult meet(const VT &rhs)
Meet (intersect) the information contained in the 'rhs' value with this lattice.
decltype(&T::meet) has_meet
Trait to check if T provides a meet method.
const ValueT & getValue() const
ValueT & getValue()
Return the value held by this lattice.
llvm::is_detected< has_meet, T > lattice_has_meet
ChangeResult join(const AbstractSparseLattice &rhs) override
Join the information contained in the 'rhs' lattice into this lattice.
ChangeResult meet(const AbstractSparseLattice &rhs) override
Meet (intersect) the information contained in the 'rhs' lattice with this lattice.
A sparse (backward) data-flow analysis for propagating SSA value lattices backwards across the IR by ...
StateT * getLatticeElement(Value value) override
Get the lattice element for a value.
void setAllToExitStates(ArrayRef< StateT * > lattices)
virtual void visitExternalCall(CallOpInterface call, ArrayRef< StateT * > argumentLattices, ArrayRef< const StateT * > resultLattices)
Visit a call to an external function.
void setToExitState(AbstractSparseLattice *lattice) override
Set the given lattice element(s) at control flow exit point(s).
SparseBackwardDataFlowAnalysis(DataFlowSolver &solver, SymbolTableCollection &symbolTable)
virtual void setToExitState(StateT *lattice)=0
Set the given lattice element(s) at control flow exit point(s).
virtual LogicalResult visitOperation(Operation *op, ArrayRef< StateT * > operands, ArrayRef< const StateT * > results)=0
Visit an operation with the lattices of its results.
A sparse forward data-flow analysis for propagating SSA value lattices across the IR by implementing ...
const StateT * getLatticeElementFor(ProgramPoint *point, Value value)
Get the lattice element for a value and create a dependency on the provided program point.
virtual LogicalResult visitOperation(Operation *op, ArrayRef< const StateT * > operands, ArrayRef< StateT * > results)=0
Visit an operation with the lattices of its operands.
virtual void visitExternalCall(CallOpInterface call, ArrayRef< const StateT * > argumentLattices, ArrayRef< StateT * > resultLattices)
Visit a call operation to an externally defined function given the lattices of its arguments.
StateT * getLatticeElement(Value value) override
Get the lattice element for a value.
virtual void setToEntryState(StateT *lattice)=0
Set the given lattice element(s) at control flow entry point(s).
void setAllToEntryStates(ArrayRef< StateT * > lattices)
virtual void visitNonControlFlowArguments(Operation *op, const RegionSuccessor &successor, ArrayRef< StateT * > argLattices, unsigned firstIndex)
Given an operation with possible region control-flow, the lattices of the operands,...
SparseForwardDataFlowAnalysis(DataFlowSolver &solver)
Include the generated interface declarations.
ChangeResult
A result type used to indicate if a change happened.
Program point represents a specific location in the execution of a program.