27#include "llvm/Support/Debug.h"
31#define DEBUG_TYPE "memref-transforms"
32#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
36ParseResult parseLLVMTypeConverterOptions(
OpAsmParser &parser,
38 IntegerAttr &indexBitwidth,
41 StringAttr &dataLayout) {
42 bool seenUseAlignedAlloc =
false;
43 bool seenIndexBitwidth =
false;
44 bool seenUseGenericFunctions =
false;
45 bool seenUseBarePtrCallConv =
false;
46 bool seenDataLayout =
false;
48 auto parseDuplicate = [&](StringRef name,
bool &seen) -> ParseResult {
51 <<
"duplicate '" << name <<
"' option";
53 return ParseResult::success();
58 if (failed(parseDuplicate(
"use_aligned_alloc", seenUseAlignedAlloc)) ||
66 if (failed(parseDuplicate(
"index_bitwidth", seenIndexBitwidth)) ||
74 if (failed(parseDuplicate(
"use_generic_functions",
75 seenUseGenericFunctions)) ||
83 if (failed(parseDuplicate(
"use_bare_ptr_call_conv",
84 seenUseBarePtrCallConv)) ||
92 if (failed(parseDuplicate(
"data_layout", seenDataLayout)) ||
104 IntegerAttr indexBitwidth,
107 StringAttr dataLayout) {
108 bool needsSpace =
false;
109 auto printOption = [&](StringRef name,
Attribute value) {
114 printer << name <<
" = ";
119 printOption(
"use_aligned_alloc", useAlignedAlloc);
120 printOption(
"index_bitwidth", indexBitwidth);
121 printOption(
"use_generic_functions", useGenericFunctions);
122 printOption(
"use_bare_ptr_call_conv", useBarePtrCallConv);
123 printOption(
"data_layout", dataLayout);
132std::unique_ptr<TypeConverter>
133transform::MemrefToLLVMTypeConverterOp::getTypeConverter() {
138 options.useGenericFunctions = getUseGenericFunctions();
148 options.useBarePtrCallConv = getUseBarePtrCallConv();
153StringRef transform::MemrefToLLVMTypeConverterOp::getTypeConverterType() {
154 return "LLVMTypeConverter";
164 explicit AllocToAllocaPattern(Operation *analysisRoot, int64_t maxSize = 0)
165 : OpRewritePattern<memref::AllocOp>(analysisRoot->
getContext()),
166 dataLayoutAnalysis(analysisRoot), maxSize(maxSize) {}
168 LogicalResult matchAndRewrite(memref::AllocOp op,
169 PatternRewriter &rewriter)
const override {
171 rewriter, op, [
this](memref::AllocOp alloc, memref::DeallocOp dealloc) {
172 MemRefType type = alloc.getMemref().getType();
173 if (!type.hasStaticShape())
176 const DataLayout &dataLayout = dataLayoutAnalysis.getAtOrAbove(alloc);
177 int64_t elementSize = dataLayout.
getTypeSize(type.getElementType());
178 return maxSize == 0 || type.getNumElements() * elementSize < maxSize;
183 DataLayoutAnalysis dataLayoutAnalysis;
188void transform::ApplyAllocToAllocaOp::populatePatterns(
191void transform::ApplyAllocToAllocaOp::populatePatternsWithState(
193 patterns.
insert<AllocToAllocaPattern>(
197void transform::ApplyExpandOpsPatternsOp::populatePatterns(
202void transform::ApplyExpandStridedMetadataPatternsOp::populatePatterns(
207void transform::ApplyExtractAddressComputationsPatternsOp::populatePatterns(
212void transform::ApplyFoldMemrefAliasOpsPatternsOp::populatePatterns(
217void transform::ApplyResolveRankedShapedTypeResultDimsPatternsOp::
228template <
typename AllocLikeOp>
231 MemRefType memrefType = allocLikeOp.getType();
232 if (!memrefType.hasStaticShape()) {
234 <<
"conversion to a global op requires statically shaped memrefs, "
239 if (!allocLikeOp.getSymbolOperands().empty()) {
241 <<
"conversion to a global op does not support symbol operands, but "
248 if (failed(memrefType.getStridesAndOffset(strides, offset))) {
250 <<
"conversion to a global op requires strided layout, but got "
253 if (!ShapedType::isStatic(offset) || !ShapedType::isStaticShape(strides)) {
255 <<
"conversion to a global op does not support dynamic offset or "
267template <
typename AllocLikeOp>
270 AllocLikeOp allocLikeOp, StringRef globalName,
271 memref::GlobalOp &globalOp,
272 memref::GetGlobalOp &getGlobalOp) {
279 Location loc = allocLikeOp->getLoc();
283 assert(symbolTableOp &&
"expected payload to be in symbol table");
287 Type resultType = allocLikeOp.getResult().getType();
290 globalOp = memref::GlobalOp::create(
291 builder, loc, StringAttr::get(ctx, globalName),
292 StringAttr::get(ctx,
"private"), TypeAttr::get(resultType),
Attribute{},
293 UnitAttr{}, allocLikeOp.getAlignmentAttr());
294 symbolTable.
insert(globalOp);
303 for (
Operation *user : llvm::make_early_inc_range(allocLikeOp->getUsers())) {
304 if (
auto dealloc = dyn_cast<memref::DeallocOp>(user))
312 allocLikeOp, globalOp.getType(), globalOp.getName());
331 for (
auto *op : allocaOps) {
332 auto alloca = cast<memref::AllocaOp>(op);
333 memref::GlobalOp globalOp;
334 memref::GetGlobalOp getGlobalOp;
337 if (!
diag.succeeded())
340 globalOps.push_back(globalOp);
341 getGlobalOps.push_back(getGlobalOp);
345 results.
set(cast<OpResult>(getGlobal()), globalOps);
346 results.
set(cast<OpResult>(getGetGlobal()), getGlobalOps);
351void transform::MemRefAllocaToGlobalOp::getEffects(
372 for (
auto *op : allocOps) {
373 auto alloc = cast<memref::AllocOp>(op);
374 memref::GlobalOp globalOp;
375 memref::GetGlobalOp getGlobalOp;
378 if (!
diag.succeeded())
381 globalOps.push_back(globalOp);
382 getGlobalOps.push_back(getGlobalOp);
386 results.
set(cast<OpResult>(getGlobal()), globalOps);
387 results.
set(cast<OpResult>(getGetGlobal()), getGlobalOps);
392void transform::MemRefAllocToGlobalOp::getEffects(
409 bool canApplyMultiBuffer =
true;
410 auto target = cast<memref::AllocOp>(op);
411 LLVM_DEBUG(
DBGS() <<
"Start multibuffer transform op: " <<
target <<
"\n";);
414 if (isa<memref::DeallocOp>(user))
416 auto loop = user->getParentOfType<LoopLikeOpInterface>();
418 LLVM_DEBUG(
DBGS() <<
"--allocation not used in a loop\n";
419 DBGS() <<
"----due to user: " << *user;);
420 canApplyMultiBuffer =
false;
424 if (!canApplyMultiBuffer) {
425 LLVM_DEBUG(
DBGS() <<
"--cannot apply multibuffering -> Skip\n";);
433 LLVM_DEBUG(
DBGS() <<
"--op failed to multibuffer\n";);
435 <<
"op failed to multibuffer";
438 results.push_back(*newBuffer);
440 transformResults.
set(cast<OpResult>(getResult()), results);
449transform::MemRefEraseDeadAllocAndStoresOp::applyToOne(
454 vector::transferOpflowOpt(rewriter,
target);
459void transform::MemRefEraseDeadAllocAndStoresOp::getEffects(
464void transform::MemRefEraseDeadAllocAndStoresOp::build(
OpBuilder &builder,
481 for (uint64_t i = 0, e = getNumLoops(); i < e; ++i) {
485 <<
"could not find " << i
486 <<
"-th enclosing loop";
487 diag.attachNote(
target->getLoc()) <<
"target op";
490 ivs.push_back(cast<scf::ForOp>(nextOp).getInductionVar());
495 if (
auto allocaOp = dyn_cast<memref::AllocaOp>(
target)) {
499 <<
"unsupported target op";
500 diag.attachNote(
target->getLoc()) <<
"target op";
505 emitSilenceableError() <<
"could not make target op loop-independent";
506 diag.attachNote(
target->getLoc()) <<
"target op";
518class MemRefTransformDialectExtension
520 MemRefTransformDialectExtension> {
527 declareGeneratedDialect<affine::AffineDialect>();
528 declareGeneratedDialect<arith::ArithDialect>();
529 declareGeneratedDialect<memref::MemRefDialect>();
530 declareGeneratedDialect<nvgpu::NVGPUDialect>();
531 declareGeneratedDialect<vector::VectorDialect>();
533 registerTransformOps<
535#include "mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp.inc"
541#define GET_OP_CLASSES
542#include "mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp.inc"
static uint64_t getIndexBitwidth(DataLayoutEntryListRef params)
Returns the bitwidth of the index type if specified in the param list.
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static std::string diag(const llvm::Value &value)
static llvm::ManagedStatic< PassManagerOptions > options
#define MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CLASS_NAME)
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
Attributes are known-constant values of operations.
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
MLIRContext * getContext() const
llvm::TypeSize getTypeSize(Type t) const
Returns the size of the given type in the current scope.
The result of a transform IR operation application.
static DiagnosedSilenceableFailure success()
Constructs a DiagnosedSilenceableFailure in the success state.
bool succeeded() const
Returns true if this is a success.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
void addExtensions()
Add the given extensions to the registry.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Options to control the LLVM lowering.
@ Malloc
Use malloc for heap allocations.
@ AlignedAlloc
Use aligned_alloc for heap allocations.
MLIRContext is the top-level object for a collection of MLIR operations.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
This class helps build Operations.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Operation is the basic unit of execution within MLIR.
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
RewritePatternSet & insert(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class allows for representing and managing the symbol table used by operations with the 'SymbolT...
StringAttr insert(Operation *symbol, Block::iterator insertPt={})
Insert a new symbol into the table, and rename it as necessary to avoid collisions.
static Operation * getNearestSymbolTable(Operation *from)
Returns the nearest symbol table from a given operation from.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Base class for extensions of the Transform dialect that supports injecting operations into the Transf...
std::optional< DataLayout > getDataLayout(Operation *op, bool allowDefault=true)
Get the data layout for an operation.
void populateFoldMemRefAliasOpPatterns(RewritePatternSet &patterns)
Appends patterns for folding memref aliasing ops into consumer load/store ops into patterns.
void populateResolveRankedShapedTypeResultDimsPatterns(RewritePatternSet &patterns)
Appends patterns that resolve memref.dim operations with values that are defined by operations that i...
FailureOr< Value > replaceWithIndependentOp(RewriterBase &rewriter, memref::AllocaOp allocaOp, ValueRange independencies)
Build a new memref::AllocaOp whose dynamic sizes are independent of all given independencies.
void eraseDeadAllocAndStores(RewriterBase &rewriter, Operation *parentOp)
Track temporary allocations that are never read from.
FailureOr< memref::AllocOp > multiBuffer(RewriterBase &rewriter, memref::AllocOp allocOp, unsigned multiplier, bool skipOverrideAnalysis=false)
Transformation to do multi-buffering/array expansion to remove dependencies on the temporary allocati...
void populateExpandOpsPatterns(RewritePatternSet &patterns)
Collects a set of patterns to rewrite ops within the memref dialect.
void populateExtractAddressComputationsPatterns(RewritePatternSet &patterns)
Appends patterns for extracting address computations from memory access operations such that these ac...
memref::AllocaOp allocToAlloca(RewriterBase &rewriter, memref::AllocOp alloc, function_ref< bool(memref::AllocOp, memref::DeallocOp)> filter=nullptr)
Replaces the given alloc with the corresponding alloca and returns it if the following conditions are...
void populateExpandStridedMetadataPatterns(RewritePatternSet &patterns)
Appends patterns for expanding memref operations that modify the metadata (sizes, offset,...
void registerTransformDialectExtension(DialectRegistry ®istry)
Include the generated interface declarations.
static constexpr unsigned kDeriveIndexBitwidthFromDataLayout
Value to pass as bitwidth for the index type when the converter is expected to derive the bitwidth fr...
DiagnosedSilenceableFailure emitSilenceableFailure(Location loc, const Twine &message={})
Emits a silenceable failure with the given message.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
This represents an operation in an abstracted form, suitable for use with the builder APIs.