summaryrefslogtreecommitdiff
path: root/flang/include/flang/Optimizer/Transforms/Passes.td
blob: e7a7c61b479728bc0811e43cbd847a93c4e4beca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
//===-- Passes.td - Transforms pass definition file --------*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains definitions for passes within the Optimizer/Transforms/
// directory.
//
//===----------------------------------------------------------------------===//

#ifndef FLANG_OPTIMIZER_TRANSFORMS_PASSES
#define FLANG_OPTIMIZER_TRANSFORMS_PASSES

include "mlir/Pass/PassBase.td"

class AbstractResultOptBase<string optExt, string operation> 
  : Pass<"abstract-result-on-" # optExt # "-opt", operation> {
  let summary = "Convert fir.array, fir.box and fir.rec function result to "
                "function argument";
  let description = [{
    This pass is required before code gen to the LLVM IR dialect,
    including the pre-cg rewrite pass.
  }];
  let dependentDialects = [
    "fir::FIROpsDialect", "mlir::func::FuncDialect"
  ];
  let options = [
    Option<"passResultAsBox", "abstract-result-as-box",
           "bool", /*default=*/"false",
           "Pass fir.array<T> result as fir.box<fir.array<T>> argument instead"
           " of fir.ref<fir.array<T>>.">
  ];
}

def AbstractResultOnFuncOpt : AbstractResultOptBase<"func", "mlir::func::FuncOp"> {
  let constructor = "::fir::createAbstractResultOnFuncOptPass()";
}

def AbstractResultOnGlobalOpt : AbstractResultOptBase<"global", "fir::GlobalOp"> {
  let constructor = "::fir::createAbstractResultOnGlobalOptPass()";
}

def AffineDialectPromotion : Pass<"promote-to-affine", "::mlir::func::FuncOp"> {
  let summary = "Promotes `fir.{do_loop,if}` to `affine.{for,if}`.";
  let description = [{
    Convert fir operations which satisfy affine constraints to the affine
    dialect.

    `fir.do_loop` will be converted to `affine.for` if the loops inside the body
    can be converted and the indices for memory loads and stores satisfy
    `affine.apply` criteria for symbols and dimensions.

    `fir.if` will be converted to `affine.if` where possible. `affine.if`'s
    condition uses an integer set (==, >=) and an analysis is done to determine
    the fir condition's parent operations to construct the integer set.

    `fir.load` (`fir.store`) will be converted to `affine.load` (`affine.store`)
    where possible. This conversion includes adding a dummy `fir.convert` cast
    to adapt values of type `!fir.ref<!fir.array>` to `memref`. This is done
    because the affine dialect presently only understands the `memref` type.
  }];
  let constructor = "::fir::createPromoteToAffinePass()";
  let dependentDialects = [
    "fir::FIROpsDialect", "mlir::func::FuncDialect",
    "mlir::affine::AffineDialect"
  ];
}

def AffineDialectDemotion : Pass<"demote-affine", "::mlir::func::FuncOp"> {
  let summary = "Converts `affine.{load,store}` back to fir operations";
  let description = [{
    Affine dialect's default lowering for loads and stores is different from
    fir as it uses the `memref` type. The `memref` type is not compatible with
    the Fortran runtime. Therefore, conversion of memory operations back to
    `fir.load` and `fir.store` with `!fir.ref<?>` types is required.
  }];
  let constructor = "::fir::createAffineDemotionPass()";
  let dependentDialects = [
    "fir::FIROpsDialect", "mlir::func::FuncDialect",
    "mlir::affine::AffineDialect"
  ];
}

def AnnotateConstantOperands : Pass<"annotate-constant"> {
  let summary = "Annotate constant operands to all FIR operations";
  let description = [{
    The MLIR canonicalizer makes a distinction between constants based on how
    they are packaged in the IR. A constant value is wrapped in an Attr and that
    Attr can be attached to an Op. There is a distinguished Op, ConstantOp, that
    merely has one of these Attr attached.

    The MLIR canonicalizer treats constants referenced by an Op and constants
    referenced through a ConstantOp as having distinct semantics. This pass
    eliminates that distinction, so hashconsing of Ops, basic blocks, etc.
    behaves as one would expect.
  }];
  let constructor = "::fir::createAnnotateConstantOperandsPass()";
  let dependentDialects = [ "fir::FIROpsDialect" ];
}

