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/IR/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 (int64_t step : op.steps()) 198 steps.push_back(rewriter.create<arith::ConstantIndexOp>(loc, step)); 199 200 // Get the terminator op. 201 Operation *affineParOpTerminator = op.getBody()->getTerminator(); 202 scf::ParallelOp parOp; 203 if (op.results().empty()) { 204 // Case with no reduction operations/return values. 205 parOp = rewriter.create<scf::ParallelOp>(loc, lowerBoundTuple, 206 upperBoundTuple, steps, 207 /*bodyBuilderFn=*/nullptr); 208 rewriter.eraseBlock(parOp.getBody()); 209 rewriter.inlineRegionBefore(op.region(), parOp.getRegion(), 210 parOp.getRegion().end()); 211 rewriter.replaceOp(op, parOp.getResults()); 212 return success(); 213 } 214 // Case with affine.parallel with reduction operations/return values. 215 // scf.parallel handles the reduction operation differently unlike 216 // affine.parallel. 217 ArrayRef<Attribute> reductions = op.reductions().getValue(); 218 for (auto pair : llvm::zip(reductions, op.getResultTypes())) { 219 // For each of the reduction operations get the identity values for 220 // initialization of the result values. 221 Attribute reduction = std::get<0>(pair); 222 Type resultType = std::get<1>(pair); 223 Optional<arith::AtomicRMWKind> reductionOp = 224 arith::symbolizeAtomicRMWKind( 225 static_cast<uint64_t>(reduction.cast<IntegerAttr>().getInt())); 226 assert(reductionOp && "Reduction operation cannot be of None Type"); 227 arith::AtomicRMWKind reductionOpValue = *reductionOp; 228 identityVals.push_back( 229 arith::getIdentityValue(reductionOpValue, resultType, rewriter, loc)); 230 } 231 parOp = rewriter.create<scf::ParallelOp>( 232 loc, lowerBoundTuple, upperBoundTuple, steps, identityVals, 233 /*bodyBuilderFn=*/nullptr); 234 235 // Copy the body of the affine.parallel op. 236 rewriter.eraseBlock(parOp.getBody()); 237 rewriter.inlineRegionBefore(op.region(), parOp.getRegion(), 238 parOp.getRegion().end()); 239 assert(reductions.size() == affineParOpTerminator->getNumOperands() && 240 "Unequal number of reductions and operands."); 241 for (unsigned i = 0, end = reductions.size(); i < end; i++) { 242 // For each of the reduction operations get the respective mlir::Value. 243 Optional<arith::AtomicRMWKind> reductionOp = 244 arith::symbolizeAtomicRMWKind( 245 reductions[i].cast<IntegerAttr>().getInt()); 246 assert(reductionOp && "Reduction Operation cannot be of None Type"); 247 arith::AtomicRMWKind reductionOpValue = *reductionOp; 248 rewriter.setInsertionPoint(&parOp.getBody()->back()); 249 auto reduceOp = rewriter.create<scf::ReduceOp>( 250 loc, affineParOpTerminator->getOperand(i)); 251 rewriter.setInsertionPointToEnd(&reduceOp.getReductionOperator().front()); 252 Value reductionResult = arith::getReductionOp( 253 reductionOpValue, rewriter, loc, 254 reduceOp.getReductionOperator().front().getArgument(0), 255 reduceOp.getReductionOperator().front().getArgument(1)); 256 rewriter.create<scf::ReduceReturnOp>(loc, reductionResult); 257 } 258 rewriter.replaceOp(op, parOp.getResults()); 259 return success(); 260 } 261 }; 262 263 class AffineIfLowering : public OpRewritePattern<AffineIfOp> { 264 public: 265 using OpRewritePattern<AffineIfOp>::OpRewritePattern; 266 267 LogicalResult matchAndRewrite(AffineIfOp op, 268 PatternRewriter &rewriter) const override { 269 auto loc = op.getLoc(); 270 271 // Now we just have to handle the condition logic. 272 auto integerSet = op.getIntegerSet(); 273 Value zeroConstant = rewriter.create<arith::ConstantIndexOp>(loc, 0); 274 SmallVector<Value, 8> operands(op.getOperands()); 275 auto operandsRef = llvm::makeArrayRef(operands); 276 277 // Calculate cond as a conjunction without short-circuiting. 278 Value cond = nullptr; 279 for (unsigned i = 0, e = integerSet.getNumConstraints(); i < e; ++i) { 280 AffineExpr constraintExpr = integerSet.getConstraint(i); 281 bool isEquality = integerSet.isEq(i); 282 283 // Build and apply an affine expression 284 auto numDims = integerSet.getNumDims(); 285 Value affResult = expandAffineExpr(rewriter, loc, constraintExpr, 286 operandsRef.take_front(numDims), 287 operandsRef.drop_front(numDims)); 288 if (!affResult) 289 return failure(); 290 auto pred = 291 isEquality ? arith::CmpIPredicate::eq : arith::CmpIPredicate::sge; 292 Value cmpVal = 293 rewriter.create<arith::CmpIOp>(loc, pred, affResult, zeroConstant); 294 cond = cond 295 ? rewriter.create<arith::AndIOp>(loc, cond, cmpVal).getResult() 296 : cmpVal; 297 } 298 cond = cond ? cond 299 : rewriter.create<arith::ConstantIntOp>(loc, /*value=*/1, 300 /*width=*/1); 301 302 bool hasElseRegion = !op.elseRegion().empty(); 303 auto ifOp = rewriter.create<scf::IfOp>(loc, op.getResultTypes(), cond, 304 hasElseRegion); 305 rewriter.inlineRegionBefore(op.thenRegion(), &ifOp.getThenRegion().back()); 306 rewriter.eraseBlock(&ifOp.getThenRegion().back()); 307 if (hasElseRegion) { 308 rewriter.inlineRegionBefore(op.elseRegion(), 309 &ifOp.getElseRegion().back()); 310 rewriter.eraseBlock(&ifOp.getElseRegion().back()); 311 } 312 313 // Replace the Affine IfOp finally. 314 rewriter.replaceOp(op, ifOp.getResults()); 315 return success(); 316 } 317 }; 318 319 /// Convert an "affine.apply" operation into a sequence of arithmetic 320 /// operations using the StandardOps dialect. 321 class AffineApplyLowering : public OpRewritePattern<AffineApplyOp> { 322 public: 323 using OpRewritePattern<AffineApplyOp>::OpRewritePattern; 324 325 LogicalResult matchAndRewrite(AffineApplyOp op, 326 PatternRewriter &rewriter) const override { 327 auto maybeExpandedMap = 328 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), 329 llvm::to_vector<8>(op.getOperands())); 330 if (!maybeExpandedMap) 331 return failure(); 332 rewriter.replaceOp(op, *maybeExpandedMap); 333 return success(); 334 } 335 }; 336 337 /// Apply the affine map from an 'affine.load' operation to its operands, and 338 /// feed the results to a newly created 'memref.load' operation (which replaces 339 /// the original 'affine.load'). 340 class AffineLoadLowering : public OpRewritePattern<AffineLoadOp> { 341 public: 342 using OpRewritePattern<AffineLoadOp>::OpRewritePattern; 343 344 LogicalResult matchAndRewrite(AffineLoadOp op, 345 PatternRewriter &rewriter) const override { 346 // Expand affine map from 'affineLoadOp'. 347 SmallVector<Value, 8> indices(op.getMapOperands()); 348 auto resultOperands = 349 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 350 if (!resultOperands) 351 return failure(); 352 353 // Build vector.load memref[expandedMap.results]. 354 rewriter.replaceOpWithNewOp<memref::LoadOp>(op, op.getMemRef(), 355 *resultOperands); 356 return success(); 357 } 358 }; 359 360 /// Apply the affine map from an 'affine.prefetch' operation to its operands, 361 /// and feed the results to a newly created 'memref.prefetch' operation (which 362 /// replaces the original 'affine.prefetch'). 363 class AffinePrefetchLowering : public OpRewritePattern<AffinePrefetchOp> { 364 public: 365 using OpRewritePattern<AffinePrefetchOp>::OpRewritePattern; 366 367 LogicalResult matchAndRewrite(AffinePrefetchOp op, 368 PatternRewriter &rewriter) const override { 369 // Expand affine map from 'affinePrefetchOp'. 370 SmallVector<Value, 8> indices(op.getMapOperands()); 371 auto resultOperands = 372 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 373 if (!resultOperands) 374 return failure(); 375 376 // Build memref.prefetch memref[expandedMap.results]. 377 rewriter.replaceOpWithNewOp<memref::PrefetchOp>( 378 op, op.memref(), *resultOperands, op.isWrite(), op.localityHint(), 379 op.isDataCache()); 380 return success(); 381 } 382 }; 383 384 /// Apply the affine map from an 'affine.store' operation to its operands, and 385 /// feed the results to a newly created 'memref.store' operation (which replaces 386 /// the original 'affine.store'). 387 class AffineStoreLowering : public OpRewritePattern<AffineStoreOp> { 388 public: 389 using OpRewritePattern<AffineStoreOp>::OpRewritePattern; 390 391 LogicalResult matchAndRewrite(AffineStoreOp op, 392 PatternRewriter &rewriter) const override { 393 // Expand affine map from 'affineStoreOp'. 394 SmallVector<Value, 8> indices(op.getMapOperands()); 395 auto maybeExpandedMap = 396 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 397 if (!maybeExpandedMap) 398 return failure(); 399 400 // Build memref.store valueToStore, memref[expandedMap.results]. 401 rewriter.replaceOpWithNewOp<memref::StoreOp>( 402 op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap); 403 return success(); 404 } 405 }; 406 407 /// Apply the affine maps from an 'affine.dma_start' operation to each of their 408 /// respective map operands, and feed the results to a newly created 409 /// 'memref.dma_start' operation (which replaces the original 410 /// 'affine.dma_start'). 411 class AffineDmaStartLowering : public OpRewritePattern<AffineDmaStartOp> { 412 public: 413 using OpRewritePattern<AffineDmaStartOp>::OpRewritePattern; 414 415 LogicalResult matchAndRewrite(AffineDmaStartOp op, 416 PatternRewriter &rewriter) const override { 417 SmallVector<Value, 8> operands(op.getOperands()); 418 auto operandsRef = llvm::makeArrayRef(operands); 419 420 // Expand affine map for DMA source memref. 421 auto maybeExpandedSrcMap = expandAffineMap( 422 rewriter, op.getLoc(), op.getSrcMap(), 423 operandsRef.drop_front(op.getSrcMemRefOperandIndex() + 1)); 424 if (!maybeExpandedSrcMap) 425 return failure(); 426 // Expand affine map for DMA destination memref. 427 auto maybeExpandedDstMap = expandAffineMap( 428 rewriter, op.getLoc(), op.getDstMap(), 429 operandsRef.drop_front(op.getDstMemRefOperandIndex() + 1)); 430 if (!maybeExpandedDstMap) 431 return failure(); 432 // Expand affine map for DMA tag memref. 433 auto maybeExpandedTagMap = expandAffineMap( 434 rewriter, op.getLoc(), op.getTagMap(), 435 operandsRef.drop_front(op.getTagMemRefOperandIndex() + 1)); 436 if (!maybeExpandedTagMap) 437 return failure(); 438 439 // Build memref.dma_start operation with affine map results. 440 rewriter.replaceOpWithNewOp<memref::DmaStartOp>( 441 op, op.getSrcMemRef(), *maybeExpandedSrcMap, op.getDstMemRef(), 442 *maybeExpandedDstMap, op.getNumElements(), op.getTagMemRef(), 443 *maybeExpandedTagMap, op.getStride(), op.getNumElementsPerStride()); 444 return success(); 445 } 446 }; 447 448 /// Apply the affine map from an 'affine.dma_wait' operation tag memref, 449 /// and feed the results to a newly created 'memref.dma_wait' operation (which 450 /// replaces the original 'affine.dma_wait'). 451 class AffineDmaWaitLowering : public OpRewritePattern<AffineDmaWaitOp> { 452 public: 453 using OpRewritePattern<AffineDmaWaitOp>::OpRewritePattern; 454 455 LogicalResult matchAndRewrite(AffineDmaWaitOp op, 456 PatternRewriter &rewriter) const override { 457 // Expand affine map for DMA tag memref. 458 SmallVector<Value, 8> indices(op.getTagIndices()); 459 auto maybeExpandedTagMap = 460 expandAffineMap(rewriter, op.getLoc(), op.getTagMap(), indices); 461 if (!maybeExpandedTagMap) 462 return failure(); 463 464 // Build memref.dma_wait operation with affine map results. 465 rewriter.replaceOpWithNewOp<memref::DmaWaitOp>( 466 op, op.getTagMemRef(), *maybeExpandedTagMap, op.getNumElements()); 467 return success(); 468 } 469 }; 470 471 /// Apply the affine map from an 'affine.vector_load' operation to its operands, 472 /// and feed the results to a newly created 'vector.load' operation (which 473 /// replaces the original 'affine.vector_load'). 474 class AffineVectorLoadLowering : public OpRewritePattern<AffineVectorLoadOp> { 475 public: 476 using OpRewritePattern<AffineVectorLoadOp>::OpRewritePattern; 477 478 LogicalResult matchAndRewrite(AffineVectorLoadOp op, 479 PatternRewriter &rewriter) const override { 480 // Expand affine map from 'affineVectorLoadOp'. 481 SmallVector<Value, 8> indices(op.getMapOperands()); 482 auto resultOperands = 483 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 484 if (!resultOperands) 485 return failure(); 486 487 // Build vector.load memref[expandedMap.results]. 488 rewriter.replaceOpWithNewOp<vector::LoadOp>( 489 op, op.getVectorType(), op.getMemRef(), *resultOperands); 490 return success(); 491 } 492 }; 493 494 /// Apply the affine map from an 'affine.vector_store' operation to its 495 /// operands, and feed the results to a newly created 'vector.store' operation 496 /// (which replaces the original 'affine.vector_store'). 497 class AffineVectorStoreLowering : public OpRewritePattern<AffineVectorStoreOp> { 498 public: 499 using OpRewritePattern<AffineVectorStoreOp>::OpRewritePattern; 500 501 LogicalResult matchAndRewrite(AffineVectorStoreOp op, 502 PatternRewriter &rewriter) const override { 503 // Expand affine map from 'affineVectorStoreOp'. 504 SmallVector<Value, 8> indices(op.getMapOperands()); 505 auto maybeExpandedMap = 506 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 507 if (!maybeExpandedMap) 508 return failure(); 509 510 rewriter.replaceOpWithNewOp<vector::StoreOp>( 511 op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap); 512 return success(); 513 } 514 }; 515 516 } // namespace 517 518 void mlir::populateAffineToStdConversionPatterns(RewritePatternSet &patterns) { 519 // clang-format off 520 patterns.add< 521 AffineApplyLowering, 522 AffineDmaStartLowering, 523 AffineDmaWaitLowering, 524 AffineLoadLowering, 525 AffineMinLowering, 526 AffineMaxLowering, 527 AffineParallelLowering, 528 AffinePrefetchLowering, 529 AffineStoreLowering, 530 AffineForLowering, 531 AffineIfLowering, 532 AffineYieldOpLowering>(patterns.getContext()); 533 // clang-format on 534 } 535 536 void mlir::populateAffineToVectorConversionPatterns( 537 RewritePatternSet &patterns) { 538 // clang-format off 539 patterns.add< 540 AffineVectorLoadLowering, 541 AffineVectorStoreLowering>(patterns.getContext()); 542 // clang-format on 543 } 544 545 namespace { 546 class LowerAffinePass : public ConvertAffineToStandardBase<LowerAffinePass> { 547 void runOnOperation() override { 548 RewritePatternSet patterns(&getContext()); 549 populateAffineToStdConversionPatterns(patterns); 550 populateAffineToVectorConversionPatterns(patterns); 551 ConversionTarget target(getContext()); 552 target.addLegalDialect<arith::ArithmeticDialect, memref::MemRefDialect, 553 scf::SCFDialect, VectorDialect>(); 554 if (failed(applyPartialConversion(getOperation(), target, 555 std::move(patterns)))) 556 signalPassFailure(); 557 } 558 }; 559 } // namespace 560 561 /// Lowers If and For operations within a function into their lower level CFG 562 /// equivalent blocks. 563 std::unique_ptr<Pass> mlir::createLowerAffinePass() { 564 return std::make_unique<LowerAffinePass>(); 565 } 566