blob: 1dc7debd9a6cbd7150e2d292d58a59b3b4c99fe5 [file] [log] [blame]
Nicolas Vasilachecca53e82019-07-15 02:50:09 -07001//===- Ops.cpp - Loop MLIR Operations -------------------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17
18#include "mlir/Dialect/LoopOps/LoopOps.h"
River Riddleba0fa922019-08-19 11:00:47 -070019#include "mlir/Dialect/StandardOps/Ops.h"
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070020#include "mlir/IR/AffineExpr.h"
21#include "mlir/IR/AffineMap.h"
22#include "mlir/IR/Builders.h"
23#include "mlir/IR/Function.h"
24#include "mlir/IR/Matchers.h"
25#include "mlir/IR/Module.h"
26#include "mlir/IR/OpImplementation.h"
27#include "mlir/IR/PatternMatch.h"
28#include "mlir/IR/StandardTypes.h"
29#include "mlir/IR/Value.h"
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070030#include "mlir/Support/MathExtras.h"
31#include "mlir/Support/STLExtras.h"
Stephan Herhutb843cc52019-10-16 04:28:13 -070032#include "mlir/Transforms/SideEffectsInterface.h"
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070033
34using namespace mlir;
35using namespace mlir::loop;
36
37//===----------------------------------------------------------------------===//
Stephan Herhutb843cc52019-10-16 04:28:13 -070038// LoopOpsDialect Interfaces
39//===----------------------------------------------------------------------===//
40namespace {
41
42struct LoopSideEffectsInterface : public SideEffectsDialectInterface {
43 using SideEffectsDialectInterface::SideEffectsDialectInterface;
44
45 SideEffecting isSideEffecting(Operation *op) const override {
46 if (isa<IfOp>(op) || isa<ForOp>(op)) {
47 return Recursive;
48 }
49 return SideEffectsDialectInterface::isSideEffecting(op);
50 };
51};
52
53} // namespace
54
55//===----------------------------------------------------------------------===//
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070056// LoopOpsDialect
57//===----------------------------------------------------------------------===//
58
59LoopOpsDialect::LoopOpsDialect(MLIRContext *context)
60 : Dialect(getDialectNamespace(), context) {
61 addOperations<
62#define GET_OP_LIST
63#include "mlir/Dialect/LoopOps/LoopOps.cpp.inc"
64 >();
Stephan Herhutb843cc52019-10-16 04:28:13 -070065 addInterfaces<LoopSideEffectsInterface>();
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070066}
67
68//===----------------------------------------------------------------------===//
69// ForOp
70//===----------------------------------------------------------------------===//
71
River Riddle729727e2019-09-20 19:47:05 -070072void ForOp::build(Builder *builder, OperationState &result, Value *lb,
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070073 Value *ub, Value *step) {
River Riddle729727e2019-09-20 19:47:05 -070074 result.addOperands({lb, ub, step});
75 Region *bodyRegion = result.addRegion();
76 ForOp::ensureTerminator(*bodyRegion, *builder, result.location);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070077 bodyRegion->front().addArgument(builder->getIndexType());
78}
79
80LogicalResult verify(ForOp op) {
81 if (auto cst = dyn_cast_or_null<ConstantIndexOp>(op.step()->getDefiningOp()))
82 if (cst.getValue() <= 0)
83 return op.emitOpError("constant step operand must be nonnegative");
84
85 // Check that the body defines as single block argument for the induction
86 // variable.
Nicolas Vasilache0002e292019-07-16 12:20:15 -070087 auto *body = op.getBody();
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070088 if (body->getNumArguments() != 1 ||
89 !body->getArgument(0)->getType().isIndex())
90 return op.emitOpError("expected body to have a single index argument for "
91 "the induction variable");
Nicolas Vasilachecca53e82019-07-15 02:50:09 -070092 return success();
93}
94
River Riddle3a643de2019-09-20 20:43:02 -070095static void print(OpAsmPrinter &p, ForOp op) {
96 p << op.getOperationName() << " " << *op.getInductionVar() << " = "
97 << *op.lowerBound() << " to " << *op.upperBound() << " step " << *op.step();
98 p.printRegion(op.region(),
99 /*printEntryBlockArgs=*/false,
100 /*printBlockTerminators=*/false);
101 p.printOptionalAttrDict(op.getAttrs());
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700102}
103
River Riddle729727e2019-09-20 19:47:05 -0700104static ParseResult parseForOp(OpAsmParser &parser, OperationState &result) {
River Riddle27975172019-09-20 11:36:49 -0700105 auto &builder = parser.getBuilder();
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700106 OpAsmParser::OperandType inductionVariable, lb, ub, step;
107 // Parse the induction variable followed by '='.
River Riddle27975172019-09-20 11:36:49 -0700108 if (parser.parseRegionArgument(inductionVariable) || parser.parseEqual())
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700109 return failure();
110
111 // Parse loop bounds.
112 Type indexType = builder.getIndexType();
River Riddle27975172019-09-20 11:36:49 -0700113 if (parser.parseOperand(lb) ||
River Riddle729727e2019-09-20 19:47:05 -0700114 parser.resolveOperand(lb, indexType, result.operands) ||
River Riddle27975172019-09-20 11:36:49 -0700115 parser.parseKeyword("to") || parser.parseOperand(ub) ||
River Riddle729727e2019-09-20 19:47:05 -0700116 parser.resolveOperand(ub, indexType, result.operands) ||
River Riddle27975172019-09-20 11:36:49 -0700117 parser.parseKeyword("step") || parser.parseOperand(step) ||
River Riddle729727e2019-09-20 19:47:05 -0700118 parser.resolveOperand(step, indexType, result.operands))
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700119 return failure();
120
121 // Parse the body region.
River Riddle729727e2019-09-20 19:47:05 -0700122 Region *body = result.addRegion();
River Riddle27975172019-09-20 11:36:49 -0700123 if (parser.parseRegion(*body, inductionVariable, indexType))
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700124 return failure();
125
River Riddle729727e2019-09-20 19:47:05 -0700126 ForOp::ensureTerminator(*body, builder, result.location);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700127
128 // Parse the optional attribute list.
River Riddle729727e2019-09-20 19:47:05 -0700129 if (parser.parseOptionalAttributeDict(result.attributes))
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700130 return failure();
131
132 return success();
133}
134
Stephan Herhutb843cc52019-10-16 04:28:13 -0700135Region &ForOp::getLoopBody() { return region(); }
136
137bool ForOp::isDefinedOutsideOfLoop(Value *value) {
138 return !region().isAncestor(value->getParentRegion());
139}
140
141LogicalResult ForOp::moveOutOfLoop(ArrayRef<Operation *> ops) {
142 for (auto *op : ops)
143 op->moveBefore(this->getOperation());
144 return success();
145}
146
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700147ForOp mlir::loop::getForInductionVarOwner(Value *val) {
148 auto *ivArg = dyn_cast<BlockArgument>(val);
149 if (!ivArg)
150 return ForOp();
151 assert(ivArg->getOwner() && "unlinked block argument");
River Riddle1e429542019-08-09 20:07:25 -0700152 auto *containingInst = ivArg->getOwner()->getParentOp();
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700153 return dyn_cast_or_null<ForOp>(containingInst);
154}
155
156//===----------------------------------------------------------------------===//
157// IfOp
158//===----------------------------------------------------------------------===//
159
River Riddle729727e2019-09-20 19:47:05 -0700160void IfOp::build(Builder *builder, OperationState &result, Value *cond,
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700161 bool withElseRegion) {
River Riddle729727e2019-09-20 19:47:05 -0700162 result.addOperands(cond);
163 Region *thenRegion = result.addRegion();
164 Region *elseRegion = result.addRegion();
165 IfOp::ensureTerminator(*thenRegion, *builder, result.location);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700166 if (withElseRegion)
River Riddle729727e2019-09-20 19:47:05 -0700167 IfOp::ensureTerminator(*elseRegion, *builder, result.location);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700168}
169
170static LogicalResult verify(IfOp op) {
171 // Verify that the entry of each child region does not have arguments.
172 for (auto &region : op.getOperation()->getRegions()) {
173 if (region.empty())
174 continue;
175
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700176 for (auto &b : region)
177 if (b.getNumArguments() != 0)
178 return op.emitOpError(
179 "requires that child entry blocks have no arguments");
180 }
181 return success();
182}
183
River Riddle729727e2019-09-20 19:47:05 -0700184static ParseResult parseIfOp(OpAsmParser &parser, OperationState &result) {
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700185 // Create the regions for 'then'.
River Riddle729727e2019-09-20 19:47:05 -0700186 result.regions.reserve(2);
187 Region *thenRegion = result.addRegion();
188 Region *elseRegion = result.addRegion();
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700189
River Riddle27975172019-09-20 11:36:49 -0700190 auto &builder = parser.getBuilder();
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700191 OpAsmParser::OperandType cond;
192 Type i1Type = builder.getIntegerType(1);
River Riddle27975172019-09-20 11:36:49 -0700193 if (parser.parseOperand(cond) ||
River Riddle729727e2019-09-20 19:47:05 -0700194 parser.resolveOperand(cond, i1Type, result.operands))
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700195 return failure();
196
197 // Parse the 'then' region.
River Riddle27975172019-09-20 11:36:49 -0700198 if (parser.parseRegion(*thenRegion, {}, {}))
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700199 return failure();
River Riddle729727e2019-09-20 19:47:05 -0700200 IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700201
202 // If we find an 'else' keyword then parse the 'else' region.
River Riddle27975172019-09-20 11:36:49 -0700203 if (!parser.parseOptionalKeyword("else")) {
204 if (parser.parseRegion(*elseRegion, {}, {}))
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700205 return failure();
River Riddle729727e2019-09-20 19:47:05 -0700206 IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700207 }
208
209 // Parse the optional attribute list.
River Riddle729727e2019-09-20 19:47:05 -0700210 if (parser.parseOptionalAttributeDict(result.attributes))
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700211 return failure();
212
213 return success();
214}
215
River Riddle3a643de2019-09-20 20:43:02 -0700216static void print(OpAsmPrinter &p, IfOp op) {
217 p << IfOp::getOperationName() << " " << *op.condition();
218 p.printRegion(op.thenRegion(),
219 /*printEntryBlockArgs=*/false,
220 /*printBlockTerminators=*/false);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700221
222 // Print the 'else' regions if it exists and has a block.
223 auto &elseRegion = op.elseRegion();
224 if (!elseRegion.empty()) {
River Riddle3a643de2019-09-20 20:43:02 -0700225 p << " else";
226 p.printRegion(elseRegion,
227 /*printEntryBlockArgs=*/false,
228 /*printBlockTerminators=*/false);
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700229 }
230
River Riddle3a643de2019-09-20 20:43:02 -0700231 p.printOptionalAttrDict(op.getAttrs());
Nicolas Vasilachecca53e82019-07-15 02:50:09 -0700232}
233
234//===----------------------------------------------------------------------===//
235// TableGen'd op method definitions
236//===----------------------------------------------------------------------===//
237
238#define GET_OP_CLASSES
239#include "mlir/Dialect/LoopOps/LoopOps.cpp.inc"