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) and
417  /// propagate the update if it chaned.
418  virtual void setToExitState(AbstractSparseLattice *lattice) = 0;
419 
420  /// Set the given lattice element(s) at control flow exit point(s) and
421  /// propagate the update if it chaned.
423 
424  /// Get the lattice element for a value.
426 
427  /// Get the lattice elements for a range of values.
429 
430  /// Join the lattice element and propagate and update if it changed.
431  void meet(AbstractSparseLattice *lhs, const AbstractSparseLattice &rhs);
432 
433 private:
434  /// Recursively initialize the analysis on nested operations and blocks.
435  LogicalResult initializeRecursively(Operation *op);
436 
437  /// Visit an operation. If this is a call operation or an operation with
438  /// region control-flow, then its operand lattices are set accordingly.
439  /// Otherwise, the operation transfer function is invoked.
440  LogicalResult visitOperation(Operation *op);
441 
442  /// Visit a block.
443  void visitBlock(Block *block);
444 
445  /// Visit an op with regions (like e.g. `scf.while`)
446  void visitRegionSuccessors(RegionBranchOpInterface branch,
448 
449  /// Visit a `RegionBranchTerminatorOpInterface` to compute the lattice values
450  /// of its operands, given its parent op `branch`. The lattice value of an
451  /// operand is determined based on the corresponding arguments in
452  /// `terminator`'s region successor(s).
453  void visitRegionSuccessorsFromTerminator(
454  RegionBranchTerminatorOpInterface terminator,
455  RegionBranchOpInterface branch);
456 
457  /// Get the lattice element for a value, and also set up
458  /// dependencies so that the analysis on the given ProgramPoint is re-invoked
459  /// if the value changes.
460  const AbstractSparseLattice *getLatticeElementFor(ProgramPoint *point,
461  Value value);
462 
463  /// Get the lattice elements for a range of values, and also set up
464  /// dependencies so that the analysis on the given ProgramPoint is re-invoked
465  /// if any of the values change.
467  getLatticeElementsFor(ProgramPoint *point, ValueRange values);
468 
469  SymbolTableCollection &symbolTable;
470 };
471 
472 //===----------------------------------------------------------------------===//
473 // SparseBackwardDataFlowAnalysis
474 //===----------------------------------------------------------------------===//
475 
476 /// A sparse (backward) data-flow analysis for propagating SSA value lattices
477 /// backwards across the IR by implementing transfer functions for operations.
478 ///
479 /// `StateT` is expected to be a subclass of `AbstractSparseLattice`.
480 ///
481 /// Visit a program point in sparse backward data-flow analysis will invoke the
482 /// transfer function of the operation preceding the program point iterator.
483 /// Visit a program point at the begining of block will visit the block itself.
484 template <typename StateT>
487 public:
489  SymbolTableCollection &symbolTable)
490  : AbstractSparseBackwardDataFlowAnalysis(solver, symbolTable) {}
491 
492  /// Visit an operation with the lattices of its results. This function is
493  /// expected to set the lattices of the operation's operands.
494  virtual LogicalResult visitOperation(Operation *op,
495  ArrayRef<StateT *> operands,
496  ArrayRef<const StateT *> results) = 0;
497 
498  /// Visit a call to an external function. This function is expected to set
499  /// lattice values of the call operands. By default, calls `visitCallOperand`
500  /// for all operands.
501  virtual void visitExternalCall(CallOpInterface call,
502  ArrayRef<StateT *> argumentLattices,
503  ArrayRef<const StateT *> resultLattices) {
504  (void)argumentLattices;
505  (void)resultLattices;
506  for (OpOperand &operand : call->getOpOperands()) {
507  visitCallOperand(operand);
508  }
509  };
510 
511 protected:
512  /// Get the lattice element for a value.
513  StateT *getLatticeElement(Value value) override {
514  return getOrCreate<StateT>(value);
515  }
516 
517  /// Set the given lattice element(s) at control flow exit point(s).
518  virtual void setToExitState(StateT *lattice) = 0;
519  void setToExitState(AbstractSparseLattice *lattice) override {
520  return setToExitState(reinterpret_cast<StateT *>(lattice));
521  }
524  {reinterpret_cast<AbstractSparseLattice *const *>(lattices.begin()),
525  lattices.size()});
526  }
527 
528 private:
529  /// Type-erased wrappers that convert the abstract lattice operands to derived
530  /// lattices and invoke the virtual hooks operating on the derived lattices.
531  LogicalResult visitOperationImpl(
532  Operation *op, ArrayRef<AbstractSparseLattice *> operandLattices,
533  ArrayRef<const AbstractSparseLattice *> resultLattices) override {
534  return visitOperation(
535  op,
536  {reinterpret_cast<StateT *const *>(operandLattices.begin()),
537  operandLattices.size()},
538  {reinterpret_cast<const StateT *const *>(resultLattices.begin()),
539  resultLattices.size()});
540  }
541 
542  void visitExternalCallImpl(
543  CallOpInterface call, ArrayRef<AbstractSparseLattice *> operandLattices,
544  ArrayRef<const AbstractSparseLattice *> resultLattices) override {
546  call,
547  {reinterpret_cast<StateT *const *>(operandLattices.begin()),
548  operandLattices.size()},
549  {reinterpret_cast<const StateT *const *>(resultLattices.begin()),
550  resultLattices.size()});
551  }
552 };
553 
554 } // end namespace dataflow
555 } // end namespace mlir
556 
557 #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:243
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:387
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) and propagate the update if it chaned.
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) and propagate the update if it chaned.
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) and propagate the update if it chaned.
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.