1//===- AffineOps.td - Affine operation definitions ---------*- 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// Defines MLIR affine operations.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef AFFINE_OPS
14#define AFFINE_OPS
15
16include "mlir/Dialect/StandardOps/IR/StandardOpsBase.td"
17include "mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.td"
18include "mlir/Interfaces/ControlFlowInterfaces.td"
19include "mlir/Interfaces/LoopLikeInterface.td"
20include "mlir/Interfaces/SideEffectInterfaces.td"
21
22def Affine_Dialect : Dialect {
23  let name = "affine";
24  let cppNamespace = "";
25  let hasConstantMaterializer = 1;
26}
27
28// Base class for Affine dialect ops.
29class Affine_Op<string mnemonic, list<OpTrait> traits = []> :
30    Op<Affine_Dialect, mnemonic, traits> {
31  // For every affine op, there needs to be a:
32  //   * void print(OpAsmPrinter &p, ${C++ class of Op} op)
33  //   * LogicalResult verify(${C++ class of Op} op)
34  //   * ParseResult parse${C++ class of Op}(OpAsmParser &parser,
35  //                                         OperationState &result)
36  // functions.
37  let printer = [{ return ::print(p, *this); }];
38  let verifier = [{ return ::verify(*this); }];
39  let parser = [{ return ::parse$cppClass(parser, result); }];
40}
41
42// Require regions to have affine.yield.
43def ImplicitAffineTerminator
44    : SingleBlockImplicitTerminator<"AffineYieldOp">;
45
46def AffineApplyOp : Affine_Op<"apply", [NoSideEffect]> {
47  let summary = "affine apply operation";
48  let description = [{
49    The affine.apply operation applies an [affine mapping](#affine-expressions)
50    to a list of SSA values, yielding a single SSA value. The number of
51    dimension and symbol arguments to `affine.apply` must be equal to the
52    respective number of dimensional and symbolic inputs to the affine mapping;
53    the affine mapping has to be one-dimensional, and so the `affine.apply`
54    operation always returns one value. The input operands and result must all
55    have ‘index’ type.
56
57    Example:
58
59    ```mlir
60    #map10 = affine_map<(d0, d1) -> (d0 floordiv 8 + d1 floordiv 128)>
61    ...
62    %1 = affine.apply #map10 (%s, %t)
63
64    // Inline example.
65    %2 = affine.apply affine_map<(i)[s0] -> (i+s0)> (%42)[%n]
66    ```
67  }];
68  let arguments = (ins AffineMapAttr:$map, Variadic<Index>:$mapOperands);
69  let results = (outs Index);
70
71  // TODO: The auto-generated builders should check to see if the return type
72  // has a constant builder. That way we wouldn't need to explicitly specify the
73  // result types here.
74  let builders = [
75    OpBuilderDAG<(ins "AffineMap":$map, "ValueRange":$mapOperands),
76    [{
77      build($_builder, $_state, $_builder.getIndexType(), map, mapOperands);
78    }]>
79  ];
80
81  let extraClassDeclaration = [{
82    /// Returns the affine map to be applied by this operation.
83    AffineMap getAffineMap() { return map(); }
84
85    /// Returns the affine value map computed from this operation.
86    AffineValueMap getAffineValueMap();
87
88    /// Returns true if the result of this operation can be used as dimension id
89    /// in the region of the closest surrounding op with trait AffineScope.
90    bool isValidDim();
91
92    /// Returns true if the result of this operation can be used as dimension id
93    /// within 'region', i.e., for all its uses with `region`.
94    bool isValidDim(Region *region);
95
96    /// Returns true if the result of this operation is a symbol in the region
97    /// of the closest surrounding op that has the trait AffineScope.
98    bool isValidSymbol();
99
100    /// Returns true if the result of this operation is a symbol for all its
101    /// uses in `region`.
102    bool isValidSymbol(Region *region);
103
104    operand_range getMapOperands() { return getOperands(); }
105  }];
106
107  let hasCanonicalizer = 1;
108  let hasFolder = 1;
109}
110
111def AffineForOp : Affine_Op<"for",
112    [ImplicitAffineTerminator, RecursiveSideEffects,
113     DeclareOpInterfaceMethods<LoopLikeOpInterface>]> {
114  let summary = "for operation";
115  let description = [{
116    Syntax:
117
118    ```
119    operation   ::= `affine.for` ssa-id `=` lower-bound `to` upper-bound
120                    (`step` integer-literal)? `{` op* `}`
121
122    lower-bound ::= `max`? affine-map-attribute dim-and-symbol-use-list | shorthand-bound
123    upper-bound ::= `min`? affine-map-attribute dim-and-symbol-use-list | shorthand-bound
124    shorthand-bound ::= ssa-id | `-`? integer-literal
125    ```
126
127    The `affine.for` operation represents an affine loop nest. It has one region
128    containing its body. This region must contain one block that terminates with
129    [`affine.yield`](#affineyield-affineyieldop). *Note:* when
130    `affine.for` is printed in custom format, the terminator is omitted. The
131    block has one argument of [`index`](../LangRef.md#index-type) type that
132    represents the induction variable of the loop.
133
134    The `affine.for` operation executes its body a number of times iterating
135    from a lower bound to an upper bound by a stride. The stride, represented by
136    `step`, is a positive constant integer which defaults to "1" if not present.
137    The lower and upper bounds specify a half-open range: the range includes the
138    lower bound but does not include the upper bound.
139
140    The lower and upper bounds of a `affine.for` operation are represented as an
141    application of an affine mapping to a list of SSA values passed to the map.
142    The [same restrictions](#restrictions-on-dimensions-and-symbols) hold for
143    these SSA values as for all bindings of SSA values to dimensions and
144    symbols.
145
146    The affine mappings for the bounds may return multiple results, in which
147    case the `max`/`min` keywords are required (for the lower/upper bound
148    respectively), and the bound is the maximum/minimum of the returned values.
149    There is no semantic ambiguity, but MLIR syntax requires the use of these
150    keywords to make things more obvious to human readers.
151
152    Many upper and lower bounds are simple, so MLIR accepts two custom form
153    syntaxes: the form that accepts a single 'ssa-id' (e.g. `%N`) is shorthand
154    for applying that SSA value to a function that maps a single symbol to
155    itself, e.g., `()[s]->(s)()[%N]`. The integer literal form (e.g. `-42`) is
156    shorthand for a nullary mapping function that returns the constant value
157    (e.g. `()->(-42)()`).
158
159    Example showing reverse iteration of the inner loop:
160
161    ```mlir
162    #map57 = affine_map<(d0)[s0] -> (s0 - d0 - 1)>
163
164    func @simple_example(%A: memref<?x?xf32>, %B: memref<?x?xf32>) {
165      %N = dim %A, 0 : memref<?x?xf32>
166      affine.for %i = 0 to %N step 1 {
167        affine.for %j = 0 to %N {   // implicitly steps by 1
168          %0 = affine.apply #map57(%j)[%N]
169          %tmp = call @F1(%A, %i, %0) : (memref<?x?xf32>, index, index)->(f32)
170          call @F2(%tmp, %B, %i, %0) : (f32, memref<?x?xf32>, index, index)->()
171        }
172      }
173      return
174    }
175    ```
176    `affine.for` can also operate on loop-carried variables and return the final
177    values after loop termination. The initial values of the variables are
178    passed as additional SSA operands to the "affine.for" following the 2 loop
179    control values lower bound, upper bound. The operation region has equivalent
180    arguments for each variable representing the value of the variable at the
181    current iteration.
182
183    The region must terminate with an `affine.yield` that passes all the current
184    iteration variables to the next iteration, or to the `affine.for` result, if
185    at the last iteration.
186
187    `affine.for` results hold the final values after the last iteration.
188    For example, to sum-reduce a memref:
189
190     ```mlir
191    func @reduce(%buffer: memref<1024xf32>) -> (f32) {
192      // Initial sum set to 0.
193      %sum_0 = constant 0.0 : f32
194      // iter_args binds initial values to the loop's region arguments.
195      %sum = affine.for %i = 0 to 10 step 2
196          iter_args(%sum_iter = %sum_0) -> (f32) {
197        %t = affine.load %buffer[%i] : memref<1024xf32>
198        %sum_next = addf %sum_iter, %t : f32
199        // Yield current iteration sum to next iteration %sum_iter or to %sum
200        // if final iteration.
201        affine.yield %sum_next : f32
202      }
203      return %sum : f32
204    }
205    ```
206    If the `affine.for` defines any values, a yield terminator must be
207    explicitly present. The number and types of the "affine.for" results must
208    match the initial values in the `iter_args` binding and the yield operands.
209  }];
210  let arguments = (ins Variadic<AnyType>);
211  let results = (outs Variadic<AnyType>:$results);
212  let regions = (region SizedRegion<1>:$region);
213
214  let skipDefaultBuilders = 1;
215  let builders = [
216    OpBuilderDAG<(ins "int64_t":$lowerBound, "int64_t":$upperBound,
217      CArg<"int64_t", "1">:$step, CArg<"ValueRange", "llvm::None">:$iterArgs,
218      CArg<"function_ref<void(OpBuilder &, Location, Value, ValueRange)>",
219           "nullptr">:$bodyBuilder)>,
220    OpBuilderDAG<(ins "ValueRange":$lbOperands, "AffineMap":$lbMap,
221      "ValueRange":$ubOperands, "AffineMap":$ubMap, CArg<"int64_t", "1">:$step,
222      CArg<"ValueRange", "llvm::None">:$iterArgs,
223      CArg<"function_ref<void(OpBuilder &, Location, Value, ValueRange)>",
224           "nullptr">:$bodyBuilder)>
225  ];
226
227  let extraClassDeclaration = [{
228    /// Defining the function type we use for building the body of affine.for.
229    using BodyBuilderFn =
230        function_ref<void(OpBuilder &, Location, Value, ValueRange)>;
231
232    static StringRef getStepAttrName() { return "step"; }
233    static StringRef getLowerBoundAttrName() { return "lower_bound"; }
234    static StringRef getUpperBoundAttrName() { return "upper_bound"; }
235
236    Value getInductionVar() { return getBody()->getArgument(0); }
237    Block::BlockArgListType getRegionIterArgs() {
238      return getBody()->getArguments().drop_front();
239    }
240    Operation::operand_range getIterOperands() {
241      return getOperands().drop_front(getNumControlOperands());
242    }
243
244    // TODO: provide iterators for the lower and upper bound operands
245    // if the current access via getLowerBound(), getUpperBound() is too slow.
246
247    /// Returns operands for the lower bound map.
248    operand_range getLowerBoundOperands();
249
250    /// Returns operands for the upper bound map.
251    operand_range getUpperBoundOperands();
252
253    /// Returns information about the lower bound as a single object.
254    AffineBound getLowerBound();
255
256    /// Returns information about the upper bound as a single object.
257    AffineBound getUpperBound();
258
259    /// Returns loop step.
260    int64_t getStep() {
261      return (*this)->getAttr(getStepAttrName()).cast<IntegerAttr>().getInt();
262    }
263
264    /// Returns affine map for the lower bound.
265    AffineMap getLowerBoundMap() { return getLowerBoundMapAttr().getValue(); }
266    AffineMapAttr getLowerBoundMapAttr() {
267      return (*this)->getAttr(getLowerBoundAttrName()).cast<AffineMapAttr>();
268    }
269    /// Returns affine map for the upper bound. The upper bound is exclusive.
270    AffineMap getUpperBoundMap() { return getUpperBoundMapAttr().getValue(); }
271    AffineMapAttr getUpperBoundMapAttr() {
272      return (*this)->getAttr(getUpperBoundAttrName()).cast<AffineMapAttr>();
273    }
274
275    /// Set lower bound. The new bound must have the same number of operands as
276    /// the current bound map. Otherwise, 'replaceForLowerBound' should be used.
277    void setLowerBound(ValueRange operands, AffineMap map);
278    /// Set upper bound. The new bound must not have more operands than the
279    /// current bound map. Otherwise, 'replaceForUpperBound' should be used.
280    void setUpperBound(ValueRange operands, AffineMap map);
281
282    /// Set the lower bound map without changing operands.
283    void setLowerBoundMap(AffineMap map);
284
285    /// Set the upper bound map without changing operands.
286    void setUpperBoundMap(AffineMap map);
287
288    /// Set loop step.
289    void setStep(int64_t step) {
290      assert(step > 0 && "step has to be a positive integer constant");
291      auto *context = getLowerBoundMap().getContext();
292      (*this)->setAttr(Identifier::get(getStepAttrName(), context),
293                       IntegerAttr::get(IndexType::get(context), step));
294    }
295
296    /// Returns number of region arguments for loop-carried values.
297    unsigned getNumRegionIterArgs() {
298      return getBody()->getNumArguments() - 1;
299    }
300
301    /// Number of operands controlling the loop: lb and ub.
302    unsigned getNumControlOperands() { return getOperation()->getNumOperands() - getNumIterOperands(); }
303
304    /// Get the number of loop-carried values.
305    unsigned getNumIterOperands();
306
307    /// Returns true if the lower bound is constant.
308    bool hasConstantLowerBound();
309    /// Returns true if the upper bound is constant.
310    bool hasConstantUpperBound();
311    /// Returns true if both bounds are constant.
312    bool hasConstantBounds() {
313      return hasConstantLowerBound() && hasConstantUpperBound();
314    }
315    /// Returns the value of the constant lower bound.
316    /// Fails assertion if the bound is non-constant.
317    int64_t getConstantLowerBound();
318    /// Returns the value of the constant upper bound. The upper bound is
319    /// exclusive. Fails assertion if the bound is non-constant.
320    int64_t getConstantUpperBound();
321    /// Sets the lower bound to the given constant value.
322    void setConstantLowerBound(int64_t value);
323    /// Sets the upper bound to the given constant value.
324    void setConstantUpperBound(int64_t value);
325
326    /// Returns true if both the lower and upper bound have the same operand
327    /// lists (same operands in the same order).
328    bool matchingBoundOperandList();
329  }];
330
331  let hasCanonicalizer = 1;
332  let hasFolder = 1;
333}
334
335def AffineIfOp : Affine_Op<"if",
336                           [ImplicitAffineTerminator, RecursiveSideEffects,
337                            NoRegionArguments]> {
338  let summary = "if-then-else operation";
339  let description = [{
340    Syntax:
341
342    ```
343    operation  ::= `affine.if` if-op-cond `{` op* `}` (`else` `{` op* `}`)?
344    if-op-cond ::= integer-set-attr dim-and-symbol-use-list
345    ```
346
347    The `affine.if` operation restricts execution to a subset of the loop
348    iteration space defined by an integer set (a conjunction of affine
349    constraints). A single `affine.if` may end with an optional `else` clause.
350
351    The condition of the `affine.if` is represented by an
352    [integer set](#integer-sets) (a conjunction of affine constraints),
353    and the SSA values bound to the dimensions and symbols in the integer set.
354    The [same restrictions](#restrictions-on-dimensions-and-symbols) hold for
355    these SSA values as for all bindings of SSA values to dimensions and
356    symbols.
357
358    The `affine.if` operation contains two regions for the "then" and "else"
359    clauses.  `affine.if` may return results that are defined in its regions.
360    The values defined are determined by which execution path is taken.  Each
361    region of the `affine.if` must contain a single block with no arguments,
362    and be terminated by `affine.yield`.  If `affine.if` defines no values,
363    the `affine.yield` can be left out, and will be inserted implicitly.
364    Otherwise, it must be explicit.  If no values are defined, the else block
365    may be empty (i.e. contain no blocks).
366
367    Example:
368
369    ```mlir
370    #set = affine_set<(d0, d1)[s0]: (d0 - 10 >= 0, s0 - d0 - 9 >= 0,
371                                     d1 - 10 >= 0, s0 - d1 - 9 >= 0)>
372    func @reduced_domain_example(%A, %X, %N) : (memref<10xi32>, i32, i32) {
373      affine.for %i = 0 to %N {
374         affine.for %j = 0 to %N {
375           %0 = affine.apply #map42(%j)
376           %tmp = call @S1(%X, %i, %0)
377           affine.if #set(%i, %j)[%N] {
378              %1 = affine.apply #map43(%i, %j)
379              call @S2(%tmp, %A, %i, %1)
380           }
381        }
382      }
383      return
384    }
385    ```
386
387    Example with an explicit yield (initialization with edge padding):
388
389    ```mlir
390    #interior = affine_set<(i, j) : (i - 1 >= 0, j - 1 >= 0,  10 - i >= 0, 10 - j >= 0)> (%i, %j)
391    func @pad_edges(%I : memref<10x10xf32>) -> (memref<12x12xf32) {
392      %O = alloc memref<12x12xf32>
393      affine.parallel (%i, %j) = (0, 0) to (12, 12) {
394        %1 = affine.if #interior (%i, %j) {
395          %2 = load %I[%i - 1, %j - 1] : memref<10x10xf32>
396          affine.yield %2
397        } else {
398          %2 = constant 0.0 : f32
399          affine.yield %2 : f32
400        }
401        affine.store %1, %O[%i, %j] : memref<12x12xf32>
402      }
403      return %O
404    }
405    ```
406  }];
407  let arguments = (ins Variadic<AnyType>);
408  let results = (outs Variadic<AnyType>:$results);
409  let regions = (region SizedRegion<1>:$thenRegion, AnyRegion:$elseRegion);
410
411  let skipDefaultBuilders = 1;
412
413  let builders = [
414    OpBuilderDAG<(ins "IntegerSet":$set, "ValueRange":$args,
415      "bool":$withElseRegion)>,
416    OpBuilderDAG<(ins "TypeRange":$resultTypes, "IntegerSet":$set,
417      "ValueRange":$args, "bool":$withElseRegion)>,
418  ];
419
420  let extraClassDeclaration = [{
421    static StringRef getConditionAttrName() { return "condition"; }
422
423    IntegerSet getIntegerSet();
424    void setIntegerSet(IntegerSet newSet);
425
426    /// Sets the integer set with its operands.
427    void setConditional(IntegerSet set, ValueRange operands);
428
429    /// Returns true if an else block exists.
430    bool hasElse() { return !elseRegion().empty(); }
431
432    Block *getThenBlock() {
433      assert(!thenRegion().empty() && "Unexpected empty 'then' region.");
434      return &thenRegion().front();
435    }
436
437    Block *getElseBlock() {
438      assert(hasElse() && "Empty 'else' region.");
439      return &elseRegion().front();
440    }
441
442    OpBuilder getThenBodyBuilder() {
443      assert(!thenRegion().empty() && "Unexpected empty 'then' region.");
444      Block &body = thenRegion().front();
445      return OpBuilder(&body, std::prev(body.end()));
446    }
447    OpBuilder getElseBodyBuilder() {
448      assert(hasElse() && "No 'else' block");
449      Block &body = elseRegion().front();
450      return OpBuilder(&body, std::prev(body.end()));
451    }
452  }];
453
454  let hasCanonicalizer = 1;
455  let hasFolder = 1;
456}
457
458class AffineLoadOpBase<string mnemonic, list<OpTrait> traits = []> :
459    Affine_Op<mnemonic, !listconcat(traits,
460        [DeclareOpInterfaceMethods<AffineReadOpInterface>,
461        MemRefsNormalizable])> {
462  let arguments = (ins Arg<AnyMemRef, "the reference to load from",
463      [MemRead]>:$memref,
464      Variadic<Index>:$indices);
465
466  code extraClassDeclarationBase = [{
467    /// Returns the operand index of the memref.
468    unsigned getMemRefOperandIndex() { return 0; }
469
470    void setMemRef(Value value) { setOperand(getMemRefOperandIndex(), value); }
471
472    /// Returns the affine map used to index the memref for this operation.
473    AffineMapAttr getAffineMapAttr() {
474      return (*this)->getAttr(getMapAttrName()).cast<AffineMapAttr>();
475    }
476
477    static StringRef getMapAttrName() { return "map"; }
478  }];
479}
480
481def AffineLoadOp : AffineLoadOpBase<"load"> {
482  let summary = "affine load operation";
483  let description = [{
484    The "affine.load" op reads an element from a memref, where the index
485    for each memref dimension is an affine expression of loop induction
486    variables and symbols. The output of 'affine.load' is a new value with the
487    same type as the elements of the memref. An affine expression of loop IVs
488    and symbols must be specified for each dimension of the memref. The keyword
489    'symbol' can be used to indicate SSA identifiers which are symbolic.
490
491    Example 1:
492
493    ```mlir
494    %1 = affine.load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>
495    ```
496
497    Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'.
498
499    ```mlir
500    %1 = affine.load %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>
501    ```
502  }];
503
504  let results = (outs AnyType:$result);
505
506  let builders = [
507    /// Builds an affine load op with the specified map and operands.
508    OpBuilderDAG<(ins "AffineMap":$map, "ValueRange":$operands)>,
509    /// Builds an affine load op with an identity map and operands.
510    OpBuilderDAG<(ins "Value":$memref, CArg<"ValueRange", "{}">:$indices)>,
511    /// Builds an affine load op with the specified map and its operands.
512    OpBuilderDAG<(ins "Value":$memref, "AffineMap":$map,
513      "ValueRange":$mapOperands)>
514  ];
515
516  let extraClassDeclaration = extraClassDeclarationBase;
517
518  let hasCanonicalizer = 1;
519  let hasFolder = 1;
520}
521
522class AffineMinMaxOpBase<string mnemonic, list<OpTrait> traits = []> :
523    Op<Affine_Dialect, mnemonic, traits> {
524  let arguments = (ins AffineMapAttr:$map, Variadic<Index>:$operands);
525  let results = (outs Index);
526
527  let builders = [
528    OpBuilderDAG<(ins "AffineMap":$affineMap, "ValueRange":$mapOperands),
529    [{
530      build($_builder, $_state, $_builder.getIndexType(), affineMap, mapOperands);
531    }]>
532  ];
533
534  let extraClassDeclaration = [{
535    static StringRef getMapAttrName() { return "map"; }
536    AffineMap getAffineMap() { return map(); }
537    ValueRange getMapOperands() { return operands(); }
538    ValueRange getDimOperands() {
539      return OperandRange{operands().begin(),
540                        operands().begin() + map().getNumDims()};
541    }
542    ValueRange getSymbolOperands() {
543      return OperandRange{operands().begin() + map().getNumDims(),
544                        operands().end()};
545    }
546  }];
547  let verifier = [{ return ::verifyAffineMinMaxOp(*this); }];
548  let printer = [{ return ::printAffineMinMaxOp(p, *this); }];
549  let parser = [{ return ::parseAffineMinMaxOp<$cppClass>(parser, result); }];
550  let hasFolder = 1;
551  let hasCanonicalizer = 1;
552}
553
554def AffineMinOp : AffineMinMaxOpBase<"min", [NoSideEffect]> {
555  let summary = "min operation";
556  let description = [{
557    Syntax:
558
559    ```
560    operation ::= ssa-id `=` `affine.min` affine-map-attribute dim-and-symbol-use-list
561    ```
562
563    The `affine.min` operation applies an [affine mapping](#affine-expressions)
564    to a list of SSA values, and returns the minimum value of all result
565    expressions. The number of dimension and symbol arguments to `affine.min`
566    must be equal to the respective number of dimensional and symbolic inputs to
567    the affine mapping; the `affine.min` operation always returns one value. The
568    input operands and result must all have 'index' type.
569
570    Example:
571
572    ```mlir
573    %0 = affine.min affine_map<(d0)[s0] -> (1000, d0 + 512, s0)> (%arg0)[%arg1]
574    ```
575  }];
576}
577
578def AffineMaxOp : AffineMinMaxOpBase<"max", [NoSideEffect]> {
579  let summary = "max operation";
580  let description = [{
581    The "max" operation computes the maximum value result from a multi-result
582    affine map.
583
584    Example:
585
586    ```mlir
587    %0 = affine.max (d0) -> (1000, d0 + 512) (%i0) : index
588    ```
589  }];
590}
591
592def AffineParallelOp : Affine_Op<"parallel",
593    [ImplicitAffineTerminator, RecursiveSideEffects,
594     DeclareOpInterfaceMethods<LoopLikeOpInterface>]> {
595  let summary = "multi-index parallel band operation";
596  let description = [{
597    The "affine.parallel" operation represents a hyper-rectangular affine
598    parallel band, defining multiple SSA values for its induction variables. It
599    has one region capturing the parallel band body. The induction variables are
600    represented as arguments of this region. These SSA values always have type
601    index, which is the size of the machine word. The strides, represented by
602    steps, are positive constant integers which defaults to "1" if not present.
603    The lower and upper bounds specify a half-open range: the range includes the
604    lower bound but does not include the upper bound. The body region must
605    contain exactly one block that terminates with "affine.yield".
606
607    The lower and upper bounds of a parallel operation are represented as an
608    application of an affine mapping to a list of SSA values passed to the map.
609    The same restrictions hold for these SSA values as for all bindings of SSA
610    values to dimensions and symbols.
611
612    Each value yielded by affine.yield will be accumulated/reduced via one of
613    the reduction methods defined in the AtomicRMWKind enum.  The order of
614    reduction is unspecified, and lowering may produce any valid ordering.
615    Loops with a 0 trip count will produce as a result the identity value
616    associated with each reduction (i.e. 0.0 for addf, 1.0 for mulf).  Assign
617    reductions for loops with a trip count != 1 produces undefined results.
618
619    Note: Calling AffineParallelOp::build will create the required region and
620    block, and insert the required terminator if it is trivial (i.e. no values
621    are yielded).  Parsing will also create the required region, block, and
622    terminator, even when they are missing from the textual representation.
623
624    Example (3x3 valid convolution):
625
626    ```mlir
627    func @conv_2d(%D : memref<100x100xf32>, %K : memref<3x3xf32>) -> (memref<98x98xf32>) {
628      %O = alloc memref<98x98xf32>
629      affine.parallel (%x, %y) = (0, 0) to (98, 98) {
630        %0 = affine.parallel (%kx, %ky) = (0, 0) to (2, 2) reduce ("addf") {
631          %1 = affine.load %D[%x + %kx, %y + %ky] : memref<100x100xf32>
632          %2 = affine.load %K[%kx, %ky] : memref<3x3xf32>
633          %3 = mulf %1, %2 : f32
634          affine.yield %3 : f32
635        }
636        affine.store %0, O[%x, %y] : memref<98x98xf32>
637      }
638      return %O
639    }
640    ```
641  }];
642
643  let arguments = (ins
644     TypedArrayAttrBase<AtomicRMWKindAttr, "Reduction ops">:$reductions,
645     AffineMapAttr:$lowerBoundsMap,
646     AffineMapAttr:$upperBoundsMap,
647     I64ArrayAttr:$steps,
648     Variadic<Index>:$mapOperands);
649  let results = (outs Variadic<AnyType>:$results);
650  let regions = (region SizedRegion<1>:$region);
651
652  let builders = [
653    OpBuilderDAG<(ins "TypeRange":$resultTypes,
654      "ArrayRef<AtomicRMWKind>":$reductions, "ArrayRef<int64_t>":$ranges)>,
655    OpBuilderDAG<(ins "TypeRange":$resultTypes,
656      "ArrayRef<AtomicRMWKind>":$reductions, "AffineMap":$lbMap,
657      "ValueRange":$lbArgs, "AffineMap":$ubMap, "ValueRange":$ubArgs)>,
658    OpBuilderDAG<(ins "TypeRange":$resultTypes,
659      "ArrayRef<AtomicRMWKind>":$reductions, "AffineMap":$lbMap,
660      "ValueRange":$lbArgs, "AffineMap":$ubMap, "ValueRange":$ubArgs,
661      "ArrayRef<int64_t>":$steps)>
662  ];
663
664  let extraClassDeclaration = [{
665    /// Get the number of dimensions.
666    unsigned getNumDims();
667
668    AffineValueMap getRangesValueMap();
669
670    /// Get ranges as constants, may fail in dynamic case.
671    Optional<SmallVector<int64_t, 8>> getConstantRanges();
672
673    Block *getBody();
674    OpBuilder getBodyBuilder();
675    MutableArrayRef<BlockArgument> getIVs() {
676      return getBody()->getArguments();
677    }
678
679    operand_range getLowerBoundsOperands();
680    AffineValueMap getLowerBoundsValueMap();
681    void setLowerBounds(ValueRange operands, AffineMap map);
682    void setLowerBoundsMap(AffineMap map);
683
684    operand_range getUpperBoundsOperands();
685    AffineValueMap getUpperBoundsValueMap();
686    void setUpperBounds(ValueRange operands, AffineMap map);
687    void setUpperBoundsMap(AffineMap map);
688
689    SmallVector<int64_t, 8> getSteps();
690    void setSteps(ArrayRef<int64_t> newSteps);
691
692    static StringRef getReductionsAttrName() { return "reductions"; }
693    static StringRef getLowerBoundsMapAttrName() { return "lowerBoundsMap"; }
694    static StringRef getUpperBoundsMapAttrName() { return "upperBoundsMap"; }
695    static StringRef getStepsAttrName() { return "steps"; }
696  }];
697
698  let hasFolder = 1;
699}
700
701def AffinePrefetchOp : Affine_Op<"prefetch"> {
702  let summary = "affine prefetch operation";
703  let description = [{
704    The "affine.prefetch" op prefetches data from a memref location described
705    with an affine subscript similar to affine.load, and has three attributes:
706    a read/write specifier, a locality hint, and a cache type specifier as shown
707    below:
708
709    ```mlir
710    affine.prefetch %0[%i, %j + 5], read, locality<3>, data : memref<400x400xi32>
711    ```
712
713    The read/write specifier is either 'read' or 'write', the locality hint
714    specifier ranges from locality<0> (no locality) to locality<3> (extremely
715    local keep in cache). The cache type specifier is either 'data' or 'instr'
716    and specifies whether the prefetch is performed on data cache or on
717    instruction cache.
718  }];
719
720  let arguments = (ins AnyMemRef:$memref, Variadic<Index>:$indices,
721                   BoolAttr:$isWrite,
722                   Confined<I32Attr, [IntMinValue<0>,
723                     IntMaxValue<3>]>:$localityHint,
724                   BoolAttr:$isDataCache);
725
726  let builders = [
727    OpBuilderDAG<(ins "Value":$memref, "AffineMap":$map,
728      "ArrayRef<Value>":$mapOperands, "bool":$isWrite, "unsigned":$localityHint,
729      "bool":$isDataCache),
730    [{
731      assert(map.getNumInputs() == mapOperands.size()
732             && "inconsistent index info");
733      auto localityHintAttr = $_builder.getI32IntegerAttr(localityHint);
734      auto isWriteAttr = $_builder.getBoolAttr(isWrite);
735      auto isDataCacheAttr = $_builder.getBoolAttr(isDataCache);
736      $_state.addOperands(memref);
737      $_state.addAttribute(getMapAttrName(), AffineMapAttr::get(map));
738      $_state.addOperands(mapOperands);
739      $_state.addAttribute(getLocalityHintAttrName(), localityHintAttr);
740      $_state.addAttribute(getIsWriteAttrName(), isWriteAttr);
741      $_state.addAttribute(getIsDataCacheAttrName(), isDataCacheAttr);
742    }]>];
743
744  let extraClassDeclaration = [{
745    MemRefType getMemRefType() {
746      return memref().getType().cast<MemRefType>();
747    }
748
749    /// Returns the affine map used to index the memref for this operation.
750    AffineMap getAffineMap() { return getAffineMapAttr().getValue(); }
751    AffineMapAttr getAffineMapAttr() {
752      return (*this)->getAttr(getMapAttrName()).cast<AffineMapAttr>();
753    }
754
755    /// Returns the AffineMapAttr associated with 'memref'.
756    NamedAttribute getAffineMapAttrForMemRef(Value mref) {
757      assert(mref == memref());
758      return {Identifier::get(getMapAttrName(), getContext()),
759        getAffineMapAttr()};
760    }
761
762    /// Get affine map operands.
763    operand_range getMapOperands() {
764      return {operand_begin() + 1, operand_end()};
765    }
766
767    static StringRef getMapAttrName() { return "map"; }
768    static StringRef getLocalityHintAttrName() { return "localityHint"; }
769    static StringRef getIsWriteAttrName() { return "isWrite"; }
770    static StringRef getIsDataCacheAttrName() { return "isDataCache"; }
771  }];
772
773  let hasCanonicalizer = 1;
774  let hasFolder = 1;
775}
776
777class AffineStoreOpBase<string mnemonic, list<OpTrait> traits = []> :
778    Affine_Op<mnemonic, !listconcat(traits,
779    [DeclareOpInterfaceMethods<AffineWriteOpInterface>,
780    MemRefsNormalizable])> {
781  code extraClassDeclarationBase = [{
782    /// Returns the operand index of the value to be stored.
783    unsigned getStoredValOperandIndex() { return 0; }
784
785    /// Returns the operand index of the memref.
786    unsigned getMemRefOperandIndex() { return 1; }
787
788    void setMemRef(Value value) { setOperand(getMemRefOperandIndex(), value); }
789
790    /// Returns the affine map used to index the memref for this operation.
791    AffineMapAttr getAffineMapAttr() {
792      return (*this)->getAttr(getMapAttrName()).cast<AffineMapAttr>();
793    }
794
795    /// Returns the AffineMapAttr associated with 'memref'.
796    NamedAttribute getAffineMapAttrForMemRef(Value memref) {
797      assert(memref == getMemRef());
798      return {Identifier::get(getMapAttrName(), getContext()),
799              getAffineMapAttr()};
800    }
801
802    static StringRef getMapAttrName() { return "map"; }
803  }];
804}
805
806def AffineStoreOp : AffineStoreOpBase<"store"> {
807  let summary = "affine store operation";
808  let description = [{
809    The "affine.store" op writes an element to a memref, where the index
810    for each memref dimension is an affine expression of loop induction
811    variables and symbols. The 'affine.store' op stores a new value which is the
812    same type as the elements of the memref. An affine expression of loop IVs
813    and symbols must be specified for each dimension of the memref. The keyword
814    'symbol' can be used to indicate SSA identifiers which are symbolic.
815
816    Example 1:
817
818    ```mlir
819    affine.store %v0, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>
820    ```
821
822    Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'.
823
824    ```mlir
825    affine.store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>
826    ```
827  }];
828  let arguments = (ins AnyType:$value,
829      Arg<AnyMemRef, "the reference to store to",
830      [MemWrite]>:$memref,
831      Variadic<Index>:$indices);
832
833  let skipDefaultBuilders = 1;
834  let builders = [
835    OpBuilderDAG<(ins "Value":$valueToStore, "Value":$memref,
836      "ValueRange":$indices)>,
837    OpBuilderDAG<(ins "Value":$valueToStore, "Value":$memref, "AffineMap":$map,
838      "ValueRange":$mapOperands)>
839  ];
840
841  let extraClassDeclaration = extraClassDeclarationBase;
842
843  let hasCanonicalizer = 1;
844  let hasFolder = 1;
845}
846
847def AffineYieldOp : Affine_Op<"yield", [NoSideEffect, Terminator, ReturnLike]> {
848  let summary = "Yield values to parent operation";
849  let description = [{
850    "affine.yield" yields zero or more SSA values from an affine op region and
851    terminates the region. The semantics of how the values yielded are used
852    is defined by the parent operation.
853    If "affine.yield" has any operands, the operands must match the parent
854    operation's results.
855    If the parent operation defines no values, then the "affine.yield" may be
856    left out in the custom syntax and the builders will insert one implicitly.
857    Otherwise, it has to be present in the syntax to indicate which values are
858    yielded.
859    ```
860  }];
861
862  let arguments = (ins Variadic<AnyType>:$operands);
863
864  let builders = [
865    OpBuilderDAG<(ins), [{ build($_builder, $_state, llvm::None); }]>
866  ];
867
868  let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
869}
870
871def AffineVectorLoadOp : AffineLoadOpBase<"vector_load"> {
872  let summary = "affine vector load operation";
873  let description = [{
874    The "affine.vector_load" is the vector counterpart of
875    [affine.load](#affineload-operation). It reads a slice from a
876    [MemRef](../LangRef.md#memref-type), supplied as its first operand,
877    into a [vector](../LangRef.md#vector-type) of the same base elemental type.
878    The index for each memref dimension is an affine expression of loop induction
879    variables and symbols. These indices determine the start position of the read
880    within the memref. The shape of the return vector type determines the shape of
881    the slice read from the memref. This slice is contiguous along the respective
882    dimensions of the shape. Strided vector loads will be supported in the future.
883    An affine expression of loop IVs and symbols must be specified for each
884    dimension of the memref. The keyword 'symbol' can be used to indicate SSA
885    identifiers which are symbolic.
886
887    Example 1: 8-wide f32 vector load.
888
889    ```mlir
890    %1 = affine.vector_load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>, vector<8xf32>
891    ```
892
893    Example 2: 4-wide f32 vector load. Uses 'symbol' keyword for symbols '%n' and '%m'.
894
895    ```mlir
896    %1 = affine.vector_load %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>, vector<4xf32>
897    ```
898
899    Example 3: 2-dim f32 vector load.
900
901    ```mlir
902    %1 = affine.vector_load %0[%i0, %i1] : memref<100x100xf32>, vector<2x8xf32>
903    ```
904
905    TODOs:
906    * Add support for strided vector loads.
907    * Consider adding a permutation map to permute the slice that is read from memory
908    (see [vector.transfer_read](../Vector/#vectortransfer_read-vectortransferreadop)).
909  }];
910
911  let results = (outs AnyVector:$result);
912
913  let builders = [
914    /// Builds an affine vector load op with the specified map and operands.
915    OpBuilderDAG<(ins "VectorType":$resultType, "AffineMap":$map,
916      "ValueRange":$operands)>,
917    /// Builds an affine vector load op with an identity map and operands.
918    OpBuilderDAG<(ins "VectorType":$resultType, "Value":$memref,
919      CArg<"ValueRange", "{}">:$indices)>,
920    /// Builds an affine vector load op with the specified map and its operands.
921    OpBuilderDAG<(ins "VectorType":$resultType, "Value":$memref,
922      "AffineMap":$map, "ValueRange":$mapOperands)>
923  ];
924
925  let extraClassDeclaration = extraClassDeclarationBase # [{
926    VectorType getVectorType() {
927      return result().getType().cast<VectorType>();
928    }
929  }];
930}
931
932def AffineVectorStoreOp : AffineStoreOpBase<"vector_store"> {
933  let summary = "affine vector store operation";
934  let description = [{
935    The "affine.vector_store" is the vector counterpart of
936    [affine.store](#affinestore-affinestoreop). It writes a
937    [vector](../LangRef.md#vector-type), supplied as its first operand,
938    into a slice within a [MemRef](../LangRef.md#memref-type) of the same base
939    elemental type, supplied as its second operand.
940    The index for each memref dimension is an affine expression of loop
941    induction variables and symbols. These indices determine the start position
942    of the write within the memref. The shape of th input vector determines the
943    shape of the slice written to the memref. This slice is contiguous along the
944    respective dimensions of the shape. Strided vector stores will be supported
945    in the future.
946    An affine expression of loop IVs and symbols must be specified for each
947    dimension of the memref. The keyword 'symbol' can be used to indicate SSA
948    identifiers which are symbolic.
949
950    Example 1: 8-wide f32 vector store.
951
952    ```mlir
953    affine.vector_store %v0, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>, vector<8xf32>
954    ```
955
956    Example 2: 4-wide f32 vector store. Uses 'symbol' keyword for symbols '%n' and '%m'.
957
958    ```mlir
959    affine.vector_store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>, vector<4xf32>
960    ```
961
962    Example 3: 2-dim f32 vector store.
963
964    ```mlir
965    affine.vector_store %v0, %0[%i0, %i1] : memref<100x100xf32>, vector<2x8xf32>
966    ```
967
968    TODOs:
969    * Add support for strided vector stores.
970    * Consider adding a permutation map to permute the slice that is written to memory
971    (see [vector.transfer_write](../Vector/#vectortransfer_write-vectortransferwriteop)).
972  }];
973
974  let arguments = (ins AnyVector:$value,
975      Arg<AnyMemRef, "the reference to store to",
976      [MemWrite]>:$memref,
977      Variadic<Index>:$indices);
978
979  let skipDefaultBuilders = 1;
980  let builders = [
981    OpBuilderDAG<(ins "Value":$valueToStore, "Value":$memref,
982      "ValueRange":$indices)>,
983    OpBuilderDAG<(ins "Value":$valueToStore, "Value":$memref, "AffineMap":$map,
984      "ValueRange":$mapOperands)>
985  ];
986
987  let extraClassDeclaration = extraClassDeclarationBase # [{
988    VectorType getVectorType() {
989      return value().getType().cast<VectorType>();
990    }
991  }];
992}
993
994#endif // AFFINE_OPS
995