blob: c8d3336106f37399d7a33e6898444c0684773bd1 [file] [log] [blame]
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001//===- Statement.cpp - MLIR Statement Classes ----------------------------===//
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
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -070018#include "mlir/IR/AffineExpr.h"
Tatiana Shpeismande8829f2018-08-24 23:38:14 -070019#include "mlir/IR/AffineMap.h"
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -070020#include "mlir/IR/IntegerSet.h"
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070021#include "mlir/IR/MLFunction.h"
Chris Lattner1628fa02018-08-23 14:32:25 -070022#include "mlir/IR/MLIRContext.h"
Tatiana Shpeismande8829f2018-08-24 23:38:14 -070023#include "mlir/IR/StandardOps.h"
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070024#include "mlir/IR/Statements.h"
Uday Bondhugula0b4059b2018-07-24 20:01:16 -070025#include "mlir/IR/StmtVisitor.h"
Chris Lattnere787b322018-08-08 11:14:57 -070026#include "llvm/ADT/DenseMap.h"
Tatiana Shpeismande8829f2018-08-24 23:38:14 -070027
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070028using namespace mlir;
29
30//===----------------------------------------------------------------------===//
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -070031// StmtResult
32//===------------------------------------------------------------------===//
33
34/// Return the result number of this result.
35unsigned StmtResult::getResultNumber() const {
36 // Results are always stored consecutively, so use pointer subtraction to
37 // figure out what number this is.
38 return this - &getOwner()->getStmtResults()[0];
39}
40
41//===----------------------------------------------------------------------===//
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070042// Statement
43//===------------------------------------------------------------------===//
44
45// Statements are deleted through the destroy() member because we don't have
46// a virtual destructor.
47Statement::~Statement() {
48 assert(block == nullptr && "statement destroyed but still in a block");
49}
50
51/// Destroy this statement or one of its subclasses.
Tatiana Shpeisman6708b452018-07-24 10:15:13 -070052void Statement::destroy() {
53 switch (this->getKind()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070054 case Kind::Operation:
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -070055 cast<OperationStmt>(this)->destroy();
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070056 break;
57 case Kind::For:
Tatiana Shpeisman6708b452018-07-24 10:15:13 -070058 delete cast<ForStmt>(this);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070059 break;
60 case Kind::If:
Tatiana Shpeisman6708b452018-07-24 10:15:13 -070061 delete cast<IfStmt>(this);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070062 break;
63 }
64}
65
Chris Lattner1628fa02018-08-23 14:32:25 -070066/// Return the context this operation is associated with.
67MLIRContext *Statement::getContext() const {
68 // Work a bit to avoid calling findFunction() and getting its context.
69 switch (getKind()) {
70 case Kind::Operation:
71 return cast<OperationStmt>(this)->getContext();
72 case Kind::For:
Tatiana Shpeismande8829f2018-08-24 23:38:14 -070073 return cast<ForStmt>(this)->getContext();
Chris Lattner1628fa02018-08-23 14:32:25 -070074 case Kind::If:
75 // TODO(shpeisman): When if statement has value operands, we can get a
76 // context from their type.
77 return findFunction()->getContext();
78 }
79}
80
Tatiana Shpeismanc335d182018-08-03 11:12:34 -070081Statement *Statement::getParentStmt() const {
82 return block ? block->getParentStmt() : nullptr;
83}
Tatiana Shpeismand880b352018-07-31 23:14:16 -070084
85MLFunction *Statement::findFunction() const {
Tatiana Shpeismanc335d182018-08-03 11:12:34 -070086 return block ? block->findFunction() : nullptr;
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070087}
88
Uday Bondhugula081d9e72018-07-27 10:58:14 -070089bool Statement::isInnermost() const {
90 struct NestedLoopCounter : public StmtWalker<NestedLoopCounter> {
Uday Bondhugula0b4059b2018-07-24 20:01:16 -070091 unsigned numNestedLoops;
92 NestedLoopCounter() : numNestedLoops(0) {}
Uday Bondhugula081d9e72018-07-27 10:58:14 -070093 void walkForStmt(const ForStmt *fs) { numNestedLoops++; }
Uday Bondhugula0b4059b2018-07-24 20:01:16 -070094 };
95
96 NestedLoopCounter nlc;
Uday Bondhugula081d9e72018-07-27 10:58:14 -070097 nlc.walk(const_cast<Statement *>(this));
98 return nlc.numNestedLoops == 1;
Uday Bondhugula0b4059b2018-07-24 20:01:16 -070099}
100
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700101MLValue *Statement::getOperand(unsigned idx) {
102 return getStmtOperand(idx).get();
103}
104
105const MLValue *Statement::getOperand(unsigned idx) const {
106 return getStmtOperand(idx).get();
107}
108
109void Statement::setOperand(unsigned idx, MLValue *value) {
110 getStmtOperand(idx).set(value);
111}
112
113unsigned Statement::getNumOperands() const {
114 switch (getKind()) {
115 case Kind::Operation:
116 return cast<OperationStmt>(this)->getNumOperands();
117 case Kind::For:
118 return cast<ForStmt>(this)->getNumOperands();
119 case Kind::If:
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700120 return cast<IfStmt>(this)->getNumOperands();
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700121 }
122}
123
124MutableArrayRef<StmtOperand> Statement::getStmtOperands() {
125 switch (getKind()) {
126 case Kind::Operation:
127 return cast<OperationStmt>(this)->getStmtOperands();
128 case Kind::For:
129 return cast<ForStmt>(this)->getStmtOperands();
130 case Kind::If:
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700131 return cast<IfStmt>(this)->getStmtOperands();
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700132 }
133}
134
Chris Lattner1628fa02018-08-23 14:32:25 -0700135/// Emit a note about this statement, reporting up to any diagnostic
136/// handlers that may be listening.
137void Statement::emitNote(const Twine &message) const {
138 getContext()->emitDiagnostic(getLoc(), message,
139 MLIRContext::DiagnosticKind::Note);
140}
141
142/// Emit a warning about this statement, reporting up to any diagnostic
143/// handlers that may be listening.
144void Statement::emitWarning(const Twine &message) const {
145 getContext()->emitDiagnostic(getLoc(), message,
146 MLIRContext::DiagnosticKind::Warning);
147}
148
149/// Emit an error about fatal conditions with this statement, reporting up to
150/// any diagnostic handlers that may be listening. NOTE: This may terminate
151/// the containing application, only use when the IR is in an inconsistent
152/// state.
153void Statement::emitError(const Twine &message) const {
154 getContext()->emitDiagnostic(getLoc(), message,
155 MLIRContext::DiagnosticKind::Error);
156}
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700157//===----------------------------------------------------------------------===//
158// ilist_traits for Statement
159//===----------------------------------------------------------------------===//
160
161StmtBlock *llvm::ilist_traits<::mlir::Statement>::getContainingBlock() {
162 size_t Offset(
163 size_t(&((StmtBlock *)nullptr->*StmtBlock::getSublistAccess(nullptr))));
164 iplist<Statement> *Anchor(static_cast<iplist<Statement> *>(this));
165 return reinterpret_cast<StmtBlock *>(reinterpret_cast<char *>(Anchor) -
166 Offset);
167}
168
169/// This is a trait method invoked when a statement is added to a block. We
170/// keep the block pointer up to date.
171void llvm::ilist_traits<::mlir::Statement>::addNodeToList(Statement *stmt) {
172 assert(!stmt->getBlock() && "already in a statement block!");
173 stmt->block = getContainingBlock();
174}
175
176/// This is a trait method invoked when a statement is removed from a block.
177/// We keep the block pointer up to date.
178void llvm::ilist_traits<::mlir::Statement>::removeNodeFromList(
179 Statement *stmt) {
180 assert(stmt->block && "not already in a statement block!");
181 stmt->block = nullptr;
182}
183
184/// This is a trait method invoked when a statement is moved from one block
185/// to another. We keep the block pointer up to date.
186void llvm::ilist_traits<::mlir::Statement>::transferNodesFromList(
187 ilist_traits<Statement> &otherList, stmt_iterator first,
188 stmt_iterator last) {
189 // If we are transferring statements within the same block, the block
190 // pointer doesn't need to be updated.
191 StmtBlock *curParent = getContainingBlock();
192 if (curParent == otherList.getContainingBlock())
193 return;
194
195 // Update the 'block' member of each statement.
196 for (; first != last; ++first)
197 first->block = curParent;
198}
199
Uday Bondhugula0b4059b2018-07-24 20:01:16 -0700200/// Remove this statement (and its descendants) from its StmtBlock and delete
201/// all of them.
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700202void Statement::eraseFromBlock() {
203 assert(getBlock() && "Statement has no block");
204 getBlock()->getStatements().erase(this);
205}
206
207//===----------------------------------------------------------------------===//
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700208// OperationStmt
209//===----------------------------------------------------------------------===//
210
211/// Create a new OperationStmt with the specific fields.
Chris Lattnerfc647d52018-08-27 21:05:16 -0700212OperationStmt *OperationStmt::create(Location *location, Identifier name,
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700213 ArrayRef<MLValue *> operands,
214 ArrayRef<Type *> resultTypes,
215 ArrayRef<NamedAttribute> attributes,
216 MLIRContext *context) {
217 auto byteSize = totalSizeToAlloc<StmtOperand, StmtResult>(operands.size(),
218 resultTypes.size());
219 void *rawMem = malloc(byteSize);
220
221 // Initialize the OperationStmt part of the statement.
222 auto stmt = ::new (rawMem) OperationStmt(
Chris Lattner1628fa02018-08-23 14:32:25 -0700223 location, name, operands.size(), resultTypes.size(), attributes, context);
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700224
225 // Initialize the operands and results.
226 auto stmtOperands = stmt->getStmtOperands();
227 for (unsigned i = 0, e = operands.size(); i != e; ++i)
228 new (&stmtOperands[i]) StmtOperand(stmt, operands[i]);
229
230 auto stmtResults = stmt->getStmtResults();
231 for (unsigned i = 0, e = resultTypes.size(); i != e; ++i)
232 new (&stmtResults[i]) StmtResult(resultTypes[i], stmt);
233 return stmt;
234}
235
Chris Lattnerfc647d52018-08-27 21:05:16 -0700236OperationStmt::OperationStmt(Location *location, Identifier name,
Chris Lattner1628fa02018-08-23 14:32:25 -0700237 unsigned numOperands, unsigned numResults,
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700238 ArrayRef<NamedAttribute> attributes,
239 MLIRContext *context)
Chris Lattner1628fa02018-08-23 14:32:25 -0700240 : Operation(/*isInstruction=*/false, name, attributes, context),
241 Statement(Kind::Operation, location), numOperands(numOperands),
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700242 numResults(numResults) {}
243
244OperationStmt::~OperationStmt() {
245 // Explicitly run the destructors for the operands and results.
246 for (auto &operand : getStmtOperands())
247 operand.~StmtOperand();
248
249 for (auto &result : getStmtResults())
250 result.~StmtResult();
251}
252
253void OperationStmt::destroy() {
254 this->~OperationStmt();
255 free(this);
256}
257
Chris Lattner95865062018-08-01 10:18:59 -0700258/// Return the context this operation is associated with.
259MLIRContext *OperationStmt::getContext() const {
260 // If we have a result or operand type, that is a constant time way to get
261 // to the context.
262 if (getNumResults())
263 return getResult(0)->getType()->getContext();
264 if (getNumOperands())
265 return getOperand(0)->getType()->getContext();
266
267 // In the very odd case where we have no operands or results, fall back to
268 // doing a find.
269 return findFunction()->getContext();
270}
271
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700272bool OperationStmt::isReturn() const { return is<ReturnOp>(); }
273
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700274//===----------------------------------------------------------------------===//
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700275// ForStmt
276//===----------------------------------------------------------------------===//
277
Chris Lattnerfc647d52018-08-27 21:05:16 -0700278ForStmt *ForStmt::create(Location *location, ArrayRef<MLValue *> lbOperands,
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700279 AffineMap *lbMap, ArrayRef<MLValue *> ubOperands,
280 AffineMap *ubMap, int64_t step, MLIRContext *context) {
281 assert(lbOperands.size() == lbMap->getNumOperands() &&
282 "lower bound operand count does not match the affine map");
283 assert(ubOperands.size() == ubMap->getNumOperands() &&
284 "upper bound operand count does not match the affine map");
285
286 unsigned numOperands = lbOperands.size() + ubOperands.size();
287 ForStmt *stmt =
288 new ForStmt(location, numOperands, lbMap, ubMap, step, context);
289
290 unsigned i = 0;
291 for (unsigned e = lbOperands.size(); i != e; ++i)
292 stmt->operands.emplace_back(StmtOperand(stmt, lbOperands[i]));
293
294 for (unsigned j = 0, e = ubOperands.size(); j != e; ++i, ++j)
295 stmt->operands.emplace_back(StmtOperand(stmt, ubOperands[j]));
296
297 return stmt;
298}
299
Chris Lattnerfc647d52018-08-27 21:05:16 -0700300ForStmt::ForStmt(Location *location, unsigned numOperands, AffineMap *lbMap,
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700301 AffineMap *ubMap, int64_t step, MLIRContext *context)
Chris Lattner1628fa02018-08-23 14:32:25 -0700302 : Statement(Kind::For, location),
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700303 MLValue(MLValueKind::ForStmt, Type::getAffineInt(context)),
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700304 StmtBlock(StmtBlockKind::For), lbMap(lbMap), ubMap(ubMap), step(step) {
305 operands.reserve(numOperands);
306}
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700307
308const AffineBound ForStmt::getLowerBound() const {
309 return AffineBound(*this, 0, lbMap->getNumOperands(), lbMap);
310}
311
312const AffineBound ForStmt::getUpperBound() const {
313 return AffineBound(*this, lbMap->getNumOperands(), getNumOperands(), ubMap);
314}
315
316void ForStmt::setLowerBound(ArrayRef<MLValue *> operands, AffineMap *map) {
317 // TODO: handle the case when number of existing or new operands is non-zero.
318 assert(getNumOperands() == 0 && operands.empty());
319
320 this->lbMap = map;
321}
322
323void ForStmt::setUpperBound(ArrayRef<MLValue *> operands, AffineMap *map) {
324 // TODO: handle the case when number of existing or new operands is non-zero.
325 assert(getNumOperands() == 0 && operands.empty());
326
327 this->ubMap = map;
328}
329
330bool ForStmt::hasConstantLowerBound() const {
331 return lbMap->isSingleConstant();
332}
333
334bool ForStmt::hasConstantUpperBound() const {
335 return ubMap->isSingleConstant();
336}
337
338int64_t ForStmt::getConstantLowerBound() const {
Uday Bondhugulad3004002018-09-11 16:29:24 -0700339 return lbMap->getSingleConstantResult();
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700340}
341
342int64_t ForStmt::getConstantUpperBound() const {
Uday Bondhugulad3004002018-09-11 16:29:24 -0700343 return ubMap->getSingleConstantResult();
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700344}
345
Uday Bondhugula832b17a2018-09-07 14:47:21 -0700346Optional<uint64_t> ForStmt::getConstantTripCount() const {
347 // TODO(bondhugula): handle arbitrary lower/upper bounds.
348 if (!hasConstantBounds())
349 return None;
350 int64_t lb = getConstantLowerBound();
351 int64_t ub = getConstantUpperBound();
352 int64_t step = getStep();
353
354 // 0 iteration loops.
355 if ((step >= 1 && lb > ub) || (step <= -1 && lb < ub))
356 return 0;
357
358 uint64_t tripCount = static_cast<uint64_t>((ub - lb + 1) % step == 0
359 ? (ub - lb + 1) / step
360 : (ub - lb + 1) / step + 1);
361 return tripCount;
362}
363
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700364void ForStmt::setConstantLowerBound(int64_t value) {
365 MLIRContext *context = getContext();
366 auto *expr = AffineConstantExpr::get(value, context);
367 setLowerBound({}, AffineMap::get(0, 0, expr, {}, context));
368}
369
370void ForStmt::setConstantUpperBound(int64_t value) {
371 MLIRContext *context = getContext();
372 auto *expr = AffineConstantExpr::get(value, context);
373 setUpperBound({}, AffineMap::get(0, 0, expr, {}, context));
374}
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700375
376//===----------------------------------------------------------------------===//
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700377// IfStmt
378//===----------------------------------------------------------------------===//
379
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700380IfStmt::IfStmt(Location *location, unsigned numOperands, IntegerSet *set)
Chris Lattner1628fa02018-08-23 14:32:25 -0700381 : Statement(Kind::If, location), thenClause(new IfClause(this)),
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700382 elseClause(nullptr), set(set) {
383 operands.reserve(numOperands);
384}
Chris Lattner1628fa02018-08-23 14:32:25 -0700385
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700386IfStmt::~IfStmt() {
Tatiana Shpeismane935fa22018-09-02 08:48:54 -0700387 delete thenClause;
388
Uday Bondhugula15984952018-08-01 22:36:12 -0700389 if (elseClause)
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700390 delete elseClause;
Tatiana Shpeisman0a917a92018-08-31 22:33:47 -0700391
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700392 // An IfStmt's IntegerSet 'set' should not be deleted since it is
Uday Bondhugulabc535622018-08-07 14:24:38 -0700393 // allocated through MLIRContext's bump pointer allocator.
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700394}
Uday Bondhugula84b80952018-08-03 13:22:26 -0700395
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700396IfStmt *IfStmt::create(Location *location, ArrayRef<MLValue *> operands,
397 IntegerSet *set) {
398 unsigned numOperands = operands.size();
399 assert(numOperands == set->getNumOperands() &&
400 "operand cound does not match the integer set operand count");
401
402 IfStmt *stmt = new IfStmt(location, numOperands, set);
403
404 for (auto *op : operands)
405 stmt->operands.emplace_back(StmtOperand(stmt, op));
406
407 return stmt;
408}
409
410const AffineCondition IfStmt::getCondition() const {
411 return AffineCondition(*this, set);
412}
413
414MLIRContext *IfStmt::getContext() const {
415 // Check for degenerate case of if statement with no operands.
416 // This is unlikely, but legal.
417 if (operands.empty())
418 return findFunction()->getContext();
419
420 return getOperand(0)->getType()->getContext();
421}
422
Chris Lattnere787b322018-08-08 11:14:57 -0700423//===----------------------------------------------------------------------===//
424// Statement Cloning
425//===----------------------------------------------------------------------===//
426
427/// Create a deep copy of this statement, remapping any operands that use
428/// values outside of the statement using the map that is provided (leaving
429/// them alone if no entry is present). Replaces references to cloned
430/// sub-statements to the corresponding statement that is copied, and adds
431/// those mappings to the map.
432Statement *Statement::clone(DenseMap<const MLValue *, MLValue *> &operandMap,
433 MLIRContext *context) const {
434 // If the specified value is in operandMap, return the remapped value.
435 // Otherwise return the value itself.
436 auto remapOperand = [&](const MLValue *value) -> MLValue * {
437 auto it = operandMap.find(value);
438 return it != operandMap.end() ? it->second : const_cast<MLValue *>(value);
439 };
440
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700441 SmallVector<MLValue *, 8> operands;
442 operands.reserve(getNumOperands());
443 for (auto *opValue : getOperands())
444 operands.push_back(remapOperand(opValue));
Chris Lattnere787b322018-08-08 11:14:57 -0700445
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700446 if (auto *opStmt = dyn_cast<OperationStmt>(this)) {
Chris Lattnere787b322018-08-08 11:14:57 -0700447 SmallVector<Type *, 8> resultTypes;
448 resultTypes.reserve(opStmt->getNumResults());
449 for (auto *result : opStmt->getResults())
450 resultTypes.push_back(result->getType());
Chris Lattner1628fa02018-08-23 14:32:25 -0700451 auto *newOp =
452 OperationStmt::create(getLoc(), opStmt->getName(), operands,
453 resultTypes, opStmt->getAttrs(), context);
Chris Lattnere787b322018-08-08 11:14:57 -0700454 // Remember the mapping of any results.
455 for (unsigned i = 0, e = opStmt->getNumResults(); i != e; ++i)
456 operandMap[opStmt->getResult(i)] = newOp->getResult(i);
457 return newOp;
458 }
459
460 if (auto *forStmt = dyn_cast<ForStmt>(this)) {
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700461 auto *lbMap = forStmt->getLowerBoundMap();
462 auto *ubMap = forStmt->getUpperBoundMap();
463
464 auto *newFor = ForStmt::create(
465 getLoc(),
466 ArrayRef<MLValue *>(operands).take_front(lbMap->getNumOperands()),
467 lbMap, ArrayRef<MLValue *>(operands).take_back(ubMap->getNumOperands()),
468 ubMap, forStmt->getStep(), context);
469
Chris Lattnere787b322018-08-08 11:14:57 -0700470 // Remember the induction variable mapping.
471 operandMap[forStmt] = newFor;
472
Chris Lattnere787b322018-08-08 11:14:57 -0700473 // Recursively clone the body of the for loop.
474 for (auto &subStmt : *forStmt)
475 newFor->push_back(subStmt.clone(operandMap, context));
476
477 return newFor;
478 }
479
480 // Otherwise, we must have an If statement.
481 auto *ifStmt = cast<IfStmt>(this);
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700482 auto *newIf = IfStmt::create(getLoc(), operands, ifStmt->getIntegerSet());
Chris Lattnere787b322018-08-08 11:14:57 -0700483
484 auto *resultThen = newIf->getThen();
485 for (auto &childStmt : *ifStmt->getThen())
486 resultThen->push_back(childStmt.clone(operandMap, context));
487
488 if (ifStmt->hasElse()) {
489 auto *resultElse = newIf->createElse();
490 for (auto &childStmt : *ifStmt->getElse())
491 resultElse->push_back(childStmt.clone(operandMap, context));
492 }
493
494 return newIf;
Uday Bondhugula84b80952018-08-03 13:22:26 -0700495}