1 //===- AffineToStandard.cpp - Lower affine constructs to primitives -------===// 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 // This file lowers affine constructs (If and For statements, AffineApply 10 // operations) within a function into their standard If and For equivalent ops. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "mlir/Conversion/AffineToStandard/AffineToStandard.h" 15 16 #include "mlir/Dialect/Affine/IR/AffineOps.h" 17 #include "mlir/Dialect/LoopOps/LoopOps.h" 18 #include "mlir/Dialect/StandardOps/IR/Ops.h" 19 #include "mlir/IR/AffineExprVisitor.h" 20 #include "mlir/IR/BlockAndValueMapping.h" 21 #include "mlir/IR/Builders.h" 22 #include "mlir/IR/IntegerSet.h" 23 #include "mlir/IR/MLIRContext.h" 24 #include "mlir/Pass/Pass.h" 25 #include "mlir/Support/Functional.h" 26 #include "mlir/Transforms/DialectConversion.h" 27 #include "mlir/Transforms/Passes.h" 28 29 using namespace mlir; 30 31 namespace { 32 /// Visit affine expressions recursively and build the sequence of operations 33 /// that correspond to it. Visitation functions return an Value of the 34 /// expression subtree they visited or `nullptr` on error. 35 class AffineApplyExpander 36 : public AffineExprVisitor<AffineApplyExpander, Value> { 37 public: 38 /// This internal class expects arguments to be non-null, checks must be 39 /// performed at the call site. 40 AffineApplyExpander(OpBuilder &builder, ValueRange dimValues, 41 ValueRange symbolValues, Location loc) 42 : builder(builder), dimValues(dimValues), symbolValues(symbolValues), 43 loc(loc) {} 44 45 template <typename OpTy> Value buildBinaryExpr(AffineBinaryOpExpr expr) { 46 auto lhs = visit(expr.getLHS()); 47 auto rhs = visit(expr.getRHS()); 48 if (!lhs || !rhs) 49 return nullptr; 50 auto op = builder.create<OpTy>(loc, lhs, rhs); 51 return op.getResult(); 52 } 53 54 Value visitAddExpr(AffineBinaryOpExpr expr) { 55 return buildBinaryExpr<AddIOp>(expr); 56 } 57 58 Value visitMulExpr(AffineBinaryOpExpr expr) { 59 return buildBinaryExpr<MulIOp>(expr); 60 } 61 62 /// Euclidean modulo operation: negative RHS is not allowed. 63 /// Remainder of the euclidean integer division is always non-negative. 64 /// 65 /// Implemented as 66 /// 67 /// a mod b = 68 /// let remainder = srem a, b; 69 /// negative = a < 0 in 70 /// select negative, remainder + b, remainder. 71 Value visitModExpr(AffineBinaryOpExpr expr) { 72 auto rhsConst = expr.getRHS().dyn_cast<AffineConstantExpr>(); 73 if (!rhsConst) { 74 emitError( 75 loc, 76 "semi-affine expressions (modulo by non-const) are not supported"); 77 return nullptr; 78 } 79 if (rhsConst.getValue() <= 0) { 80 emitError(loc, "modulo by non-positive value is not supported"); 81 return nullptr; 82 } 83 84 auto lhs = visit(expr.getLHS()); 85 auto rhs = visit(expr.getRHS()); 86 assert(lhs && rhs && "unexpected affine expr lowering failure"); 87 88 Value remainder = builder.create<SignedRemIOp>(loc, lhs, rhs); 89 Value zeroCst = builder.create<ConstantIndexOp>(loc, 0); 90 Value isRemainderNegative = 91 builder.create<CmpIOp>(loc, CmpIPredicate::slt, remainder, zeroCst); 92 Value correctedRemainder = builder.create<AddIOp>(loc, remainder, rhs); 93 Value result = builder.create<SelectOp>(loc, isRemainderNegative, 94 correctedRemainder, remainder); 95 return result; 96 } 97 98 /// Floor division operation (rounds towards negative infinity). 99 /// 100 /// For positive divisors, it can be implemented without branching and with a 101 /// single division operation as 102 /// 103 /// a floordiv b = 104 /// let negative = a < 0 in 105 /// let absolute = negative ? -a - 1 : a in 106 /// let quotient = absolute / b in 107 /// negative ? -quotient - 1 : quotient 108 Value visitFloorDivExpr(AffineBinaryOpExpr expr) { 109 auto rhsConst = expr.getRHS().dyn_cast<AffineConstantExpr>(); 110 if (!rhsConst) { 111 emitError( 112 loc, 113 "semi-affine expressions (division by non-const) are not supported"); 114 return nullptr; 115 } 116 if (rhsConst.getValue() <= 0) { 117 emitError(loc, "division by non-positive value is not supported"); 118 return nullptr; 119 } 120 121 auto lhs = visit(expr.getLHS()); 122 auto rhs = visit(expr.getRHS()); 123 assert(lhs && rhs && "unexpected affine expr lowering failure"); 124 125 Value zeroCst = builder.create<ConstantIndexOp>(loc, 0); 126 Value noneCst = builder.create<ConstantIndexOp>(loc, -1); 127 Value negative = 128 builder.create<CmpIOp>(loc, CmpIPredicate::slt, lhs, zeroCst); 129 Value negatedDecremented = builder.create<SubIOp>(loc, noneCst, lhs); 130 Value dividend = 131 builder.create<SelectOp>(loc, negative, negatedDecremented, lhs); 132 Value quotient = builder.create<SignedDivIOp>(loc, dividend, rhs); 133 Value correctedQuotient = builder.create<SubIOp>(loc, noneCst, quotient); 134 Value result = 135 builder.create<SelectOp>(loc, negative, correctedQuotient, quotient); 136 return result; 137 } 138 139 /// Ceiling division operation (rounds towards positive infinity). 140 /// 141 /// For positive divisors, it can be implemented without branching and with a 142 /// single division operation as 143 /// 144 /// a ceildiv b = 145 /// let negative = a <= 0 in 146 /// let absolute = negative ? -a : a - 1 in 147 /// let quotient = absolute / b in 148 /// negative ? -quotient : quotient + 1 149 Value visitCeilDivExpr(AffineBinaryOpExpr expr) { 150 auto rhsConst = expr.getRHS().dyn_cast<AffineConstantExpr>(); 151 if (!rhsConst) { 152 emitError(loc) << "semi-affine expressions (division by non-const) are " 153 "not supported"; 154 return nullptr; 155 } 156 if (rhsConst.getValue() <= 0) { 157 emitError(loc, "division by non-positive value is not supported"); 158 return nullptr; 159 } 160 auto lhs = visit(expr.getLHS()); 161 auto rhs = visit(expr.getRHS()); 162 assert(lhs && rhs && "unexpected affine expr lowering failure"); 163 164 Value zeroCst = builder.create<ConstantIndexOp>(loc, 0); 165 Value oneCst = builder.create<ConstantIndexOp>(loc, 1); 166 Value nonPositive = 167 builder.create<CmpIOp>(loc, CmpIPredicate::sle, lhs, zeroCst); 168 Value negated = builder.create<SubIOp>(loc, zeroCst, lhs); 169 Value decremented = builder.create<SubIOp>(loc, lhs, oneCst); 170 Value dividend = 171 builder.create<SelectOp>(loc, nonPositive, negated, decremented); 172 Value quotient = builder.create<SignedDivIOp>(loc, dividend, rhs); 173 Value negatedQuotient = builder.create<SubIOp>(loc, zeroCst, quotient); 174 Value incrementedQuotient = builder.create<AddIOp>(loc, quotient, oneCst); 175 Value result = builder.create<SelectOp>(loc, nonPositive, negatedQuotient, 176 incrementedQuotient); 177 return result; 178 } 179 180 Value visitConstantExpr(AffineConstantExpr expr) { 181 auto valueAttr = 182 builder.getIntegerAttr(builder.getIndexType(), expr.getValue()); 183 auto op = 184 builder.create<ConstantOp>(loc, builder.getIndexType(), valueAttr); 185 return op.getResult(); 186 } 187 188 Value visitDimExpr(AffineDimExpr expr) { 189 assert(expr.getPosition() < dimValues.size() && 190 "affine dim position out of range"); 191 return dimValues[expr.getPosition()]; 192 } 193 194 Value visitSymbolExpr(AffineSymbolExpr expr) { 195 assert(expr.getPosition() < symbolValues.size() && 196 "symbol dim position out of range"); 197 return symbolValues[expr.getPosition()]; 198 } 199 200 private: 201 OpBuilder &builder; 202 ValueRange dimValues; 203 ValueRange symbolValues; 204 205 Location loc; 206 }; 207 } // namespace 208 209 /// Create a sequence of operations that implement the `expr` applied to the 210 /// given dimension and symbol values. 211 mlir::Value mlir::expandAffineExpr(OpBuilder &builder, Location loc, 212 AffineExpr expr, ValueRange dimValues, 213 ValueRange symbolValues) { 214 return AffineApplyExpander(builder, dimValues, symbolValues, loc).visit(expr); 215 } 216 217 /// Create a sequence of operations that implement the `affineMap` applied to 218 /// the given `operands` (as it it were an AffineApplyOp). 219 Optional<SmallVector<Value, 8>> mlir::expandAffineMap(OpBuilder &builder, 220 Location loc, 221 AffineMap affineMap, 222 ValueRange operands) { 223 auto numDims = affineMap.getNumDims(); 224 auto expanded = functional::map( 225 [numDims, &builder, loc, operands](AffineExpr expr) { 226 return expandAffineExpr(builder, loc, expr, 227 operands.take_front(numDims), 228 operands.drop_front(numDims)); 229 }, 230 affineMap.getResults()); 231 if (llvm::all_of(expanded, [](Value v) { return v; })) 232 return expanded; 233 return None; 234 } 235 236 /// Given a range of values, emit the code that reduces them with "min" or "max" 237 /// depending on the provided comparison predicate. The predicate defines which 238 /// comparison to perform, "lt" for "min", "gt" for "max" and is used for the 239 /// `cmpi` operation followed by the `select` operation: 240 /// 241 /// %cond = cmpi "predicate" %v0, %v1 242 /// %result = select %cond, %v0, %v1 243 /// 244 /// Multiple values are scanned in a linear sequence. This creates a data 245 /// dependences that wouldn't exist in a tree reduction, but is easier to 246 /// recognize as a reduction by the subsequent passes. 247 static Value buildMinMaxReductionSeq(Location loc, CmpIPredicate predicate, 248 ValueRange values, OpBuilder &builder) { 249 assert(!llvm::empty(values) && "empty min/max chain"); 250 251 auto valueIt = values.begin(); 252 Value value = *valueIt++; 253 for (; valueIt != values.end(); ++valueIt) { 254 auto cmpOp = builder.create<CmpIOp>(loc, predicate, value, *valueIt); 255 value = builder.create<SelectOp>(loc, cmpOp.getResult(), value, *valueIt); 256 } 257 258 return value; 259 } 260 261 /// Emit instructions that correspond to computing the maximum value among the 262 /// values of a (potentially) multi-output affine map applied to `operands`. 263 static Value lowerAffineMapMax(OpBuilder &builder, Location loc, AffineMap map, 264 ValueRange operands) { 265 if (auto values = expandAffineMap(builder, loc, map, operands)) 266 return buildMinMaxReductionSeq(loc, CmpIPredicate::sgt, *values, builder); 267 return nullptr; 268 } 269 270 /// Emit instructions that correspond to computing the minimum value among the 271 /// values of a (potentially) multi-output affine map applied to `operands`. 272 static Value lowerAffineMapMin(OpBuilder &builder, Location loc, AffineMap map, 273 ValueRange operands) { 274 if (auto values = expandAffineMap(builder, loc, map, operands)) 275 return buildMinMaxReductionSeq(loc, CmpIPredicate::slt, *values, builder); 276 return nullptr; 277 } 278 279 /// Emit instructions that correspond to the affine map in the upper bound 280 /// applied to the respective operands, and compute the minimum value across 281 /// the results. 282 Value mlir::lowerAffineUpperBound(AffineForOp op, OpBuilder &builder) { 283 return lowerAffineMapMin(builder, op.getLoc(), op.getUpperBoundMap(), 284 op.getUpperBoundOperands()); 285 } 286 287 /// Emit instructions that correspond to the affine map in the lower bound 288 /// applied to the respective operands, and compute the maximum value across 289 /// the results. 290 Value mlir::lowerAffineLowerBound(AffineForOp op, OpBuilder &builder) { 291 return lowerAffineMapMax(builder, op.getLoc(), op.getLowerBoundMap(), 292 op.getLowerBoundOperands()); 293 } 294 295 namespace { 296 class AffineMinLowering : public OpRewritePattern<AffineMinOp> { 297 public: 298 using OpRewritePattern<AffineMinOp>::OpRewritePattern; 299 300 LogicalResult matchAndRewrite(AffineMinOp op, 301 PatternRewriter &rewriter) const override { 302 Value reduced = 303 lowerAffineMapMin(rewriter, op.getLoc(), op.map(), op.operands()); 304 if (!reduced) 305 return failure(); 306 307 rewriter.replaceOp(op, reduced); 308 return success(); 309 } 310 }; 311 312 class AffineMaxLowering : public OpRewritePattern<AffineMaxOp> { 313 public: 314 using OpRewritePattern<AffineMaxOp>::OpRewritePattern; 315 316 LogicalResult matchAndRewrite(AffineMaxOp op, 317 PatternRewriter &rewriter) const override { 318 Value reduced = 319 lowerAffineMapMax(rewriter, op.getLoc(), op.map(), op.operands()); 320 if (!reduced) 321 return failure(); 322 323 rewriter.replaceOp(op, reduced); 324 return success(); 325 } 326 }; 327 328 /// Affine terminators are removed. 329 class AffineTerminatorLowering : public OpRewritePattern<AffineTerminatorOp> { 330 public: 331 using OpRewritePattern<AffineTerminatorOp>::OpRewritePattern; 332 333 LogicalResult matchAndRewrite(AffineTerminatorOp op, 334 PatternRewriter &rewriter) const override { 335 rewriter.replaceOpWithNewOp<loop::YieldOp>(op); 336 return success(); 337 } 338 }; 339 340 class AffineForLowering : public OpRewritePattern<AffineForOp> { 341 public: 342 using OpRewritePattern<AffineForOp>::OpRewritePattern; 343 344 LogicalResult matchAndRewrite(AffineForOp op, 345 PatternRewriter &rewriter) const override { 346 Location loc = op.getLoc(); 347 Value lowerBound = lowerAffineLowerBound(op, rewriter); 348 Value upperBound = lowerAffineUpperBound(op, rewriter); 349 Value step = rewriter.create<ConstantIndexOp>(loc, op.getStep()); 350 auto f = rewriter.create<loop::ForOp>(loc, lowerBound, upperBound, step); 351 f.region().getBlocks().clear(); 352 rewriter.inlineRegionBefore(op.region(), f.region(), f.region().end()); 353 rewriter.eraseOp(op); 354 return success(); 355 } 356 }; 357 358 class AffineIfLowering : public OpRewritePattern<AffineIfOp> { 359 public: 360 using OpRewritePattern<AffineIfOp>::OpRewritePattern; 361 362 LogicalResult matchAndRewrite(AffineIfOp op, 363 PatternRewriter &rewriter) const override { 364 auto loc = op.getLoc(); 365 366 // Now we just have to handle the condition logic. 367 auto integerSet = op.getIntegerSet(); 368 Value zeroConstant = rewriter.create<ConstantIndexOp>(loc, 0); 369 SmallVector<Value, 8> operands(op.getOperands()); 370 auto operandsRef = llvm::makeArrayRef(operands); 371 372 // Calculate cond as a conjunction without short-circuiting. 373 Value cond = nullptr; 374 for (unsigned i = 0, e = integerSet.getNumConstraints(); i < e; ++i) { 375 AffineExpr constraintExpr = integerSet.getConstraint(i); 376 bool isEquality = integerSet.isEq(i); 377 378 // Build and apply an affine expression 379 auto numDims = integerSet.getNumDims(); 380 Value affResult = expandAffineExpr(rewriter, loc, constraintExpr, 381 operandsRef.take_front(numDims), 382 operandsRef.drop_front(numDims)); 383 if (!affResult) 384 return failure(); 385 auto pred = isEquality ? CmpIPredicate::eq : CmpIPredicate::sge; 386 Value cmpVal = 387 rewriter.create<CmpIOp>(loc, pred, affResult, zeroConstant); 388 cond = 389 cond ? rewriter.create<AndOp>(loc, cond, cmpVal).getResult() : cmpVal; 390 } 391 cond = cond ? cond 392 : rewriter.create<ConstantIntOp>(loc, /*value=*/1, /*width=*/1); 393 394 bool hasElseRegion = !op.elseRegion().empty(); 395 auto ifOp = rewriter.create<loop::IfOp>(loc, cond, hasElseRegion); 396 rewriter.inlineRegionBefore(op.thenRegion(), &ifOp.thenRegion().back()); 397 ifOp.thenRegion().back().erase(); 398 if (hasElseRegion) { 399 rewriter.inlineRegionBefore(op.elseRegion(), &ifOp.elseRegion().back()); 400 ifOp.elseRegion().back().erase(); 401 } 402 403 // Ok, we're done! 404 rewriter.eraseOp(op); 405 return success(); 406 } 407 }; 408 409 /// Convert an "affine.apply" operation into a sequence of arithmetic 410 /// operations using the StandardOps dialect. 411 class AffineApplyLowering : public OpRewritePattern<AffineApplyOp> { 412 public: 413 using OpRewritePattern<AffineApplyOp>::OpRewritePattern; 414 415 LogicalResult matchAndRewrite(AffineApplyOp op, 416 PatternRewriter &rewriter) const override { 417 auto maybeExpandedMap = 418 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), 419 llvm::to_vector<8>(op.getOperands())); 420 if (!maybeExpandedMap) 421 return failure(); 422 rewriter.replaceOp(op, *maybeExpandedMap); 423 return success(); 424 } 425 }; 426 427 /// Apply the affine map from an 'affine.load' operation to its operands, and 428 /// feed the results to a newly created 'std.load' operation (which replaces the 429 /// original 'affine.load'). 430 class AffineLoadLowering : public OpRewritePattern<AffineLoadOp> { 431 public: 432 using OpRewritePattern<AffineLoadOp>::OpRewritePattern; 433 434 LogicalResult matchAndRewrite(AffineLoadOp op, 435 PatternRewriter &rewriter) const override { 436 // Expand affine map from 'affineLoadOp'. 437 SmallVector<Value, 8> indices(op.getMapOperands()); 438 auto resultOperands = 439 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 440 if (!resultOperands) 441 return failure(); 442 443 // Build std.load memref[expandedMap.results]. 444 rewriter.replaceOpWithNewOp<LoadOp>(op, op.getMemRef(), *resultOperands); 445 return success(); 446 } 447 }; 448 449 /// Apply the affine map from an 'affine.prefetch' operation to its operands, 450 /// and feed the results to a newly created 'std.prefetch' operation (which 451 /// replaces the original 'affine.prefetch'). 452 class AffinePrefetchLowering : public OpRewritePattern<AffinePrefetchOp> { 453 public: 454 using OpRewritePattern<AffinePrefetchOp>::OpRewritePattern; 455 456 LogicalResult matchAndRewrite(AffinePrefetchOp op, 457 PatternRewriter &rewriter) const override { 458 // Expand affine map from 'affinePrefetchOp'. 459 SmallVector<Value, 8> indices(op.getMapOperands()); 460 auto resultOperands = 461 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 462 if (!resultOperands) 463 return failure(); 464 465 // Build std.prefetch memref[expandedMap.results]. 466 rewriter.replaceOpWithNewOp<PrefetchOp>( 467 op, op.memref(), *resultOperands, op.isWrite(), 468 op.localityHint().getZExtValue(), op.isDataCache()); 469 return success(); 470 } 471 }; 472 473 /// Apply the affine map from an 'affine.store' operation to its operands, and 474 /// feed the results to a newly created 'std.store' operation (which replaces 475 /// the original 'affine.store'). 476 class AffineStoreLowering : public OpRewritePattern<AffineStoreOp> { 477 public: 478 using OpRewritePattern<AffineStoreOp>::OpRewritePattern; 479 480 LogicalResult matchAndRewrite(AffineStoreOp op, 481 PatternRewriter &rewriter) const override { 482 // Expand affine map from 'affineStoreOp'. 483 SmallVector<Value, 8> indices(op.getMapOperands()); 484 auto maybeExpandedMap = 485 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 486 if (!maybeExpandedMap) 487 return failure(); 488 489 // Build std.store valueToStore, memref[expandedMap.results]. 490 rewriter.replaceOpWithNewOp<StoreOp>(op, op.getValueToStore(), 491 op.getMemRef(), *maybeExpandedMap); 492 return success(); 493 } 494 }; 495 496 /// Apply the affine maps from an 'affine.dma_start' operation to each of their 497 /// respective map operands, and feed the results to a newly created 498 /// 'std.dma_start' operation (which replaces the original 'affine.dma_start'). 499 class AffineDmaStartLowering : public OpRewritePattern<AffineDmaStartOp> { 500 public: 501 using OpRewritePattern<AffineDmaStartOp>::OpRewritePattern; 502 503 LogicalResult matchAndRewrite(AffineDmaStartOp op, 504 PatternRewriter &rewriter) const override { 505 SmallVector<Value, 8> operands(op.getOperands()); 506 auto operandsRef = llvm::makeArrayRef(operands); 507 508 // Expand affine map for DMA source memref. 509 auto maybeExpandedSrcMap = expandAffineMap( 510 rewriter, op.getLoc(), op.getSrcMap(), 511 operandsRef.drop_front(op.getSrcMemRefOperandIndex() + 1)); 512 if (!maybeExpandedSrcMap) 513 return failure(); 514 // Expand affine map for DMA destination memref. 515 auto maybeExpandedDstMap = expandAffineMap( 516 rewriter, op.getLoc(), op.getDstMap(), 517 operandsRef.drop_front(op.getDstMemRefOperandIndex() + 1)); 518 if (!maybeExpandedDstMap) 519 return failure(); 520 // Expand affine map for DMA tag memref. 521 auto maybeExpandedTagMap = expandAffineMap( 522 rewriter, op.getLoc(), op.getTagMap(), 523 operandsRef.drop_front(op.getTagMemRefOperandIndex() + 1)); 524 if (!maybeExpandedTagMap) 525 return failure(); 526 527 // Build std.dma_start operation with affine map results. 528 rewriter.replaceOpWithNewOp<DmaStartOp>( 529 op, op.getSrcMemRef(), *maybeExpandedSrcMap, op.getDstMemRef(), 530 *maybeExpandedDstMap, op.getNumElements(), op.getTagMemRef(), 531 *maybeExpandedTagMap, op.getStride(), op.getNumElementsPerStride()); 532 return success(); 533 } 534 }; 535 536 /// Apply the affine map from an 'affine.dma_wait' operation tag memref, 537 /// and feed the results to a newly created 'std.dma_wait' operation (which 538 /// replaces the original 'affine.dma_wait'). 539 class AffineDmaWaitLowering : public OpRewritePattern<AffineDmaWaitOp> { 540 public: 541 using OpRewritePattern<AffineDmaWaitOp>::OpRewritePattern; 542 543 LogicalResult matchAndRewrite(AffineDmaWaitOp op, 544 PatternRewriter &rewriter) const override { 545 // Expand affine map for DMA tag memref. 546 SmallVector<Value, 8> indices(op.getTagIndices()); 547 auto maybeExpandedTagMap = 548 expandAffineMap(rewriter, op.getLoc(), op.getTagMap(), indices); 549 if (!maybeExpandedTagMap) 550 return failure(); 551 552 // Build std.dma_wait operation with affine map results. 553 rewriter.replaceOpWithNewOp<DmaWaitOp>( 554 op, op.getTagMemRef(), *maybeExpandedTagMap, op.getNumElements()); 555 return success(); 556 } 557 }; 558 559 } // end namespace 560 561 void mlir::populateAffineToStdConversionPatterns( 562 OwningRewritePatternList &patterns, MLIRContext *ctx) { 563 // clang-format off 564 patterns.insert< 565 AffineApplyLowering, 566 AffineDmaStartLowering, 567 AffineDmaWaitLowering, 568 AffineLoadLowering, 569 AffineMinLowering, 570 AffineMaxLowering, 571 AffinePrefetchLowering, 572 AffineStoreLowering, 573 AffineForLowering, 574 AffineIfLowering, 575 AffineTerminatorLowering>(ctx); 576 // clang-format on 577 } 578 579 namespace { 580 class LowerAffinePass : public FunctionPass<LowerAffinePass> { 581 /// Include the generated pass utilities. 582 #define GEN_PASS_ConvertAffineToStandard 583 #include "mlir/Conversion/Passes.h.inc" 584 585 void runOnFunction() override { 586 OwningRewritePatternList patterns; 587 populateAffineToStdConversionPatterns(patterns, &getContext()); 588 ConversionTarget target(getContext()); 589 target.addLegalDialect<loop::LoopOpsDialect, StandardOpsDialect>(); 590 if (failed(applyPartialConversion(getFunction(), target, patterns))) 591 signalPassFailure(); 592 } 593 }; 594 } // namespace 595 596 /// Lowers If and For operations within a function into their lower level CFG 597 /// equivalent blocks. 598 std::unique_ptr<OpPassBase<FuncOp>> mlir::createLowerAffinePass() { 599 return std::make_unique<LowerAffinePass>(); 600 } 601