1//===- SCFTransformOps.td - SCF (loop) transformation ops --*- tablegen -*-===//
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#ifndef SCF_TRANSFORM_OPS
10#define SCF_TRANSFORM_OPS
11
12include "mlir/Dialect/Transform/IR/TransformDialect.td"
13include "mlir/Dialect/Transform/IR/TransformEffects.td"
14include "mlir/Dialect/Transform/IR/TransformInterfaces.td"
15include "mlir/Dialect/PDL/IR/PDLTypes.td"
16include "mlir/Interfaces/SideEffectInterfaces.td"
17include "mlir/IR/OpBase.td"
18
19def GetParentForOp : Op<Transform_Dialect, "loop.get_parent_for",
20    [NavigationTransformOpTrait, MemoryEffectsOpInterface,
21     DeclareOpInterfaceMethods<TransformOpInterface>]> {
22  let summary = "Gets a handle to the parent 'for' loop of the given operation";
23  let description = [{
24    Produces a handle to the n-th (default 1) parent `scf.for` loop for each
25    Payload IR operation associated with the operand. Fails if such a loop
26    cannot be found. The list of operations associated with the handle contains
27    parent operations in the same order as the list associated with the operand,
28    except for operations that are parents to more than one input which are only
29    present once.
30  }];
31
32  let arguments =
33    (ins PDL_Operation:$target,
34         DefaultValuedAttr<Confined<I64Attr, [IntPositive]>,
35                           "1">:$num_loops);
36  let results = (outs PDL_Operation:$parent);
37
38  let assemblyFormat = "$target attr-dict";
39}
40
41def LoopOutlineOp : Op<Transform_Dialect, "loop.outline",
42    [FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface,
43     DeclareOpInterfaceMethods<TransformOpInterface>]> {
44  let summary = "Outlines a loop into a named function";
45  let description = [{
46     Moves the loop into a separate function with the specified name and
47     replaces the loop in the Payload IR with a call to that function. Takes
48     care of forwarding values that are used in the loop as function arguments.
49     If the operand is associated with more than one loop, each loop will be
50     outlined into a separate function. The provided name is used as a _base_
51     for forming actual function names following SymbolTable auto-renaming
52     scheme to avoid duplicate symbols. Expects that all ops in the Payload IR
53     have a SymbolTable ancestor (typically true because of the top-level
54     module). Returns the handle to the list of outlined functions in the same
55     order as the operand handle.
56  }];
57
58  let arguments = (ins PDL_Operation:$target,
59                   StrAttr:$func_name);
60  let results = (outs PDL_Operation:$transformed);
61
62  let assemblyFormat = "$target attr-dict";
63}
64
65def LoopPeelOp : Op<Transform_Dialect, "loop.peel",
66    [FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface,
67     TransformOpInterface, TransformEachOpTrait]> {
68  let summary = "Peels the last iteration of the loop";
69  let description = [{
70     Updates the given loop so that its step evenly divides its range and puts
71     the remaining iteration into a separate loop or a conditional.
72
73     In the absence of sufficient static information, this op may peel a loop,
74     even if the step always divides the range evenly at runtime.
75
76     #### Return modes
77
78     This operation ignores non-scf::ForOp ops and drops them in the return.
79
80     This operation always succeeds and returns the scf::ForOp with the
81     postcondition: "the loop trip count is divisible by the step".
82     This operation may return the same unmodified loop handle when peeling did
83     not modify the IR (i.e. the loop trip count was already divisible).
84
85     Note that even though the Payload IR modification may be performed
86     in-place, this operation consumes the operand handle and produces a new
87     one.
88
89     TODO: Return both the peeled loop and the remainder loop.
90  }];
91
92  let arguments =
93      (ins PDL_Operation:$target,
94           DefaultValuedAttr<BoolAttr, "false">:$fail_if_already_divisible);
95  // TODO: Return both the peeled loop and the remainder loop.
96  let results = (outs PDL_Operation:$transformed);
97
98  let assemblyFormat = "$target attr-dict";
99
100  let extraClassDeclaration = [{
101    ::mlir::DiagnosedSilenceableFailure applyToOne(
102        ::mlir::scf::ForOp target,
103        ::llvm::SmallVector<::mlir::Operation *> &results,
104        ::mlir::transform::TransformState &state);
105  }];
106}
107
108def LoopPipelineOp : Op<Transform_Dialect, "loop.pipeline",
109    [FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface,
110     TransformOpInterface, TransformEachOpTrait]> {
111  let summary = "Applies software pipelining to the loop";
112  let description = [{
113    Transforms the given loops one by one to achieve software pipelining for
114    each of them. That is, performs some amount of reads from memory before the
115    loop rather than inside the loop, the same amount of writes into memory
116    after the loop, and updates each iteration to read the data for a following
117    iteration rather than the current one.
118
119    The amount is specified by the attributes.
120
121    The values read and about to be stored are transferred as loop iteration
122    arguments. Currently supports memref and vector transfer operations as
123    memory reads/writes.
124
125    #### Return modes
126
127    This operation ignores non-scf::For ops and drops them in the return.
128    If all the operations referred to by the `target` PDLOperation pipeline
129    properly, the transform succeeds. Otherwise the transform silently fails.
130    The return handle points to only the subset of successfully produced
131    pipelined loops, which can be empty.
132  }];
133
134  let arguments = (ins PDL_Operation:$target,
135                   DefaultValuedAttr<I64Attr, "1">:$iteration_interval,
136                   DefaultValuedAttr<I64Attr, "10">:$read_latency);
137  let results = (outs PDL_Operation:$transformed);
138
139  let assemblyFormat = "$target attr-dict";
140
141  let extraClassDeclaration = [{
142    ::mlir::DiagnosedSilenceableFailure applyToOne(
143        ::mlir::scf::ForOp target,
144        ::llvm::SmallVector<::mlir::Operation *> &results,
145        ::mlir::transform::TransformState &state);
146  }];
147}
148
149def LoopUnrollOp : Op<Transform_Dialect, "loop.unroll",
150    [FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface,
151     TransformOpInterface, TransformEachOpTrait]> {
152  let summary = "Unrolls the given loop with the given unroll factor";
153  let description = [{
154    Unrolls each loop associated with the given handle to have up to the given
155    number of loop body copies per iteration. If the unroll factor is larger
156    than the loop trip count, the latter is used as the unroll factor instead.
157
158    #### Return modes
159
160    This operation ignores non-scf::For ops and drops them in the return.
161    If all the operations referred to by the `target` PDLOperation unroll
162    properly, the transform succeeds. Otherwise the transform silently fails.
163
164    Does not return handles as the operation may result in the loop being
165    removed after a full unrolling.
166  }];
167
168  let arguments = (ins PDL_Operation:$target,
169                       Confined<I64Attr, [IntPositive]>:$factor);
170
171  let assemblyFormat = "$target attr-dict";
172
173  let extraClassDeclaration = [{
174    ::mlir::DiagnosedSilenceableFailure applyToOne(
175        ::mlir::scf::ForOp target,
176        ::llvm::SmallVector<::mlir::Operation *> &results,
177        ::mlir::transform::TransformState &state);
178  }];
179}
180
181#endif // SCF_TRANSFORM_OPS
182