def ArrayValueCopy : Pass<"array-value-copy", "::mlir::func::FuncOp"> {
  let summary = "Convert array value operations to memory operations.";
  let description = [{
    Transform the set of array value primitives to a memory-based array
    representation.

    The Ops `array_load`, `array_store`, `array_fetch`, and `array_update` are
    used to manage abstract aggregate array values. A simple analysis is done
    to determine if there are potential dependences between these operations.
    If not, these array operations can be lowered to work directly on the memory
    representation. If there is a potential conflict, a temporary is created
    along with appropriate copy-in/copy-out operations. Here, a more refined
    analysis might be deployed, such as using the affine framework.

    This pass is required before code gen to the LLVM IR dialect.
  }];
  let constructor = "::fir::createArrayValueCopyPass()";
  let dependentDialects = [ "fir::FIROpsDialect" ];
  let options = [
    Option<"optimizeConflicts", "optimize-conflicts", "bool",
           /*default=*/"false",
           "do more detailed conflict analysis to reduce the number "
           "of temporaries">
  ];
}

def CharacterConversion : Pass<"character-conversion"> {
  let summary = "Convert CHARACTER entities with different KINDs";
  let description = [{
    Translates entities of one CHARACTER KIND to another.

    By default the translation is to naively zero-extend or truncate a code
    point to fit the destination size.
  }];
  let constructor = "::fir::createCharacterConversionPass()";
  let dependentDialects = [ "fir::FIROpsDialect" ];
  let options = [
    Option<"useRuntimeCalls", "use-runtime-calls",
           "std::string", /*default=*/"std::string{}",
           "Generate runtime calls to a named set of conversion routines. "
           "By default, the conversions may produce unexpected results.">
  ];
}

def CFGConversion : Pass<"cfg-conversion", "::mlir::func::FuncOp"> {
  let summary = "Convert FIR structured control flow ops to CFG ops.";
  let description = [{
    Transform the `fir.do_loop`, `fir.if`, `fir.iterate_while` and
    `fir.select_type` ops into plain old test and branch operations. Removing
    the high-level control structures can enable other optimizations.

    This pass is required before code gen to the LLVM IR dialect.
  }];
  let constructor = "::fir::createFirToCfgPass()";
  let dependentDialects = [
    "fir::FIROpsDialect", "mlir::func::FuncDialect"
  ];
  let options = [
    Option<"forceLoopToExecuteOnce", "always-execute-loop-body", "bool",
           /*default=*/"false",
           "force the body of a loop to execute at least once">
  ];
}

def ExternalNameConversion : Pass<"external-name-interop", "mlir::ModuleOp"> {
  let summary = "Convert name for external interoperability";
  let description = [{
    Demangle FIR internal name and mangle them for external interoperability.
  }];
  let constructor = "::fir::createExternalNameConversionPass()";
  let options = [
    Option<"appendUnderscore", "append-underscore",
           "bool", /*default=*/"true",
           "Append trailing underscore to external names.">
  ];
}

def MemRefDataFlowOpt : Pass<"fir-memref-dataflow-opt", "::mlir::func::FuncOp"> {
  let summary =
    "Perform store/load forwarding and potentially removing dead stores.";
  let description = [{
    This pass performs store to load forwarding to eliminate memory accesses and
    potentially the entire allocation if all the accesses are forwarded.
  }];
  let constructor = "::fir::createMemDataFlowOptPass()";
  let dependentDialects = [
    "fir::FIROpsDialect", "mlir::func::FuncDialect"
  ];
}

// This needs to be a "mlir::ModuleOp" pass, because we are creating debug for
// the module in this pass.
def AddDebugFoundation : Pass<"add-debug-foundation", "mlir::ModuleOp"> {
  let summary = "Add the foundation for debug info";
  let description = [{
    Add the foundation for emitting debug info that can be understood by llvm.
  }];
  let constructor = "::fir::createAddDebugFoundationPass()";
  let dependentDialects = [
    "fir::FIROpsDialect", "mlir::func::FuncDialect", "mlir::LLVM::LLVMDialect"
  ];
}

