MLIR 22.0.0git
DenseAnalysis.h
Go to the documentation of this file.
1//===- DenseAnalysis.h - Dense 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 dense 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_DENSEDATAFLOWANALYSIS_H
16#define MLIR_ANALYSIS_DENSEDATAFLOWANALYSIS_H
17
19#include "mlir/IR/SymbolTable.h"
22
23namespace mlir {
24namespace dataflow {
25
26//===----------------------------------------------------------------------===//
27// CallControlFlowAction
28//===----------------------------------------------------------------------===//
29
30/// Indicates whether the control enters, exits, or skips over the callee (in
31/// the case of external functions).
33
34//===----------------------------------------------------------------------===//
35// AbstractDenseLattice
36//===----------------------------------------------------------------------===//
37
38/// This class represents a dense lattice. A dense lattice is attached to
39/// program point to represent the program state at the program point.
40/// lattice is propagated through the IR by dense data-flow analysis.
42public:
43 /// A dense lattice can only be created for operations and blocks.
45
46 /// Join the lattice across control-flow or callgraph edges.
50
54};
55
56//===----------------------------------------------------------------------===//
57// AbstractDenseForwardDataFlowAnalysis
58//===----------------------------------------------------------------------===//
59
60/// Base class for dense forward data-flow analyses. Dense data-flow analysis
61/// attaches a lattice to program points and implements a transfer function from
62/// the lattice before each operation to the lattice after. The lattice contains
63/// information about the state of the program at that program point.
64///
65/// Visit a program point in forward dense data-flow analysis will invoke the
66/// transfer function of the operation preceding the program point iterator.
67/// Visit a program point at the begining of block will visit the block itself.
69public:
71
72 /// Initialize the analysis by visiting every program point whose execution
73 /// may modify the program state; that is, every operation and block.
74 LogicalResult initialize(Operation *top) override;
75
76 /// Initialize lattice anchor equivalence class from the provided top-level
77 /// operation.
78 ///
79 /// This function will union lattice anchor to same equivalent class if the
80 /// analysis can determine the lattice content of lattice anchor is
81 /// necessarily identical under the corrensponding lattice type.
82 virtual void initializeEquivalentLatticeAnchor(Operation *top) override;
83
84 /// Visit a program point that modifies the state of the program. If the
85 /// program point is at the beginning of a block, then the state is propagated
86 /// from control-flow predecessors or callsites. If the operation before
87 /// program point iterator is a call operation or region control-flow
88 /// operation, then the state after the execution of the operation is set by
89 /// control-flow or the callgraph. Otherwise, this function invokes the
90 /// operation transfer function before the program point iterator.
91 LogicalResult visit(ProgramPoint *point) override;
92
93protected:
94 /// Propagate the dense lattice before the execution of an operation to the
95 /// lattice after its execution.
96 virtual LogicalResult visitOperationImpl(Operation *op,
97 const AbstractDenseLattice &before,
98 AbstractDenseLattice *after) = 0;
99
100 /// Get the dense lattice on the given lattice anchor.
102
103 /// Get the dense lattice on the given lattice anchor and add dependent as its
104 /// dependency. That is, every time the lattice after anchor is updated, the
105 /// dependent program point must be visited, and the newly triggered visit
106 /// might update the lattice on dependent.
108 LatticeAnchor anchor) = 0;
109
110 /// Set the dense lattice at control flow entry point and propagate an update
111 /// if it changed.
112 virtual void setToEntryState(AbstractDenseLattice *lattice) = 0;
113
114 /// Join a lattice with another and propagate an update if it changed.
118
119 /// Visit an operation. If this is a call operation or region control-flow
120 /// operation, then the state after the execution of the operation is set by
121 /// control-flow or the callgraph. Otherwise, this function invokes the
122 /// operation transfer function.
123 virtual LogicalResult processOperation(Operation *op);
124
125 /// Visit an operation. If this analysis can confirm that lattice content
126 /// of lattice anchors around operation are necessarily identical, join
127 /// them into the same equivalent class.
129
130 /// Visit a block and propagate the dense lattice forward along the control
131 /// flow edge from predecessor to block. `point` corresponds to the program
132 /// point before `block`. The default implementation merges in the state from
133 /// the predecessor's terminator.
134 virtual void visitBlockTransfer(Block *block, ProgramPoint *point,
135 Block *predecessor,
136 const AbstractDenseLattice &before,
137 AbstractDenseLattice *after) {
138 // Merge in the state from the predecessor's terminator.
139 join(after, before);
140 }
141
142 /// Propagate the dense lattice forward along the control flow edge from
143 /// `regionFrom` to `regionTo` regions of the `branch` operation. `nullopt`
144 /// values correspond to control flow branches originating at or targeting the
145 /// `branch` operation itself. Default implementation just joins the states,
146 /// meaning that operations implementing `RegionBranchOpInterface` don't have
147 /// any effect on the lattice that isn't already expressed by the interface
148 /// itself.
150 RegionBranchOpInterface branch, std::optional<unsigned> regionFrom,
151 std::optional<unsigned> regionTo, const AbstractDenseLattice &before,
152 AbstractDenseLattice *after) {
153 join(after, before);
154 }
155
156 /// Propagate the dense lattice forward along the call control flow edge,
157 /// which can be either entering or exiting the callee. Default implementation
158 /// for enter and exit callee actions just meets the states, meaning that
159 /// operations implementing `CallOpInterface` don't have any effect on the
160 /// lattice that isn't already expressed by the interface itself. Default
161 /// implementation for the external callee action additionally sets the
162 /// "after" lattice to the entry state.
163 virtual void visitCallControlFlowTransfer(CallOpInterface call,
165 const AbstractDenseLattice &before,
166 AbstractDenseLattice *after) {
167 join(after, before);
168 // Note that `setToEntryState` may be a "partial fixpoint" for some
169 // lattices, e.g., lattices that are lists of maps of other lattices will
170 // only set fixpoint for "known" lattices.
172 setToEntryState(after);
173 }
174
175 /// Visit a program point within a region branch operation with predecessors
176 /// in it. This can either be an entry block of one of the regions of the
177 /// parent operation itself.
179 RegionBranchOpInterface branch,
180 AbstractDenseLattice *after);
181
182private:
183 /// Visit a block. The state at the start of the block is propagated from
184 /// control-flow predecessors or callsites.
185 void visitBlock(Block *block);
186
187 /// Visit an operation for which the data flow is described by the
188 /// `CallOpInterface`.
189 void visitCallOperation(CallOpInterface call,
190 const AbstractDenseLattice &before,
191 AbstractDenseLattice *after);
192};
193
194//===----------------------------------------------------------------------===//
195// DenseForwardDataFlowAnalysis
196//===----------------------------------------------------------------------===//
197
198/// A dense forward data-flow analysis for propagating lattices before and
199/// after the execution of every operation across the IR by implementing
200/// transfer functions for operations.
201///
202/// `LatticeT` is expected to be a subclass of `AbstractDenseLattice`.
203template <typename LatticeT>
206 static_assert(
207 std::is_base_of<AbstractDenseLattice, LatticeT>::value,
208 "analysis state class expected to subclass AbstractDenseLattice");
209
210public:
212 AbstractDenseForwardDataFlowAnalysis;
213
214 /// Visit an operation with the dense lattice before its execution. This
215 /// function is expected to set the dense lattice after its execution and
216 /// trigger change propagation in case of change.
217 virtual LogicalResult visitOperation(Operation *op, const LatticeT &before,
218 LatticeT *after) = 0;
219
220 /// Hook for customizing the behavior of lattice propagation along the call
221 /// control flow edges. Two types of (forward) propagation are possible here:
222 /// - `action == CallControlFlowAction::Enter` indicates that:
223 /// - `before` is the state before the call operation;
224 /// - `after` is the state at the beginning of the callee entry block;
225 /// - `action == CallControlFlowAction::Exit` indicates that:
226 /// - `before` is the state at the end of a callee exit block;
227 /// - `after` is the state after the call operation.
228 /// By default, the `after` state is simply joined with the `before` state.
229 /// Concrete analyses can override this behavior or delegate to the parent
230 /// call for the default behavior. Specifically, if the `call` op may affect
231 /// the lattice prior to entering the callee, the custom behavior can be added
232 /// for `action == CallControlFlowAction::Enter`. If the `call` op may affect
233 /// the lattice post exiting the callee, the custom behavior can be added for
234 /// `action == CallControlFlowAction::Exit`.
235 virtual void visitCallControlFlowTransfer(CallOpInterface call,
237 const LatticeT &before,
238 LatticeT *after) {
240 call, action, before, after);
241 }
242
243 /// Hook for customizing the behavior of lattice propagation along the control
244 /// flow edges between regions and their parent op. The control flows from
245 /// `regionFrom` to `regionTo`, both of which may be `nullopt` to indicate the
246 /// parent op. The lattice is propagated forward along this edge. The lattices
247 /// are as follows:
248 /// - `before:`
249 /// - if `regionFrom` is a region, this is the lattice at the end of the
250 /// block that exits the region; note that for multi-exit regions, the
251 /// lattices are equal at the end of all exiting blocks, but they are
252 /// associated with different program points.
253 /// - otherwise, this is the lattice before the parent op.
254 /// - `after`:
255 /// - if `regionTo` is a region, this is the lattice at the beginning of
256 /// the entry block of that region;
257 /// - otherwise, this is the lattice after the parent op.
258 /// By default, the `after` state is simply joined with the `before` state.
259 /// Concrete analyses can override this behavior or delegate to the parent
260 /// call for the default behavior. Specifically, if the `branch` op may affect
261 /// the lattice before entering any region, the custom behavior can be added
262 /// for `regionFrom == nullopt`. If the `branch` op may affect the lattice
263 /// after all terminated, the custom behavior can be added for `regionTo ==
264 /// nullptr`. The behavior can be further refined for specific pairs of "from"
265 /// and "to" regions.
267 RegionBranchOpInterface branch, std::optional<unsigned> regionFrom,
268 std::optional<unsigned> regionTo, const LatticeT &before,
269 LatticeT *after) {
271 branch, regionFrom, regionTo, before, after);
272 }
273
274 /// Hook for customizing the behavior of lattice propagation along the control
275 /// flow edges between blocks. The control flows from `predecessor` to
276 /// `block`. The lattice is propagated forward along this edge. The lattices
277 /// are as follows:
278 /// - `before` is the lattice at the end of the predecessor block;
279 /// - `after` is the lattice at the beginning of the block.
280 /// By default, the `after` state is simply joined with the `before` state.
281 /// Concrete analyses can override this behavior or delegate to the parent
282 /// call for the default behavior.
283 virtual void visitBlockTransfer(Block *block, ProgramPoint *point,
284 Block *predecessor, const LatticeT &before,
285 LatticeT *after) {
287 block, point, predecessor, before, after);
288 }
289
290protected:
291 /// Get the dense lattice on this lattice anchor.
292 LatticeT *getLattice(LatticeAnchor anchor) override {
293 return getOrCreate<LatticeT>(anchor);
294 }
295
296 /// Get the dense lattice on the given lattice anchor and add dependent as its
297 /// dependency. That is, every time the lattice after anchor is updated, the
298 /// dependent program point must be visited, and the newly triggered visit
299 /// might update the lattice on dependent.
301 LatticeAnchor anchor) override {
302 return getOrCreateFor<LatticeT>(dependent, anchor);
303 }
304
305 /// Set the dense lattice at control flow entry point and propagate an update
306 /// if it changed.
307 virtual void setToEntryState(LatticeT *lattice) = 0;
308 void setToEntryState(AbstractDenseLattice *lattice) override {
309 setToEntryState(static_cast<LatticeT *>(lattice));
310 }
311
312 /// Type-erased wrappers that convert the abstract dense lattice to a derived
313 /// lattice and invoke the virtual hooks operating on the derived lattice.
314 LogicalResult visitOperationImpl(Operation *op,
315 const AbstractDenseLattice &before,
316 AbstractDenseLattice *after) final {
317 return visitOperation(op, static_cast<const LatticeT &>(before),
318 static_cast<LatticeT *>(after));
319 }
320 void visitCallControlFlowTransfer(CallOpInterface call,
322 const AbstractDenseLattice &before,
323 AbstractDenseLattice *after) final {
324 visitCallControlFlowTransfer(call, action,
325 static_cast<const LatticeT &>(before),
326 static_cast<LatticeT *>(after));
327 }
328 void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch,
329 std::optional<unsigned> regionFrom,
330 std::optional<unsigned> regionTo,
331 const AbstractDenseLattice &before,
332 AbstractDenseLattice *after) final {
333 visitRegionBranchControlFlowTransfer(branch, regionFrom, regionTo,
334 static_cast<const LatticeT &>(before),
335 static_cast<LatticeT *>(after));
336 }
337 void visitBlockTransfer(Block *block, ProgramPoint *point, Block *predecessor,
338 const AbstractDenseLattice &before,
339 AbstractDenseLattice *after) final {
340 visitBlockTransfer(block, point, predecessor,
341 static_cast<const LatticeT &>(before),
342 static_cast<LatticeT *>(after));
343 }
344};
345
346//===----------------------------------------------------------------------===//
347// AbstractDenseBackwardDataFlowAnalysis
348//===----------------------------------------------------------------------===//
349
350/// Base class for dense backward dataflow analyses. Such analyses attach a
351/// lattice to program point and implement a transfer function from the lattice
352/// after the operation to the lattice before it, thus propagating backward.
353///
354/// Visit a program point in dense backward data-flow analysis will invoke the
355/// transfer function of the operation following the program point iterator.
356/// Visit a program point at the end of block will visit the block itself.
358public:
359 /// Construct the analysis in the given solver. Takes a symbol table
360 /// collection that is used to cache symbol resolution in interprocedural part
361 /// of the analysis. The symbol table need not be prefilled.
363 SymbolTableCollection &symbolTable)
364 : DataFlowAnalysis(solver), symbolTable(symbolTable) {}
365
366 /// Initialize the analysis by visiting every program point whose execution
367 /// may modify the program state; that is, every operation and block.
368 LogicalResult initialize(Operation *top) override;
369
370 /// Initialize lattice anchor equivalence class from the provided top-level
371 /// operation.
372 ///
373 /// This function will union lattice anchor to same equivalent class if the
374 /// analysis can determine the lattice content of lattice anchor is
375 /// necessarily identical under the corrensponding lattice type.
376 virtual void initializeEquivalentLatticeAnchor(Operation *top) override;
377
378 /// Visit a program point that modifies the state of the program. The state is
379 /// propagated along control flow directions for branch-, region- and
380 /// call-based control flow using the respective interfaces. For other
381 /// operations, the state is propagated using the transfer function
382 /// (visitOperation).
383 ///
384 /// Note: the transfer function is currently *not* invoked before operations
385 /// with region or call interface, but *is* invoked before block terminators.
386 LogicalResult visit(ProgramPoint *point) override;
387
388protected:
389 /// Propagate the dense lattice after the execution of an operation to the
390 /// lattice before its execution.
391 virtual LogicalResult visitOperationImpl(Operation *op,
392 const AbstractDenseLattice &after,
393 AbstractDenseLattice *before) = 0;
394
395 /// Get the dense lattice before the execution of the lattice anchor. That is,
396 /// before the execution of the given operation or after the execution of the
397 /// block.
399
400 /// Get the dense lattice on the given lattice anchor and add dependent as its
401 /// dependency. That is, every time the lattice after anchor is updated, the
402 /// dependent program point must be visited, and the newly triggered visit
403 /// might update the lattice before dependent.
405 LatticeAnchor anchor) = 0;
406
407 /// Set the dense lattice before at the control flow exit point and propagate
408 /// the update if it changed.
409 virtual void setToExitState(AbstractDenseLattice *lattice) = 0;
410
411 /// Meet a lattice with another lattice and propagate an update if it changed.
415
416 /// Visit an operation. Dispatches to specialized methods for call or region
417 /// control-flow operations. Otherwise, this function invokes the operation
418 /// transfer function.
419 virtual LogicalResult processOperation(Operation *op);
420
421 /// Visit an operation. If this analysis can confirm that lattice content
422 /// of lattice anchors around operation are necessarily identical, join
423 /// them into the same equivalent class.
425
426 /// Visit a block and propagate the dense lattice backward along the control
427 /// flow edge from successor to block. `point` corresponds to the program
428 /// point after `block`. The default implementation merges in the state from
429 /// the successor's first operation or the block itself when empty.
430 virtual void visitBlockTransfer(Block *block, ProgramPoint *point,
431 Block *successor,
432 const AbstractDenseLattice &after,
433 AbstractDenseLattice *before) {
434 meet(before, after);
435 }
436
437 /// Propagate the dense lattice backwards along the control flow edge from
438 /// `regionFrom` to `regionTo` regions of the `branch` operation. `nullopt`
439 /// values correspond to control flow branches originating at or targeting the
440 /// `branch` operation itself. Default implementation just meets the states,
441 /// meaning that operations implementing `RegionBranchOpInterface` don't have
442 /// any effect on the lattice that isn't already expressed by the interface
443 /// itself.
445 RegionBranchOpInterface branch, RegionBranchPoint regionFrom,
446 RegionSuccessor regionTo, const AbstractDenseLattice &after,
447 AbstractDenseLattice *before) {
448 meet(before, after);
449 }
450
451 /// Propagate the dense lattice backwards along the call control flow edge,
452 /// which can be either entering or exiting the callee. Default implementation
453 /// for enter and exit callee action just meets the states, meaning that
454 /// operations implementing `CallOpInterface` don't have any effect on the
455 /// lattice that isn't already expressed by the interface itself. Default
456 /// implementation for external callee action additional sets the result to
457 /// the exit (fixpoint) state.
458 virtual void visitCallControlFlowTransfer(CallOpInterface call,
460 const AbstractDenseLattice &after,
461 AbstractDenseLattice *before) {
462 meet(before, after);
463
464 // Note that `setToExitState` may be a "partial fixpoint" for some lattices,
465 // e.g., lattices that are lists of maps of other lattices will only
466 // set fixpoint for "known" lattices.
468 setToExitState(before);
469 }
470
471private:
472 /// Visit a block. The state and the end of the block is propagated from
473 /// control-flow successors of the block or callsites.
474 void visitBlock(Block *block);
475
476 /// Visit a program point within a region branch operation with successors
477 /// (from which the state is propagated) in or after it. `regionNo` indicates
478 /// the region that contains the successor, `nullopt` indicating the successor
479 /// of the branch operation itself.
480 void visitRegionBranchOperation(ProgramPoint *point,
481 RegionBranchOpInterface branch,
482 RegionBranchPoint branchPoint,
483 AbstractDenseLattice *before);
484
485 /// Visit an operation for which the data flow is described by the
486 /// `CallOpInterface`. Performs inter-procedural data flow as follows:
487 ///
488 /// - find the callable (resolve via the symbol table),
489 /// - get the entry block of the callable region,
490 /// - take the state before the first operation if present or at block end
491 /// otherwise,
492 /// - meet that state with the state before the call-like op, or use the
493 /// custom logic if overridden by concrete analyses.
494 void visitCallOperation(CallOpInterface call,
495 const AbstractDenseLattice &after,
496 AbstractDenseLattice *before);
497
498 /// Symbol table for call-level control flow.
499 SymbolTableCollection &symbolTable;
500};
501
502//===----------------------------------------------------------------------===//
503// DenseBackwardDataFlowAnalysis
504//===----------------------------------------------------------------------===//
505
506/// A dense backward dataflow analysis propagating lattices after and before the
507/// execution of every operation across the IR by implementing transfer
508/// functions for opreations.
509///
510/// `LatticeT` is expected to be a subclass of `AbstractDenseLattice`.
511template <typename LatticeT>
514 static_assert(std::is_base_of_v<AbstractDenseLattice, LatticeT>,
515 "analysis state expected to subclass AbstractDenseLattice");
516
517public:
519 AbstractDenseBackwardDataFlowAnalysis;
520
521 /// Transfer function. Visits an operation with the dense lattice after its
522 /// execution. This function is expected to set the dense lattice before its
523 /// execution and trigger propagation in case of change.
524 virtual LogicalResult visitOperation(Operation *op, const LatticeT &after,
525 LatticeT *before) = 0;
526
527 /// Hook for customizing the behavior of lattice propagation along the call
528 /// control flow edges. Two types of (back) propagation are possible here:
529 /// - `action == CallControlFlowAction::Enter` indicates that:
530 /// - `after` is the state at the top of the callee entry block;
531 /// - `before` is the state before the call operation;
532 /// - `action == CallControlFlowAction::Exit` indicates that:
533 /// - `after` is the state after the call operation;
534 /// - `before` is the state of exit blocks of the callee.
535 /// By default, the `before` state is simply met with the `after` state.
536 /// Concrete analyses can override this behavior or delegate to the parent
537 /// call for the default behavior. Specifically, if the `call` op may affect
538 /// the lattice prior to entering the callee, the custom behavior can be added
539 /// for `action == CallControlFlowAction::Enter`. If the `call` op may affect
540 /// the lattice post exiting the callee, the custom behavior can be added for
541 /// `action == CallControlFlowAction::Exit`.
542 virtual void visitCallControlFlowTransfer(CallOpInterface call,
544 const LatticeT &after,
545 LatticeT *before) {
547 call, action, after, before);
548 }
549
550 /// Hook for customizing the behavior of lattice propagation along the control
551 /// flow edges between regions and their parent op. The control flows from
552 /// `regionFrom` to `regionTo`, both of which may be `nullopt` to indicate the
553 /// parent op. The lattice is propagated back along this edge. The lattices
554 /// are as follows:
555 /// - `after`:
556 /// - if `regionTo` is a region, this is the lattice at the beginning of
557 /// the entry block of that region;
558 /// - otherwise, this is the lattice after the parent op.
559 /// - `before:`
560 /// - if `regionFrom` is a region, this is the lattice at the end of the
561 /// block that exits the region; note that for multi-exit regions, the
562 /// lattices are equal at the end of all exiting blocks, but they are
563 /// associated with different program points.
564 /// - otherwise, this is the lattice before the parent op.
565 /// By default, the `before` state is simply met with the `after` state.
566 /// Concrete analyses can override this behavior or delegate to the parent
567 /// call for the default behavior. Specifically, if the `branch` op may affect
568 /// the lattice before entering any region, the custom behavior can be added
569 /// for `regionFrom == nullopt`. If the `branch` op may affect the lattice
570 /// after all terminated, the custom behavior can be added for `regionTo ==
571 /// nullptr`. The behavior can be further refined for specific pairs of "from"
572 /// and "to" regions.
574 RegionBranchOpInterface branch, RegionBranchPoint regionFrom,
575 RegionSuccessor regionTo, const LatticeT &after, LatticeT *before) {
577 branch, regionFrom, regionTo, after, before);
578 }
579
580 /// Hook for customizing the behavior of lattice propagation along the control
581 /// flow edges between blocks. The control flows from `successor` to
582 /// `block`. The lattice is propagated back along this edge. The lattices
583 /// are as follows:
584 /// - `after` is the lattice at the beginning of the successor block;
585 /// - `before` is the lattice at the end of the block.
586 /// By default, the `before` state is simply met with the `after` state.
587 /// Concrete analyses can override this behavior or delegate to the parent
588 /// call for the default behavior.
589 virtual void visitBlockTransfer(Block *block, ProgramPoint *point,
590 Block *successor, const LatticeT &after,
591 LatticeT *before) {
593 block, point, successor, after, before);
594 }
595
596protected:
597 /// Get the dense lattice at the given lattice anchor.
598 LatticeT *getLattice(LatticeAnchor anchor) override {
599 return getOrCreate<LatticeT>(anchor);
600 }
601
602 /// Get the dense lattice on the given lattice anchor and add dependent as its
603 /// dependency. That is, every time the lattice after anchor is updated, the
604 /// dependent program point must be visited, and the newly triggered visit
605 /// might update the lattice before dependent.
606 virtual const AbstractDenseLattice *
607 getLatticeFor(ProgramPoint *dependent, LatticeAnchor anchor) override {
608 return getOrCreateFor<LatticeT>(dependent, anchor);
609 }
610
611 /// Set the dense lattice at control flow exit point (after the terminator)
612 /// and propagate an update if it changed.
613 virtual void setToExitState(LatticeT *lattice) = 0;
615 setToExitState(static_cast<LatticeT *>(lattice));
616 }
617
618 /// Type-erased wrappers that convert the abstract dense lattice to a derived
619 /// lattice and invoke the virtual hooks operating on the derived lattice.
620 LogicalResult visitOperationImpl(Operation *op,
621 const AbstractDenseLattice &after,
622 AbstractDenseLattice *before) final {
623 return visitOperation(op, static_cast<const LatticeT &>(after),
624 static_cast<LatticeT *>(before));
625 }
626 void visitCallControlFlowTransfer(CallOpInterface call,
628 const AbstractDenseLattice &after,
629 AbstractDenseLattice *before) final {
630 visitCallControlFlowTransfer(call, action,
631 static_cast<const LatticeT &>(after),
632 static_cast<LatticeT *>(before));
633 }
635 RegionBranchOpInterface branch, RegionBranchPoint regionForm,
636 RegionSuccessor regionTo, const AbstractDenseLattice &after,
637 AbstractDenseLattice *before) final {
638 visitRegionBranchControlFlowTransfer(branch, regionForm, regionTo,
639 static_cast<const LatticeT &>(after),
640 static_cast<LatticeT *>(before));
641 }
642 void visitBlockTransfer(Block *block, ProgramPoint *point, Block *successor,
643 const AbstractDenseLattice &after,
644 AbstractDenseLattice *before) final {
645 visitBlockTransfer(block, point, successor,
646 static_cast<const LatticeT &>(after),
647 static_cast<LatticeT *>(before));
648 }
649};
650
651} // end namespace dataflow
652} // end namespace mlir
653
654#endif // MLIR_ANALYSIS_DENSEDATAFLOWANALYSIS_H
lhs
AnalysisState(LatticeAnchor anchor)
Create the analysis state on the given lattice anchor.
Block represents an ordered list of Operations.
Definition Block.h:33
void propagateIfChanged(AnalysisState *state, ChangeResult changed)
Propagate an update to a state if it changed.
StateT * getOrCreate(AnchorT anchor)
Get the analysis state associated with the lattice anchor.
DataFlowAnalysis(DataFlowSolver &solver)
Create an analysis with a reference to the parent solver.
friend class DataFlowSolver
Allow the data-flow solver to access the internals of this class.
const StateT * getOrCreateFor(ProgramPoint *dependent, AnchorT anchor)
Get a read-only analysis state for the given point and create a dependency on dependent.
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.
This class represents a collection of SymbolTables.
virtual void setToExitState(AbstractDenseLattice *lattice)=0
Set the dense lattice before at the control flow exit point and propagate the update if it changed.
LogicalResult initialize(Operation *top) override
Initialize the analysis by visiting every program point whose execution may modify the program state;...
virtual void visitCallControlFlowTransfer(CallOpInterface call, CallControlFlowAction action, const AbstractDenseLattice &after, AbstractDenseLattice *before)
Propagate the dense lattice backwards along the call control flow edge, which can be either entering ...
virtual void initializeEquivalentLatticeAnchor(Operation *top) override
Initialize lattice anchor equivalence class from the provided top-level operation.
virtual void buildOperationEquivalentLatticeAnchor(Operation *op)
Visit an operation.
virtual void visitBlockTransfer(Block *block, ProgramPoint *point, Block *successor, const AbstractDenseLattice &after, AbstractDenseLattice *before)
Visit a block and propagate the dense lattice backward along the control flow edge from successor to ...
virtual AbstractDenseLattice * getLattice(LatticeAnchor anchor)=0
Get the dense lattice before the execution of the lattice anchor.
LogicalResult visit(ProgramPoint *point) override
Visit a program point that modifies the state of the program.
virtual LogicalResult visitOperationImpl(Operation *op, const AbstractDenseLattice &after, AbstractDenseLattice *before)=0
Propagate the dense lattice after the execution of an operation to the lattice before its execution.
void meet(AbstractDenseLattice *lhs, const AbstractDenseLattice &rhs)
Meet a lattice with another lattice and propagate an update if it changed.
virtual LogicalResult processOperation(Operation *op)
Visit an operation.
virtual void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, RegionBranchPoint regionFrom, RegionSuccessor regionTo, const AbstractDenseLattice &after, AbstractDenseLattice *before)
Propagate the dense lattice backwards along the control flow edge from regionFrom to regionTo regions...
virtual const AbstractDenseLattice * getLatticeFor(ProgramPoint *dependent, LatticeAnchor anchor)=0
Get the dense lattice on the given lattice anchor and add dependent as its dependency.
AbstractDenseBackwardDataFlowAnalysis(DataFlowSolver &solver, SymbolTableCollection &symbolTable)
Construct the analysis in the given solver.
Base class for dense forward data-flow analyses.
virtual LogicalResult visitOperationImpl(Operation *op, const AbstractDenseLattice &before, AbstractDenseLattice *after)=0
Propagate the dense lattice before the execution of an operation to the lattice after its execution.
virtual const AbstractDenseLattice * getLatticeFor(ProgramPoint *dependent, LatticeAnchor anchor)=0
Get the dense lattice on the given lattice anchor and add dependent as its dependency.
void visitRegionBranchOperation(ProgramPoint *point, RegionBranchOpInterface branch, AbstractDenseLattice *after)
Visit a program point within a region branch operation with predecessors in it.
virtual void initializeEquivalentLatticeAnchor(Operation *top) override
Initialize lattice anchor equivalence class from the provided top-level operation.
void join(AbstractDenseLattice *lhs, const AbstractDenseLattice &rhs)
Join a lattice with another and propagate an update if it changed.
virtual void setToEntryState(AbstractDenseLattice *lattice)=0
Set the dense lattice at control flow entry point and propagate an update if it changed.
LogicalResult initialize(Operation *top) override
Initialize the analysis by visiting every program point whose execution may modify the program state;...
virtual void visitCallControlFlowTransfer(CallOpInterface call, CallControlFlowAction action, const AbstractDenseLattice &before, AbstractDenseLattice *after)
Propagate the dense lattice forward along the call control flow edge, which can be either entering or...
virtual AbstractDenseLattice * getLattice(LatticeAnchor anchor)=0
Get the dense lattice on the given lattice anchor.
virtual LogicalResult processOperation(Operation *op)
Visit an operation.
DataFlowAnalysis(DataFlowSolver &solver)
Create an analysis with a reference to the parent solver.
virtual void visitBlockTransfer(Block *block, ProgramPoint *point, Block *predecessor, const AbstractDenseLattice &before, AbstractDenseLattice *after)
Visit a block and propagate the dense lattice forward along the control flow edge from predecessor to...
virtual void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, std::optional< unsigned > regionFrom, std::optional< unsigned > regionTo, const AbstractDenseLattice &before, AbstractDenseLattice *after)
Propagate the dense lattice forward along the control flow edge from regionFrom to regionTo regions o...
virtual void buildOperationEquivalentLatticeAnchor(Operation *op)
Visit an operation.
LogicalResult visit(ProgramPoint *point) override
Visit a program point that modifies the state of the program.
This class represents a dense lattice.
virtual ChangeResult join(const AbstractDenseLattice &rhs)
Join the lattice across control-flow or callgraph edges.
AnalysisState(LatticeAnchor anchor)
A dense lattice can only be created for operations and blocks.
virtual ChangeResult meet(const AbstractDenseLattice &rhs)
A dense backward dataflow analysis propagating lattices after and before the execution of every opera...
virtual void setToExitState(LatticeT *lattice)=0
Set the dense lattice at control flow exit point (after the terminator) and propagate an update if it...
void visitBlockTransfer(Block *block, ProgramPoint *point, Block *successor, const AbstractDenseLattice &after, AbstractDenseLattice *before) final
Visit a block and propagate the dense lattice backward along the control flow edge from successor to ...
virtual const AbstractDenseLattice * getLatticeFor(ProgramPoint *dependent, LatticeAnchor anchor) override
Get the dense lattice on the given lattice anchor and add dependent as its dependency.
LogicalResult visitOperationImpl(Operation *op, const AbstractDenseLattice &after, AbstractDenseLattice *before) final
Type-erased wrappers that convert the abstract dense lattice to a derived lattice and invoke the virt...
LatticeT * getLattice(LatticeAnchor anchor) override
Get the dense lattice at the given lattice anchor.
virtual void visitCallControlFlowTransfer(CallOpInterface call, CallControlFlowAction action, const LatticeT &after, LatticeT *before)
Hook for customizing the behavior of lattice propagation along the call control flow edges.
virtual void visitBlockTransfer(Block *block, ProgramPoint *point, Block *successor, const LatticeT &after, LatticeT *before)
Hook for customizing the behavior of lattice propagation along the control flow edges between blocks.
void setToExitState(AbstractDenseLattice *lattice) final
Set the dense lattice before at the control flow exit point and propagate the update if it changed.
void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, RegionBranchPoint regionForm, RegionSuccessor regionTo, const AbstractDenseLattice &after, AbstractDenseLattice *before) final
Propagate the dense lattice backwards along the control flow edge from regionFrom to regionTo regions...
void visitCallControlFlowTransfer(CallOpInterface call, CallControlFlowAction action, const AbstractDenseLattice &after, AbstractDenseLattice *before) final
Propagate the dense lattice backwards along the call control flow edge, which can be either entering ...
virtual LogicalResult visitOperation(Operation *op, const LatticeT &after, LatticeT *before)=0
Transfer function.
virtual void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, RegionBranchPoint regionFrom, RegionSuccessor regionTo, const LatticeT &after, LatticeT *before)
Hook for customizing the behavior of lattice propagation along the control flow edges between regions...
A dense forward data-flow analysis for propagating lattices before and after the execution of every o...
virtual void visitCallControlFlowTransfer(CallOpInterface call, CallControlFlowAction action, const LatticeT &before, LatticeT *after)
Hook for customizing the behavior of lattice propagation along the call control flow edges.
void setToEntryState(AbstractDenseLattice *lattice) override
Set the dense lattice at control flow entry point and propagate an update if it changed.
virtual void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, std::optional< unsigned > regionFrom, std::optional< unsigned > regionTo, const LatticeT &before, LatticeT *after)
Hook for customizing the behavior of lattice propagation along the control flow edges between regions...
const AbstractDenseLattice * getLatticeFor(ProgramPoint *dependent, LatticeAnchor anchor) override
Get the dense lattice on the given lattice anchor and add dependent as its dependency.
virtual void setToEntryState(LatticeT *lattice)=0
Set the dense lattice at control flow entry point and propagate an update if it changed.
virtual void visitBlockTransfer(Block *block, ProgramPoint *point, Block *predecessor, const LatticeT &before, LatticeT *after)
Hook for customizing the behavior of lattice propagation along the control flow edges between blocks.
LatticeT * getLattice(LatticeAnchor anchor) override
Get the dense lattice on this lattice anchor.
LogicalResult visitOperationImpl(Operation *op, const AbstractDenseLattice &before, AbstractDenseLattice *after) final
Type-erased wrappers that convert the abstract dense lattice to a derived lattice and invoke the virt...
virtual LogicalResult visitOperation(Operation *op, const LatticeT &before, LatticeT *after)=0
Visit an operation with the dense lattice before its execution.
void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, std::optional< unsigned > regionFrom, std::optional< unsigned > regionTo, const AbstractDenseLattice &before, AbstractDenseLattice *after) final
Propagate the dense lattice forward along the control flow edge from regionFrom to regionTo regions o...
void visitBlockTransfer(Block *block, ProgramPoint *point, Block *predecessor, const AbstractDenseLattice &before, AbstractDenseLattice *after) final
Visit a block and propagate the dense lattice forward along the control flow edge from predecessor to...
void visitCallControlFlowTransfer(CallOpInterface call, CallControlFlowAction action, const AbstractDenseLattice &before, AbstractDenseLattice *after) final
Propagate the dense lattice forward along the call control flow edge, which can be either entering or...
CallControlFlowAction
Indicates whether the control enters, exits, or skips over the callee (in the case of external functi...
Include the generated interface declarations.
ChangeResult
A result type used to indicate if a change happened.
Fundamental IR components are supported as first-class lattice anchor.
Program point represents a specific location in the execution of a program.