|
| 1 | +//===- CFGToSCF.h - Control Flow Graph to Structured Control Flow *- C++ -*===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | +// |
| 9 | +// This header file defines a generic `transformCFGToSCF` function that can be |
| 10 | +// used to lift any dialect operations implementing control flow graph |
| 11 | +// operations to any dialect implementing structured control flow operations. |
| 12 | +// |
| 13 | +//===----------------------------------------------------------------------===// |
| 14 | + |
| 15 | +#ifndef MLIR_TRANSFORMS_CFGTOSCF_H |
| 16 | +#define MLIR_TRANSFORMS_CFGTOSCF_H |
| 17 | + |
| 18 | +#include "mlir/IR/Builders.h" |
| 19 | +#include "mlir/IR/Dominance.h" |
| 20 | +#include "mlir/IR/Operation.h" |
| 21 | + |
| 22 | +namespace mlir { |
| 23 | + |
| 24 | +/// Interface that should be implemented by any caller of `transformCFGToSCF`. |
| 25 | +/// The transformation requires the caller to 1) create switch-like control |
| 26 | +/// flow operations for intermediate transformations and 2) to create |
| 27 | +/// the desired structured control flow ops. |
| 28 | +class CFGToSCFInterface { |
| 29 | +public: |
| 30 | + virtual ~CFGToSCFInterface() = default; |
| 31 | + |
| 32 | + /// Creates a structured control flow operation branching to one of `regions`. |
| 33 | + /// It replaces `controlFlowCondOp` and must have `resultTypes` as results. |
| 34 | + /// `regions` contains the list of branch regions corresponding to each |
| 35 | + /// successor of `controlFlowCondOp`. Their bodies must simply be taken and |
| 36 | + /// left as is. |
| 37 | + /// Returns failure if incapable of converting the control flow graph |
| 38 | + /// operation. |
| 39 | + virtual FailureOr<Operation *> createStructuredBranchRegionOp( |
| 40 | + OpBuilder &builder, Operation *controlFlowCondOp, TypeRange resultTypes, |
| 41 | + MutableArrayRef<Region> regions) = 0; |
| 42 | + |
| 43 | + /// Creates a return-like terminator for a branch region of the op returned |
| 44 | + /// by `createStructuredBranchRegionOp`. `branchRegionOp` is the operation |
| 45 | + /// returned by `createStructuredBranchRegionOp` while `results` are the |
| 46 | + /// values that should be returned by the branch region. |
| 47 | + virtual LogicalResult |
| 48 | + createStructuredBranchRegionTerminatorOp(Location loc, OpBuilder &builder, |
| 49 | + Operation *branchRegionOp, |
| 50 | + ValueRange results) = 0; |
| 51 | + |
| 52 | + /// Creates a structured control flow operation representing a do-while loop. |
| 53 | + /// The do-while loop is expected to have the exact same result types as the |
| 54 | + /// types of the iteration values. |
| 55 | + /// `loopBody` is the body of the loop. The implementation of this |
| 56 | + /// function must create a suitable terminator op at the end of the last block |
| 57 | + /// in `loopBody` which continues the loop if `condition` is 1 and exits the |
| 58 | + /// loop if 0. `loopValuesNextIter` are the values that have to be passed as |
| 59 | + /// the iteration values for the next iteration if continuing, or the result |
| 60 | + /// of the loop if exiting. |
| 61 | + /// `condition` is guaranteed to be of the same type as values returned by |
| 62 | + /// `getCFGSwitchValue` with either 0 or 1 as value. |
| 63 | + /// |
| 64 | + /// `loopValuesInit` are the values used to initialize the iteration |
| 65 | + /// values of the loop. |
| 66 | + /// Returns failure if incapable of creating a loop op. |
| 67 | + virtual FailureOr<Operation *> createStructuredDoWhileLoopOp( |
| 68 | + OpBuilder &builder, Operation *replacedOp, ValueRange loopValuesInit, |
| 69 | + Value condition, ValueRange loopValuesNextIter, Region &&loopBody) = 0; |
| 70 | + |
| 71 | + /// Creates a constant operation with a result representing `value` that is |
| 72 | + /// suitable as flag for `createCFGSwitchOp`. |
| 73 | + virtual Value getCFGSwitchValue(Location loc, OpBuilder &builder, |
| 74 | + unsigned value) = 0; |
| 75 | + |
| 76 | + /// Creates a switch CFG branch operation branching to one of |
| 77 | + /// `caseDestinations` or `defaultDest`. This is used by the transformation |
| 78 | + /// for intermediate transformations before lifting to structured control |
| 79 | + /// flow. The switch op branches based on `flag` which is guaranteed to be of |
| 80 | + /// the same type as values returned by `getCFGSwitchValue`. Note: |
| 81 | + /// `caseValues` and other related ranges may be empty to represent an |
| 82 | + /// unconditional branch. |
| 83 | + virtual void createCFGSwitchOp(Location loc, OpBuilder &builder, Value flag, |
| 84 | + ArrayRef<unsigned> caseValues, |
| 85 | + BlockRange caseDestinations, |
| 86 | + ArrayRef<ValueRange> caseArguments, |
| 87 | + Block *defaultDest, |
| 88 | + ValueRange defaultArgs) = 0; |
| 89 | + |
| 90 | + /// Creates a constant operation returning an undefined instance of `type`. |
| 91 | + /// This is required by the transformation as the lifting process might create |
| 92 | + /// control-flow paths where an SSA-value is undefined. |
| 93 | + virtual Value getUndefValue(Location loc, OpBuilder &builder, Type type) = 0; |
| 94 | + |
| 95 | + /// Creates a return-like terminator indicating unreachable. |
| 96 | + /// This is required when the transformation encounters a statically known |
| 97 | + /// infinite loop. Since structured control flow ops are not terminators, |
| 98 | + /// after lifting an infinite loop, a terminator has to be placed after to |
| 99 | + /// possibly satisfy the terminator requirement of the region originally |
| 100 | + /// passed to `transformCFGToSCF`. |
| 101 | + /// |
| 102 | + /// `region` is guaranteed to be the region originally passed to |
| 103 | + /// `transformCFGToSCF` and the op is guaranteed to always be an op in a block |
| 104 | + /// directly nested under `region` after the transformation. |
| 105 | + /// |
| 106 | + /// Returns failure if incapable of creating an unreachable terminator. |
| 107 | + virtual FailureOr<Operation *> |
| 108 | + createUnreachableTerminator(Location loc, OpBuilder &builder, |
| 109 | + Region ®ion) = 0; |
| 110 | + |
| 111 | + /// Helper function to create an unconditional branch using |
| 112 | + /// `createCFGSwitchOp`. |
| 113 | + void createSingleDestinationBranch(Location loc, OpBuilder &builder, |
| 114 | + Value dummyFlag, Block *destination, |
| 115 | + ValueRange arguments) { |
| 116 | + createCFGSwitchOp(loc, builder, dummyFlag, {}, {}, {}, destination, |
| 117 | + arguments); |
| 118 | + } |
| 119 | + |
| 120 | + /// Helper function to create a conditional branch using |
| 121 | + /// `createCFGSwitchOp`. |
| 122 | + void createConditionalBranch(Location loc, OpBuilder &builder, |
| 123 | + Value condition, Block *trueDest, |
| 124 | + ValueRange trueArgs, Block *falseDest, |
| 125 | + ValueRange falseArgs) { |
| 126 | + createCFGSwitchOp(loc, builder, condition, {0}, {falseDest}, {falseArgs}, |
| 127 | + trueDest, trueArgs); |
| 128 | + } |
| 129 | +}; |
| 130 | + |
| 131 | +/// Transformation lifting any dialect implementing control flow graph |
| 132 | +/// operations to a dialect implementing structured control flow operations. |
| 133 | +/// `region` is the region that should be transformed. |
| 134 | +/// The implementation of `interface` is responsible for the conversion of the |
| 135 | +/// control flow operations to the structured control flow operations. |
| 136 | +/// |
| 137 | +/// If the region contains only a single kind of return-like operation, all |
| 138 | +/// control flow graph operations will be converted successfully. |
| 139 | +/// Otherwise a single control flow graph operation branching to one block |
| 140 | +/// per return-like operation kind remains. |
| 141 | +/// |
| 142 | +/// The transformation currently requires that all control flow graph operations |
| 143 | +/// have no side effects, implement the BranchOpInterface and does not have any |
| 144 | +/// operation produced successor operands. |
| 145 | +/// Returns failure if any of the preconditions are violated or if any of the |
| 146 | +/// methods of `interface` failed. The IR is left in an unspecified state. |
| 147 | +/// |
| 148 | +/// Otherwise, returns true or false if any changes to the IR have been made. |
| 149 | +FailureOr<bool> transformCFGToSCF(Region ®ion, CFGToSCFInterface &interface, |
| 150 | + DominanceInfo &dominanceInfo); |
| 151 | + |
| 152 | +} // namespace mlir |
| 153 | + |
| 154 | +#endif // MLIR_TRANSFORMS_CFGTOSCF_H |
0 commit comments