// This needs to be a "mlir::ModuleOp" pass, because it inserts simplified
// functions into the module, which is invalid if a finer grain mlir::Operation
// is used as the pass specification says to not touch things outside hte scope
// of the operation being processed.
def SimplifyIntrinsics : Pass<"simplify-intrinsics", "mlir::ModuleOp"> {
  let summary = "Intrinsics simplification";
  let description = [{
    Qualifying intrinsics calls are replaced with calls to a specialized and
    simplified function. The simplified function is added to the current module.
    This function can be inlined by a general purpose inlining pass.
  }];
  let constructor = "::fir::createSimplifyIntrinsicsPass()";

  let options = [
    Option<"enableExperimental", "enable-experimental", "bool",
           /*default=*/"false",
           "Enable experimental code that may not always work correctly">
  ];
}

def MemoryAllocationOpt : Pass<"memory-allocation-opt", "mlir::func::FuncOp"> {
  let summary = "Convert stack to heap allocations and vice versa.";
  let description = [{
    Convert stack allocations to heap allocations and vice versa based on
    estimated size, lifetime, usage patterns, the call tree, etc.
  }];
  let dependentDialects = [ "fir::FIROpsDialect" ];
  let options = [
    Option<"dynamicArrayOnHeap", "dynamic-array-on-heap",
           "bool", /*default=*/"false",
           "Allocate all arrays with runtime determined size on heap.">,
    Option<"maxStackArraySize", "maximum-array-alloc-size",
           "std::size_t", /*default=*/"~static_cast<std::size_t>(0)",
           "Set maximum number of elements of an array allocated on the stack.">
  ];
  let constructor = "::fir::createMemoryAllocationPass()";
}

def StackArrays : Pass<"stack-arrays", "mlir::ModuleOp"> {
  let summary = "Move local array allocations from heap memory into stack memory";
  let description = [{
    Convert heap allocations for arrays, even those of unknown size, into stack
    allocations.
  }];
  let dependentDialects = [ "fir::FIROpsDialect" ];
  let constructor = "::fir::createStackArraysPass()";
}

def SimplifyRegionLite : Pass<"simplify-region-lite", "mlir::ModuleOp"> {
  let summary = "Region simplification";
  let description = [{
    Run region DCE and erase unreachable blocks in regions.
  }];
  let constructor = "::fir::createSimplifyRegionLitePass()";
}

def AlgebraicSimplification : Pass<"flang-algebraic-simplification"> {
  let summary = "";
  let description = [{
    Run algebraic simplifications for Math/Complex/etc. dialect operations.
    This is a flang specific pass, because we may want to "tune"
    the rewrite patterns specifically for Fortran (e.g. increase
    the limit for constant exponent value that defines the cases
    when pow(x, constant) is transformed into a set of multiplications, etc.).
  }];
  let dependentDialects = [ "mlir::math::MathDialect" ];
  let constructor = "::fir::createAlgebraicSimplificationPass()";
}

def PolymorphicOpConversion : Pass<"fir-polymorphic-op", "::mlir::func::FuncOp"> {
  let summary =
    "Simplify operations on polymorphic types";
  let description = [{
    This pass breaks up the lowering of operations on polymorphic types by 
    introducing an intermediate FIR level that simplifies code geneation. 
  }];
  let constructor = "::fir::createPolymorphicOpConversionPass()";
  let dependentDialects = [
    "fir::FIROpsDialect", "mlir::func::FuncDialect"
  ];
}

def OpenACCDataOperandConversion : Pass<"fir-openacc-data-operand-conversion", "::mlir::func::FuncOp"> {
  let summary = "Convert the FIR operands in OpenACC ops to LLVM dialect";
  let dependentDialects = ["mlir::LLVM::LLVMDialect"];
  let options = [
    Option<"useOpaquePointers", "use-opaque-pointers", "bool",
           /*default=*/"true", "Generate LLVM IR using opaque pointers "
           "instead of typed pointers">,
  ];
}

def LoopVersioning : Pass<"loop-versioning", "mlir::func::FuncOp"> {
  let summary = "Loop Versioning";
  let description = [{
    Loop Versioning pass adds a check and two variants of a loop when the input
    array is an assumed shape array, to optimize for the (often common) case where
    an array has element sized stride. The element sizes stride allows some
    loops to be vectorized as well as other loop optimizations.
  }];
  let constructor = "::fir::createLoopVersioningPass()";
  let dependentDialects = [ "fir::FIROpsDialect" ];
}

#endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES