diff --git a/mlir/include/mlir/Dialect/Linalg/Passes.td b/mlir/include/mlir/Dialect/Linalg/Passes.td --- a/mlir/include/mlir/Dialect/Linalg/Passes.td +++ b/mlir/include/mlir/Dialect/Linalg/Passes.td @@ -43,7 +43,10 @@ "Allows the return of memrefs (for testing purposes only)">, Option<"useAlloca", "use-alloca", "bool", /*default=*/"false", - "Use stack allocations for memrefs (for testing purposes only)"> + "Use stack allocations for memrefs (for testing purposes only)">, + Option<"analysisFuzzerSeed", "analysis-fuzzer-seed", "unsigned", + /*default=*/"0", + "Analyze ops in random order with a given seed (fuzzer)"> ]; let constructor = "mlir::createLinalgComprehensiveModuleBufferizePass()"; } diff --git a/mlir/include/mlir/Dialect/Linalg/Transforms/ComprehensiveBufferize.h b/mlir/include/mlir/Dialect/Linalg/Transforms/ComprehensiveBufferize.h --- a/mlir/include/mlir/Dialect/Linalg/Transforms/ComprehensiveBufferize.h +++ b/mlir/include/mlir/Dialect/Linalg/Transforms/ComprehensiveBufferize.h @@ -173,7 +173,8 @@ /// Analyze the `ops` to determine which OpResults are inplaceable. LogicalResult inPlaceAnalysis(SmallVector &ops, BufferizationAliasInfo &aliasInfo, - const DominanceInfo &domInfo); + const DominanceInfo &domInfo, + unsigned analysisFuzzerSeed = 0); /// Default allocation function that is used by the comprehensive bufferization /// pass. The default currently creates a ranked memref using `memref.alloc`. diff --git a/mlir/lib/Dialect/Linalg/Transforms/ComprehensiveBufferize.cpp b/mlir/lib/Dialect/Linalg/Transforms/ComprehensiveBufferize.cpp --- a/mlir/lib/Dialect/Linalg/Transforms/ComprehensiveBufferize.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/ComprehensiveBufferize.cpp @@ -107,6 +107,8 @@ #include "mlir/Dialect/Linalg/Transforms/ComprehensiveBufferize.h" +#include + #include "PassDetail.h" #include "mlir/Dialect/Linalg/IR/LinalgOps.h" #include "mlir/Dialect/Linalg/Passes.h" @@ -2359,7 +2361,16 @@ /// ExtractSliceOps are interleaved with other ops in traversal order. LogicalResult mlir::linalg::inPlaceAnalysis(SmallVector &ops, BufferizationAliasInfo &aliasInfo, - const DominanceInfo &domInfo) { + const DominanceInfo &domInfo, + unsigned analysisFuzzerSeed) { + if (analysisFuzzerSeed) { + // This is a fuzzer. For testing purposes only. Randomize the order in which + // operations are analyzed. The bufferization quality is likely worse, but + // we want to make sure that no assertions are triggered anywhere. + std::mt19937 g(analysisFuzzerSeed); + llvm::shuffle(ops.begin(), ops.end(), g); + } + // Walk ops in reverse for better interference analysis. for (Operation *op : reverse(ops)) { for (OpOperand &opOperand : op->getOpOperands()) @@ -2383,7 +2394,8 @@ /// Analyze the `funcOp` body to determine which OpResults are inplaceable. static LogicalResult inPlaceAnalysisFuncOpBody(FuncOp funcOp, BufferizationAliasInfo &aliasInfo, - const DominanceInfo &domInfo) { + const DominanceInfo &domInfo, + unsigned analysisFuzzerSeed = 0) { LLVM_DEBUG(llvm::dbgs() << "\n\n"); LDBG("Begin InPlaceAnalysisFuncOpInternals:\n" << funcOp << '\n'); assert(funcOp && funcOp->getNumRegions() > 0 && !funcOp.body().empty() && @@ -2408,7 +2420,8 @@ aliasInfo.setBufferizesToWritableMemory(bbArg); } - LogicalResult res = inPlaceAnalysis(ops, aliasInfo, domInfo); + LogicalResult res = + inPlaceAnalysis(ops, aliasInfo, domInfo, analysisFuzzerSeed); LDBG("End InPlaceAnalysisFuncOpInternals:\n" << funcOp << '\n'); return res; @@ -3099,7 +3112,8 @@ setInPlaceFuncArgument(bbArg); // If the analysis fails, just return. - if (failed(inPlaceAnalysisFuncOpBody(funcOp, aliasInfo, domInfo))) { + if (failed(inPlaceAnalysisFuncOpBody(funcOp, aliasInfo, domInfo, + analysisFuzzerSeed))) { signalPassFailure(); return; } diff --git a/mlir/test/Dialect/Linalg/comprehensive-module-bufferize-analysis.mlir b/mlir/test/Dialect/Linalg/comprehensive-module-bufferize-analysis.mlir --- a/mlir/test/Dialect/Linalg/comprehensive-module-bufferize-analysis.mlir +++ b/mlir/test/Dialect/Linalg/comprehensive-module-bufferize-analysis.mlir @@ -1,5 +1,10 @@ // RUN: mlir-opt %s -linalg-comprehensive-module-bufferize=test-analysis-only -split-input-file | FileCheck %s +// Run fuzzer with different seeds. +// RUN: mlir-opt %s -linalg-comprehensive-module-bufferize="test-analysis-only analysis-fuzzer-seed=23" -split-input-file -o /dev/null +// RUN: mlir-opt %s -linalg-comprehensive-module-bufferize="test-analysis-only analysis-fuzzer-seed=59" -split-input-file -o /dev/null +// RUN: mlir-opt %s -linalg-comprehensive-module-bufferize="test-analysis-only analysis-fuzzer-seed=91" -split-input-file -o /dev/null + //===----------------------------------------------------------------------===// // Simple cases //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/Linalg/comprehensive-module-bufferize.mlir b/mlir/test/Dialect/Linalg/comprehensive-module-bufferize.mlir --- a/mlir/test/Dialect/Linalg/comprehensive-module-bufferize.mlir +++ b/mlir/test/Dialect/Linalg/comprehensive-module-bufferize.mlir @@ -1,5 +1,10 @@ // RUN: mlir-opt %s -linalg-comprehensive-module-bufferize=allow-return-memref -split-input-file | FileCheck %s +// Run fuzzer with different seeds. +// RUN: mlir-opt %s -linalg-comprehensive-module-bufferize="test-analysis-only analysis-fuzzer-seed=23" -split-input-file -o /dev/null +// RUN: mlir-opt %s -linalg-comprehensive-module-bufferize="test-analysis-only analysis-fuzzer-seed=59" -split-input-file -o /dev/null +// RUN: mlir-opt %s -linalg-comprehensive-module-bufferize="test-analysis-only analysis-fuzzer-seed=91" -split-input-file -o /dev/null + // CHECK-LABEL: func @transfer_read(%{{.*}}: memref) -> vector<4xf32> { func @transfer_read(%A : tensor) -> (vector<4xf32>) { %c0 = arith.constant 0 : index