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 "../PassDetail.h" 17 #include "mlir/Dialect/Affine/IR/AffineOps.h" 18 #include "mlir/Dialect/Affine/Utils.h" 19 #include "mlir/Dialect/MemRef/IR/MemRef.h" 20 #include "mlir/Dialect/SCF/SCF.h" 21 #include "mlir/Dialect/Vector/IR/VectorOps.h" 22 #include "mlir/IR/BlockAndValueMapping.h" 23 #include "mlir/IR/IntegerSet.h" 24 #include "mlir/IR/MLIRContext.h" 25 #include "mlir/Pass/Pass.h" 26 #include "mlir/Transforms/DialectConversion.h" 27 #include "mlir/Transforms/Passes.h" 28 29 using namespace mlir; 30 using namespace mlir::vector; 31 32 /// Given a range of values, emit the code that reduces them with "min" or "max" 33 /// depending on the provided comparison predicate. The predicate defines which 34 /// comparison to perform, "lt" for "min", "gt" for "max" and is used for the 35 /// `cmpi` operation followed by the `select` operation: 36 /// 37 /// %cond = arith.cmpi "predicate" %v0, %v1 38 /// %result = select %cond, %v0, %v1 39 /// 40 /// Multiple values are scanned in a linear sequence. This creates a data 41 /// dependences that wouldn't exist in a tree reduction, but is easier to 42 /// recognize as a reduction by the subsequent passes. 43 static Value buildMinMaxReductionSeq(Location loc, 44 arith::CmpIPredicate predicate, 45 ValueRange values, OpBuilder &builder) { 46 assert(!llvm::empty(values) && "empty min/max chain"); 47 48 auto valueIt = values.begin(); 49 Value value = *valueIt++; 50 for (; valueIt != values.end(); ++valueIt) { 51 auto cmpOp = builder.create<arith::CmpIOp>(loc, predicate, value, *valueIt); 52 value = builder.create<arith::SelectOp>(loc, cmpOp.getResult(), value, 53 *valueIt); 54 } 55 56 return value; 57 } 58 59 /// Emit instructions that correspond to computing the maximum value among the 60 /// values of a (potentially) multi-output affine map applied to `operands`. 61 static Value lowerAffineMapMax(OpBuilder &builder, Location loc, AffineMap map, 62 ValueRange operands) { 63 if (auto values = expandAffineMap(builder, loc, map, operands)) 64 return buildMinMaxReductionSeq(loc, arith::CmpIPredicate::sgt, *values, 65 builder); 66 return nullptr; 67 } 68 69 /// Emit instructions that correspond to computing the minimum value among the 70 /// values of a (potentially) multi-output affine map applied to `operands`. 71 static Value lowerAffineMapMin(OpBuilder &builder, Location loc, AffineMap map, 72 ValueRange operands) { 73 if (auto values = expandAffineMap(builder, loc, map, operands)) 74 return buildMinMaxReductionSeq(loc, arith::CmpIPredicate::slt, *values, 75 builder); 76 return nullptr; 77 } 78 79 /// Emit instructions that correspond to the affine map in the upper bound 80 /// applied to the respective operands, and compute the minimum value across 81 /// the results. 82 Value mlir::lowerAffineUpperBound(AffineForOp op, OpBuilder &builder) { 83 return lowerAffineMapMin(builder, op.getLoc(), op.getUpperBoundMap(), 84 op.getUpperBoundOperands()); 85 } 86 87 /// Emit instructions that correspond to the affine map in the lower bound 88 /// applied to the respective operands, and compute the maximum value across 89 /// the results. 90 Value mlir::lowerAffineLowerBound(AffineForOp op, OpBuilder &builder) { 91 return lowerAffineMapMax(builder, op.getLoc(), op.getLowerBoundMap(), 92 op.getLowerBoundOperands()); 93 } 94 95 namespace { 96 class AffineMinLowering : public OpRewritePattern<AffineMinOp> { 97 public: 98 using OpRewritePattern<AffineMinOp>::OpRewritePattern; 99 100 LogicalResult matchAndRewrite(AffineMinOp op, 101 PatternRewriter &rewriter) const override { 102 Value reduced = 103 lowerAffineMapMin(rewriter, op.getLoc(), op.map(), op.operands()); 104 if (!reduced) 105 return failure(); 106 107 rewriter.replaceOp(op, reduced); 108 return success(); 109 } 110 }; 111 112 class AffineMaxLowering : public OpRewritePattern<AffineMaxOp> { 113 public: 114 using OpRewritePattern<AffineMaxOp>::OpRewritePattern; 115 116 LogicalResult matchAndRewrite(AffineMaxOp op, 117 PatternRewriter &rewriter) const override { 118 Value reduced = 119 lowerAffineMapMax(rewriter, op.getLoc(), op.map(), op.operands()); 120 if (!reduced) 121 return failure(); 122 123 rewriter.replaceOp(op, reduced); 124 return success(); 125 } 126 }; 127 128 /// Affine yields ops are removed. 129 class AffineYieldOpLowering : public OpRewritePattern<AffineYieldOp> { 130 public: 131 using OpRewritePattern<AffineYieldOp>::OpRewritePattern; 132 133 LogicalResult matchAndRewrite(AffineYieldOp op, 134 PatternRewriter &rewriter) const override { 135 if (isa<scf::ParallelOp>(op->getParentOp())) { 136 // scf.parallel does not yield any values via its terminator scf.yield but 137 // models reductions differently using additional ops in its region. 138 rewriter.replaceOpWithNewOp<scf::YieldOp>(op); 139 return success(); 140 } 141 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, op.operands()); 142 return success(); 143 } 144 }; 145 146 class AffineForLowering : public OpRewritePattern<AffineForOp> { 147 public: 148 using OpRewritePattern<AffineForOp>::OpRewritePattern; 149 150 LogicalResult matchAndRewrite(AffineForOp op, 151 PatternRewriter &rewriter) const override { 152 Location loc = op.getLoc(); 153 Value lowerBound = lowerAffineLowerBound(op, rewriter); 154 Value upperBound = lowerAffineUpperBound(op, rewriter); 155 Value step = rewriter.create<arith::ConstantIndexOp>(loc, op.getStep()); 156 auto scfForOp = rewriter.create<scf::ForOp>(loc, lowerBound, upperBound, 157 step, op.getIterOperands()); 158 rewriter.eraseBlock(scfForOp.getBody()); 159 rewriter.inlineRegionBefore(op.region(), scfForOp.getRegion(), 160 scfForOp.getRegion().end()); 161 rewriter.replaceOp(op, scfForOp.getResults()); 162 return success(); 163 } 164 }; 165 166 /// Convert an `affine.parallel` (loop nest) operation into a `scf.parallel` 167 /// operation. 168 class AffineParallelLowering : public OpRewritePattern<AffineParallelOp> { 169 public: 170 using OpRewritePattern<AffineParallelOp>::OpRewritePattern; 171 172 LogicalResult matchAndRewrite(AffineParallelOp op, 173 PatternRewriter &rewriter) const override { 174 Location loc = op.getLoc(); 175 SmallVector<Value, 8> steps; 176 SmallVector<Value, 8> upperBoundTuple; 177 SmallVector<Value, 8> lowerBoundTuple; 178 SmallVector<Value, 8> identityVals; 179 // Emit IR computing the lower and upper bound by expanding the map 180 // expression. 181 lowerBoundTuple.reserve(op.getNumDims()); 182 upperBoundTuple.reserve(op.getNumDims()); 183 for (unsigned i = 0, e = op.getNumDims(); i < e; ++i) { 184 Value lower = lowerAffineMapMax(rewriter, loc, op.getLowerBoundMap(i), 185 op.getLowerBoundsOperands()); 186 if (!lower) 187 return rewriter.notifyMatchFailure(op, "couldn't convert lower bounds"); 188 lowerBoundTuple.push_back(lower); 189 190 Value upper = lowerAffineMapMin(rewriter, loc, op.getUpperBoundMap(i), 191 op.getUpperBoundsOperands()); 192 if (!upper) 193 return rewriter.notifyMatchFailure(op, "couldn't convert upper bounds"); 194 upperBoundTuple.push_back(upper); 195 } 196 steps.reserve(op.steps().size()); 197 for (Attribute step : op.steps()) 198 steps.push_back(rewriter.create<arith::ConstantIndexOp>( 199 loc, step.cast<IntegerAttr>().getInt())); 200 201 // Get the terminator op. 202 Operation *affineParOpTerminator = op.getBody()->getTerminator(); 203 scf::ParallelOp parOp; 204 if (op.results().empty()) { 205 // Case with no reduction operations/return values. 206 parOp = rewriter.create<scf::ParallelOp>(loc, lowerBoundTuple, 207 upperBoundTuple, steps, 208 /*bodyBuilderFn=*/nullptr); 209 rewriter.eraseBlock(parOp.getBody()); 210 rewriter.inlineRegionBefore(op.region(), parOp.getRegion(), 211 parOp.getRegion().end()); 212 rewriter.replaceOp(op, parOp.getResults()); 213 return success(); 214 } 215 // Case with affine.parallel with reduction operations/return values. 216 // scf.parallel handles the reduction operation differently unlike 217 // affine.parallel. 218 ArrayRef<Attribute> reductions = op.reductions().getValue(); 219 for (auto pair : llvm::zip(reductions, op.getResultTypes())) { 220 // For each of the reduction operations get the identity values for 221 // initialization of the result values. 222 Attribute reduction = std::get<0>(pair); 223 Type resultType = std::get<1>(pair); 224 Optional<arith::AtomicRMWKind> reductionOp = 225 arith::symbolizeAtomicRMWKind( 226 static_cast<uint64_t>(reduction.cast<IntegerAttr>().getInt())); 227 assert(reductionOp.hasValue() && 228 "Reduction operation cannot be of None Type"); 229 arith::AtomicRMWKind reductionOpValue = reductionOp.getValue(); 230 identityVals.push_back( 231 arith::getIdentityValue(reductionOpValue, resultType, rewriter, loc)); 232 } 233 parOp = rewriter.create<scf::ParallelOp>( 234 loc, lowerBoundTuple, upperBoundTuple, steps, identityVals, 235 /*bodyBuilderFn=*/nullptr); 236 237 // Copy the body of the affine.parallel op. 238 rewriter.eraseBlock(parOp.getBody()); 239 rewriter.inlineRegionBefore(op.region(), parOp.getRegion(), 240 parOp.getRegion().end()); 241 assert(reductions.size() == affineParOpTerminator->getNumOperands() && 242 "Unequal number of reductions and operands."); 243 for (unsigned i = 0, end = reductions.size(); i < end; i++) { 244 // For each of the reduction operations get the respective mlir::Value. 245 Optional<arith::AtomicRMWKind> reductionOp = 246 arith::symbolizeAtomicRMWKind( 247 reductions[i].cast<IntegerAttr>().getInt()); 248 assert(reductionOp.hasValue() && 249 "Reduction Operation cannot be of None Type"); 250 arith::AtomicRMWKind reductionOpValue = reductionOp.getValue(); 251 rewriter.setInsertionPoint(&parOp.getBody()->back()); 252 auto reduceOp = rewriter.create<scf::ReduceOp>( 253 loc, affineParOpTerminator->getOperand(i)); 254 rewriter.setInsertionPointToEnd(&reduceOp.getReductionOperator().front()); 255 Value reductionResult = arith::getReductionOp( 256 reductionOpValue, rewriter, loc, 257 reduceOp.getReductionOperator().front().getArgument(0), 258 reduceOp.getReductionOperator().front().getArgument(1)); 259 rewriter.create<scf::ReduceReturnOp>(loc, reductionResult); 260 } 261 rewriter.replaceOp(op, parOp.getResults()); 262 return success(); 263 } 264 }; 265 266 class AffineIfLowering : public OpRewritePattern<AffineIfOp> { 267 public: 268 using OpRewritePattern<AffineIfOp>::OpRewritePattern; 269 270 LogicalResult matchAndRewrite(AffineIfOp op, 271 PatternRewriter &rewriter) const override { 272 auto loc = op.getLoc(); 273 274 // Now we just have to handle the condition logic. 275 auto integerSet = op.getIntegerSet(); 276 Value zeroConstant = rewriter.create<arith::ConstantIndexOp>(loc, 0); 277 SmallVector<Value, 8> operands(op.getOperands()); 278 auto operandsRef = llvm::makeArrayRef(operands); 279 280 // Calculate cond as a conjunction without short-circuiting. 281 Value cond = nullptr; 282 for (unsigned i = 0, e = integerSet.getNumConstraints(); i < e; ++i) { 283 AffineExpr constraintExpr = integerSet.getConstraint(i); 284 bool isEquality = integerSet.isEq(i); 285 286 // Build and apply an affine expression 287 auto numDims = integerSet.getNumDims(); 288 Value affResult = expandAffineExpr(rewriter, loc, constraintExpr, 289 operandsRef.take_front(numDims), 290 operandsRef.drop_front(numDims)); 291 if (!affResult) 292 return failure(); 293 auto pred = 294 isEquality ? arith::CmpIPredicate::eq : arith::CmpIPredicate::sge; 295 Value cmpVal = 296 rewriter.create<arith::CmpIOp>(loc, pred, affResult, zeroConstant); 297 cond = cond 298 ? rewriter.create<arith::AndIOp>(loc, cond, cmpVal).getResult() 299 : cmpVal; 300 } 301 cond = cond ? cond 302 : rewriter.create<arith::ConstantIntOp>(loc, /*value=*/1, 303 /*width=*/1); 304 305 bool hasElseRegion = !op.elseRegion().empty(); 306 auto ifOp = rewriter.create<scf::IfOp>(loc, op.getResultTypes(), cond, 307 hasElseRegion); 308 rewriter.inlineRegionBefore(op.thenRegion(), &ifOp.getThenRegion().back()); 309 rewriter.eraseBlock(&ifOp.getThenRegion().back()); 310 if (hasElseRegion) { 311 rewriter.inlineRegionBefore(op.elseRegion(), 312 &ifOp.getElseRegion().back()); 313 rewriter.eraseBlock(&ifOp.getElseRegion().back()); 314 } 315 316 // Replace the Affine IfOp finally. 317 rewriter.replaceOp(op, ifOp.getResults()); 318 return success(); 319 } 320 }; 321 322 /// Convert an "affine.apply" operation into a sequence of arithmetic 323 /// operations using the StandardOps dialect. 324 class AffineApplyLowering : public OpRewritePattern<AffineApplyOp> { 325 public: 326 using OpRewritePattern<AffineApplyOp>::OpRewritePattern; 327 328 LogicalResult matchAndRewrite(AffineApplyOp op, 329 PatternRewriter &rewriter) const override { 330 auto maybeExpandedMap = 331 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), 332 llvm::to_vector<8>(op.getOperands())); 333 if (!maybeExpandedMap) 334 return failure(); 335 rewriter.replaceOp(op, *maybeExpandedMap); 336 return success(); 337 } 338 }; 339 340 /// Apply the affine map from an 'affine.load' operation to its operands, and 341 /// feed the results to a newly created 'memref.load' operation (which replaces 342 /// the original 'affine.load'). 343 class AffineLoadLowering : public OpRewritePattern<AffineLoadOp> { 344 public: 345 using OpRewritePattern<AffineLoadOp>::OpRewritePattern; 346 347 LogicalResult matchAndRewrite(AffineLoadOp op, 348 PatternRewriter &rewriter) const override { 349 // Expand affine map from 'affineLoadOp'. 350 SmallVector<Value, 8> indices(op.getMapOperands()); 351 auto resultOperands = 352 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 353 if (!resultOperands) 354 return failure(); 355 356 // Build vector.load memref[expandedMap.results]. 357 rewriter.replaceOpWithNewOp<memref::LoadOp>(op, op.getMemRef(), 358 *resultOperands); 359 return success(); 360 } 361 }; 362 363 /// Apply the affine map from an 'affine.prefetch' operation to its operands, 364 /// and feed the results to a newly created 'memref.prefetch' operation (which 365 /// replaces the original 'affine.prefetch'). 366 class AffinePrefetchLowering : public OpRewritePattern<AffinePrefetchOp> { 367 public: 368 using OpRewritePattern<AffinePrefetchOp>::OpRewritePattern; 369 370 LogicalResult matchAndRewrite(AffinePrefetchOp op, 371 PatternRewriter &rewriter) const override { 372 // Expand affine map from 'affinePrefetchOp'. 373 SmallVector<Value, 8> indices(op.getMapOperands()); 374 auto resultOperands = 375 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 376 if (!resultOperands) 377 return failure(); 378 379 // Build memref.prefetch memref[expandedMap.results]. 380 rewriter.replaceOpWithNewOp<memref::PrefetchOp>( 381 op, op.memref(), *resultOperands, op.isWrite(), op.localityHint(), 382 op.isDataCache()); 383 return success(); 384 } 385 }; 386 387 /// Apply the affine map from an 'affine.store' operation to its operands, and 388 /// feed the results to a newly created 'memref.store' operation (which replaces 389 /// the original 'affine.store'). 390 class AffineStoreLowering : public OpRewritePattern<AffineStoreOp> { 391 public: 392 using OpRewritePattern<AffineStoreOp>::OpRewritePattern; 393 394 LogicalResult matchAndRewrite(AffineStoreOp op, 395 PatternRewriter &rewriter) const override { 396 // Expand affine map from 'affineStoreOp'. 397 SmallVector<Value, 8> indices(op.getMapOperands()); 398 auto maybeExpandedMap = 399 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 400 if (!maybeExpandedMap) 401 return failure(); 402 403 // Build memref.store valueToStore, memref[expandedMap.results]. 404 rewriter.replaceOpWithNewOp<memref::StoreOp>( 405 op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap); 406 return success(); 407 } 408 }; 409 410 /// Apply the affine maps from an 'affine.dma_start' operation to each of their 411 /// respective map operands, and feed the results to a newly created 412 /// 'memref.dma_start' operation (which replaces the original 413 /// 'affine.dma_start'). 414 class AffineDmaStartLowering : public OpRewritePattern<AffineDmaStartOp> { 415 public: 416 using OpRewritePattern<AffineDmaStartOp>::OpRewritePattern; 417 418 LogicalResult matchAndRewrite(AffineDmaStartOp op, 419 PatternRewriter &rewriter) const override { 420 SmallVector<Value, 8> operands(op.getOperands()); 421 auto operandsRef = llvm::makeArrayRef(operands); 422 423 // Expand affine map for DMA source memref. 424 auto maybeExpandedSrcMap = expandAffineMap( 425 rewriter, op.getLoc(), op.getSrcMap(), 426 operandsRef.drop_front(op.getSrcMemRefOperandIndex() + 1)); 427 if (!maybeExpandedSrcMap) 428 return failure(); 429 // Expand affine map for DMA destination memref. 430 auto maybeExpandedDstMap = expandAffineMap( 431 rewriter, op.getLoc(), op.getDstMap(), 432 operandsRef.drop_front(op.getDstMemRefOperandIndex() + 1)); 433 if (!maybeExpandedDstMap) 434 return failure(); 435 // Expand affine map for DMA tag memref. 436 auto maybeExpandedTagMap = expandAffineMap( 437 rewriter, op.getLoc(), op.getTagMap(), 438 operandsRef.drop_front(op.getTagMemRefOperandIndex() + 1)); 439 if (!maybeExpandedTagMap) 440 return failure(); 441 442 // Build memref.dma_start operation with affine map results. 443 rewriter.replaceOpWithNewOp<memref::DmaStartOp>( 444 op, op.getSrcMemRef(), *maybeExpandedSrcMap, op.getDstMemRef(), 445 *maybeExpandedDstMap, op.getNumElements(), op.getTagMemRef(), 446 *maybeExpandedTagMap, op.getStride(), op.getNumElementsPerStride()); 447 return success(); 448 } 449 }; 450 451 /// Apply the affine map from an 'affine.dma_wait' operation tag memref, 452 /// and feed the results to a newly created 'memref.dma_wait' operation (which 453 /// replaces the original 'affine.dma_wait'). 454 class AffineDmaWaitLowering : public OpRewritePattern<AffineDmaWaitOp> { 455 public: 456 using OpRewritePattern<AffineDmaWaitOp>::OpRewritePattern; 457 458 LogicalResult matchAndRewrite(AffineDmaWaitOp op, 459 PatternRewriter &rewriter) const override { 460 // Expand affine map for DMA tag memref. 461 SmallVector<Value, 8> indices(op.getTagIndices()); 462 auto maybeExpandedTagMap = 463 expandAffineMap(rewriter, op.getLoc(), op.getTagMap(), indices); 464 if (!maybeExpandedTagMap) 465 return failure(); 466 467 // Build memref.dma_wait operation with affine map results. 468 rewriter.replaceOpWithNewOp<memref::DmaWaitOp>( 469 op, op.getTagMemRef(), *maybeExpandedTagMap, op.getNumElements()); 470 return success(); 471 } 472 }; 473 474 /// Apply the affine map from an 'affine.vector_load' operation to its operands, 475 /// and feed the results to a newly created 'vector.load' operation (which 476 /// replaces the original 'affine.vector_load'). 477 class AffineVectorLoadLowering : public OpRewritePattern<AffineVectorLoadOp> { 478 public: 479 using OpRewritePattern<AffineVectorLoadOp>::OpRewritePattern; 480 481 LogicalResult matchAndRewrite(AffineVectorLoadOp op, 482 PatternRewriter &rewriter) const override { 483 // Expand affine map from 'affineVectorLoadOp'. 484 SmallVector<Value, 8> indices(op.getMapOperands()); 485 auto resultOperands = 486 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 487 if (!resultOperands) 488 return failure(); 489 490 // Build vector.load memref[expandedMap.results]. 491 rewriter.replaceOpWithNewOp<vector::LoadOp>( 492 op, op.getVectorType(), op.getMemRef(), *resultOperands); 493 return success(); 494 } 495 }; 496 497 /// Apply the affine map from an 'affine.vector_store' operation to its 498 /// operands, and feed the results to a newly created 'vector.store' operation 499 /// (which replaces the original 'affine.vector_store'). 500 class AffineVectorStoreLowering : public OpRewritePattern<AffineVectorStoreOp> { 501 public: 502 using OpRewritePattern<AffineVectorStoreOp>::OpRewritePattern; 503 504 LogicalResult matchAndRewrite(AffineVectorStoreOp op, 505 PatternRewriter &rewriter) const override { 506 // Expand affine map from 'affineVectorStoreOp'. 507 SmallVector<Value, 8> indices(op.getMapOperands()); 508 auto maybeExpandedMap = 509 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 510 if (!maybeExpandedMap) 511 return failure(); 512 513 rewriter.replaceOpWithNewOp<vector::StoreOp>( 514 op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap); 515 return success(); 516 } 517 }; 518 519 } // namespace 520 521 void mlir::populateAffineToStdConversionPatterns(RewritePatternSet &patterns) { 522 // clang-format off 523 patterns.add< 524 AffineApplyLowering, 525 AffineDmaStartLowering, 526 AffineDmaWaitLowering, 527 AffineLoadLowering, 528 AffineMinLowering, 529 AffineMaxLowering, 530 AffineParallelLowering, 531 AffinePrefetchLowering, 532 AffineStoreLowering, 533 AffineForLowering, 534 AffineIfLowering, 535 AffineYieldOpLowering>(patterns.getContext()); 536 // clang-format on 537 } 538 539 void mlir::populateAffineToVectorConversionPatterns( 540 RewritePatternSet &patterns) { 541 // clang-format off 542 patterns.add< 543 AffineVectorLoadLowering, 544 AffineVectorStoreLowering>(patterns.getContext()); 545 // clang-format on 546 } 547 548 namespace { 549 class LowerAffinePass : public ConvertAffineToStandardBase<LowerAffinePass> { 550 void runOnOperation() override { 551 RewritePatternSet patterns(&getContext()); 552 populateAffineToStdConversionPatterns(patterns); 553 populateAffineToVectorConversionPatterns(patterns); 554 ConversionTarget target(getContext()); 555 target.addLegalDialect<arith::ArithmeticDialect, memref::MemRefDialect, 556 scf::SCFDialect, VectorDialect>(); 557 if (failed(applyPartialConversion(getOperation(), target, 558 std::move(patterns)))) 559 signalPassFailure(); 560 } 561 }; 562 } // namespace 563 564 /// Lowers If and For operations within a function into their lower level CFG 565 /// equivalent blocks. 566 std::unique_ptr<Pass> mlir::createLowerAffinePass() { 567 return std::make_unique<LowerAffinePass>(); 568 } 569