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