MLIR 24.0.0git
MemRefTransformOps.cpp
Go to the documentation of this file.
1//===- MemRefTransformOps.cpp - Implementation of Memref transform ops ----===//
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
10
27#include "llvm/Support/Debug.h"
28
29using namespace mlir;
30
31#define DEBUG_TYPE "memref-transforms"
32#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
33
34namespace mlir::transform {
35namespace {
36ParseResult parseLLVMTypeConverterOptions(OpAsmParser &parser,
37 BoolAttr &useAlignedAlloc,
38 IntegerAttr &indexBitwidth,
39 BoolAttr &useGenericFunctions,
40 BoolAttr &useBarePtrCallConv,
41 StringAttr &dataLayout) {
42 bool seenUseAlignedAlloc = false;
43 bool seenIndexBitwidth = false;
44 bool seenUseGenericFunctions = false;
45 bool seenUseBarePtrCallConv = false;
46 bool seenDataLayout = false;
47
48 auto parseDuplicate = [&](StringRef name, bool &seen) -> ParseResult {
49 if (seen)
50 return parser.emitError(parser.getCurrentLocation())
51 << "duplicate '" << name << "' option";
52 seen = true;
53 return ParseResult::success();
54 };
55
56 while (true) {
57 if (succeeded(parser.parseOptionalKeyword("use_aligned_alloc"))) {
58 if (failed(parseDuplicate("use_aligned_alloc", seenUseAlignedAlloc)) ||
59 parser.parseEqual() ||
60 parser.parseAttribute(useAlignedAlloc,
61 parser.getBuilder().getI1Type()))
62 return failure();
63 continue;
64 }
65 if (succeeded(parser.parseOptionalKeyword("index_bitwidth"))) {
66 if (failed(parseDuplicate("index_bitwidth", seenIndexBitwidth)) ||
67 parser.parseEqual() ||
68 parser.parseAttribute(indexBitwidth,
69 parser.getBuilder().getI64Type()))
70 return failure();
71 continue;
72 }
73 if (succeeded(parser.parseOptionalKeyword("use_generic_functions"))) {
74 if (failed(parseDuplicate("use_generic_functions",
75 seenUseGenericFunctions)) ||
76 parser.parseEqual() ||
77 parser.parseAttribute(useGenericFunctions,
78 parser.getBuilder().getI1Type()))
79 return failure();
80 continue;
81 }
82 if (succeeded(parser.parseOptionalKeyword("use_bare_ptr_call_conv"))) {
83 if (failed(parseDuplicate("use_bare_ptr_call_conv",
84 seenUseBarePtrCallConv)) ||
85 parser.parseEqual() ||
86 parser.parseAttribute(useBarePtrCallConv,
87 parser.getBuilder().getI1Type()))
88 return failure();
89 continue;
90 }
91 if (succeeded(parser.parseOptionalKeyword("data_layout"))) {
92 if (failed(parseDuplicate("data_layout", seenDataLayout)) ||
93 parser.parseEqual() || parser.parseAttribute(dataLayout))
94 return failure();
95 continue;
96 }
97 break;
98 }
99 return success();
100}
101
102void printLLVMTypeConverterOptions(OpAsmPrinter &printer, Operation *,
103 BoolAttr useAlignedAlloc,
104 IntegerAttr indexBitwidth,
105 BoolAttr useGenericFunctions,
106 BoolAttr useBarePtrCallConv,
107 StringAttr dataLayout) {
108 bool needsSpace = false;
109 auto printOption = [&](StringRef name, Attribute value) {
110 if (!value)
111 return;
112 if (needsSpace)
113 printer << ' ';
114 printer << name << " = ";
115 printer.printAttributeWithoutType(value);
116 needsSpace = true;
117 };
118
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);
124}
125} // namespace
126} // namespace mlir::transform
127
128//===----------------------------------------------------------------------===//
129// Apply...ConversionPatternsOp
130//===----------------------------------------------------------------------===//
131
132std::unique_ptr<TypeConverter>
133transform::MemrefToLLVMTypeConverterOp::getTypeConverter() {
135 options.allocLowering =
138 options.useGenericFunctions = getUseGenericFunctions();
139
141 options.overrideIndexBitwidth(getIndexBitwidth());
142
143 // TODO: the following two options don't really make sense for
144 // memref_to_llvm_type_converter specifically but we should have a single
145 // to_llvm_type_converter.
146 if (getDataLayout().has_value())
147 options.dataLayout = llvm::DataLayout(getDataLayout().value());
148 options.useBarePtrCallConv = getUseBarePtrCallConv();
149
150 return std::make_unique<LLVMTypeConverter>(getContext(), options);
151}
152
153StringRef transform::MemrefToLLVMTypeConverterOp::getTypeConverterType() {
154 return "LLVMTypeConverter";
155}
156
157//===----------------------------------------------------------------------===//
158// Apply...PatternsOp
159//===----------------------------------------------------------------------===//
160
161namespace {
162class AllocToAllocaPattern : public OpRewritePattern<memref::AllocOp> {
163public:
164 explicit AllocToAllocaPattern(Operation *analysisRoot, int64_t maxSize = 0)
165 : OpRewritePattern<memref::AllocOp>(analysisRoot->getContext()),
166 dataLayoutAnalysis(analysisRoot), maxSize(maxSize) {}
167
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())
174 return false;
175
176 const DataLayout &dataLayout = dataLayoutAnalysis.getAtOrAbove(alloc);
177 int64_t elementSize = dataLayout.getTypeSize(type.getElementType());
178 return maxSize == 0 || type.getNumElements() * elementSize < maxSize;
179 }));
180 }
181
182private:
183 DataLayoutAnalysis dataLayoutAnalysis;
184 int64_t maxSize;
185};
186} // namespace
187
188void transform::ApplyAllocToAllocaOp::populatePatterns(
189 RewritePatternSet &patterns) {}
190
191void transform::ApplyAllocToAllocaOp::populatePatternsWithState(
193 patterns.insert<AllocToAllocaPattern>(
194 state.getTopLevel(), static_cast<int64_t>(getSizeLimit().value_or(0)));
195}
196
197void transform::ApplyExpandOpsPatternsOp::populatePatterns(
198 RewritePatternSet &patterns) {
200}
201
202void transform::ApplyExpandStridedMetadataPatternsOp::populatePatterns(
203 RewritePatternSet &patterns) {
205}
206
207void transform::ApplyExtractAddressComputationsPatternsOp::populatePatterns(
208 RewritePatternSet &patterns) {
210}
211
212void transform::ApplyFoldMemrefAliasOpsPatternsOp::populatePatterns(
213 RewritePatternSet &patterns) {
215}
216
217void transform::ApplyResolveRankedShapedTypeResultDimsPatternsOp::
218 populatePatterns(RewritePatternSet &patterns) {
220}
221
222//===----------------------------------------------------------------------===//
223// Alloc and alloca to global utilities
224//===----------------------------------------------------------------------===//
225
226/// Checks whether an allocation operation can be converted to a
227/// `memref.global`.
228template <typename AllocLikeOp>
230checkAllocToGlobalPreconditions(AllocLikeOp allocLikeOp) {
231 MemRefType memrefType = allocLikeOp.getType();
232 if (!memrefType.hasStaticShape()) {
233 return emitSilenceableFailure(allocLikeOp)
234 << "conversion to a global op requires statically shaped memrefs, "
235 "but got "
236 << memrefType;
237 }
238
239 if (!allocLikeOp.getSymbolOperands().empty()) {
240 return emitSilenceableFailure(allocLikeOp)
241 << "conversion to a global op does not support symbol operands, but "
242 "got "
243 << memrefType;
244 }
245
246 int64_t offset;
248 if (failed(memrefType.getStridesAndOffset(strides, offset))) {
249 return emitSilenceableFailure(allocLikeOp)
250 << "conversion to a global op requires strided layout, but got "
251 << memrefType;
252 }
253 if (!ShapedType::isStatic(offset) || !ShapedType::isStaticShape(strides)) {
254 return emitSilenceableFailure(allocLikeOp)
255 << "conversion to a global op does not support dynamic offset or "
256 "strides, but got "
257 << memrefType;
258 }
259
261}
262
263/// Converts an allocation operation (`memref.alloca` or `memref.alloc`) to a
264/// `memref.global` operation in the nearest symbol table, and replaces the
265/// allocation with a `memref.get_global` operation. Any `memref.dealloc`
266/// operations referencing the allocation are erased.
267template <typename AllocLikeOp>
270 AllocLikeOp allocLikeOp, StringRef globalName,
271 memref::GlobalOp &globalOp,
272 memref::GetGlobalOp &getGlobalOp) {
273 if (DiagnosedSilenceableFailure failure =
275 !failure.succeeded())
276 return failure;
277
278 MLIRContext *ctx = rewriter.getContext();
279 Location loc = allocLikeOp->getLoc();
280
281 // Find nearest symbol table.
282 Operation *symbolTableOp = SymbolTable::getNearestSymbolTable(allocLikeOp);
283 assert(symbolTableOp && "expected payload to be in symbol table");
284 SymbolTable symbolTable(symbolTableOp);
285
286 // Insert a `memref.global` into the symbol table.
287 Type resultType = allocLikeOp.getResult().getType();
288 OpBuilder builder(rewriter.getContext());
289 // TODO: Add a better builder for this.
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);
295
296 // Remove any `memref.dealloc` operations referencing this allocation.
297 // We assume that the allocation does not escape the current container
298 // (e.g., via return or interprocedural function calls) and is not passed
299 // through control-flow or alias operations (e.g., `scf.if`, `cf.cond_br`,
300 // `select`, `memref.subview`), so any deallocation is a direct user of the
301 // allocation. Indirect deallocations are not removed and must be handled
302 // separately.
303 for (Operation *user : llvm::make_early_inc_range(allocLikeOp->getUsers())) {
304 if (auto dealloc = dyn_cast<memref::DeallocOp>(user))
305 rewriter.eraseOp(dealloc);
306 }
307
308 // Replace the allocation with a `memref.get_global` accessing the
309 // global symbol inserted above.
310 rewriter.setInsertionPoint(allocLikeOp);
311 getGlobalOp = rewriter.replaceOpWithNewOp<memref::GetGlobalOp>(
312 allocLikeOp, globalOp.getType(), globalOp.getName());
313
315}
316
317//===----------------------------------------------------------------------===//
318// AllocaToGlobalOp
319//===----------------------------------------------------------------------===//
320
322transform::MemRefAllocaToGlobalOp::apply(transform::TransformRewriter &rewriter,
325 auto allocaOps = state.getPayloadOps(getAlloca());
326
329
330 // Transform `memref.alloca`s.
331 for (auto *op : allocaOps) {
332 auto alloca = cast<memref::AllocaOp>(op);
333 memref::GlobalOp globalOp;
334 memref::GetGlobalOp getGlobalOp;
336 allocLikeToGlobal(rewriter, alloca, "alloca", globalOp, getGlobalOp);
337 if (!diag.succeeded())
338 return diag;
339
340 globalOps.push_back(globalOp);
341 getGlobalOps.push_back(getGlobalOp);
342 }
343
344 // Assemble results.
345 results.set(cast<OpResult>(getGlobal()), globalOps);
346 results.set(cast<OpResult>(getGetGlobal()), getGlobalOps);
347
349}
350
351void transform::MemRefAllocaToGlobalOp::getEffects(
353 producesHandle(getOperation()->getOpResults(), effects);
354 consumesHandle(getAllocaMutable(), effects);
355 modifiesPayload(effects);
356}
357
358//===----------------------------------------------------------------------===//
359// AllocToGlobalOp
360//===----------------------------------------------------------------------===//
361
363transform::MemRefAllocToGlobalOp::apply(transform::TransformRewriter &rewriter,
366 auto allocOps = state.getPayloadOps(getAlloc());
367
370
371 // Transform `memref.alloc`s.
372 for (auto *op : allocOps) {
373 auto alloc = cast<memref::AllocOp>(op);
374 memref::GlobalOp globalOp;
375 memref::GetGlobalOp getGlobalOp;
377 allocLikeToGlobal(rewriter, alloc, "alloc", globalOp, getGlobalOp);
378 if (!diag.succeeded())
379 return diag;
380
381 globalOps.push_back(globalOp);
382 getGlobalOps.push_back(getGlobalOp);
383 }
384
385 // Assemble results.
386 results.set(cast<OpResult>(getGlobal()), globalOps);
387 results.set(cast<OpResult>(getGetGlobal()), getGlobalOps);
388
390}
391
392void transform::MemRefAllocToGlobalOp::getEffects(
394 producesHandle(getOperation()->getOpResults(), effects);
395 consumesHandle(getAllocMutable(), effects);
396 modifiesPayload(effects);
397}
398
399//===----------------------------------------------------------------------===//
400// MemRefMultiBufferOp
401//===----------------------------------------------------------------------===//
402
403DiagnosedSilenceableFailure transform::MemRefMultiBufferOp::apply(
405 transform::TransformResults &transformResults,
408 for (Operation *op : state.getPayloadOps(getTarget())) {
409 bool canApplyMultiBuffer = true;
410 auto target = cast<memref::AllocOp>(op);
411 LLVM_DEBUG(DBGS() << "Start multibuffer transform op: " << target << "\n";);
412 // Skip allocations not used in a loop.
413 for (Operation *user : target->getUsers()) {
414 if (isa<memref::DeallocOp>(user))
415 continue;
416 auto loop = user->getParentOfType<LoopLikeOpInterface>();
417 if (!loop) {
418 LLVM_DEBUG(DBGS() << "--allocation not used in a loop\n";
419 DBGS() << "----due to user: " << *user;);
420 canApplyMultiBuffer = false;
421 break;
422 }
423 }
424 if (!canApplyMultiBuffer) {
425 LLVM_DEBUG(DBGS() << "--cannot apply multibuffering -> Skip\n";);
426 continue;
427 }
428
429 auto newBuffer =
430 memref::multiBuffer(rewriter, target, getFactor(), getSkipAnalysis());
431
432 if (failed(newBuffer)) {
433 LLVM_DEBUG(DBGS() << "--op failed to multibuffer\n";);
434 return emitSilenceableFailure(target->getLoc())
435 << "op failed to multibuffer";
436 }
437
438 results.push_back(*newBuffer);
439 }
440 transformResults.set(cast<OpResult>(getResult()), results);
442}
443
444//===----------------------------------------------------------------------===//
445// MemRefEraseDeadAllocAndStoresOp
446//===----------------------------------------------------------------------===//
447
449transform::MemRefEraseDeadAllocAndStoresOp::applyToOne(
453 // Apply store to load forwarding and dead store elimination.
454 vector::transferOpflowOpt(rewriter, target);
457}
458
459void transform::MemRefEraseDeadAllocAndStoresOp::getEffects(
461 transform::onlyReadsHandle(getTargetMutable(), effects);
463}
464void transform::MemRefEraseDeadAllocAndStoresOp::build(OpBuilder &builder,
466 Value target) {
467 result.addOperands(target);
468}
469
470//===----------------------------------------------------------------------===//
471// MemRefMakeLoopIndependentOp
472//===----------------------------------------------------------------------===//
473
474DiagnosedSilenceableFailure transform::MemRefMakeLoopIndependentOp::applyToOne(
478 // Gather IVs.
480 Operation *nextOp = target;
481 for (uint64_t i = 0, e = getNumLoops(); i < e; ++i) {
482 nextOp = nextOp->getParentOfType<scf::ForOp>();
483 if (!nextOp) {
484 DiagnosedSilenceableFailure diag = emitSilenceableError()
485 << "could not find " << i
486 << "-th enclosing loop";
487 diag.attachNote(target->getLoc()) << "target op";
488 return diag;
489 }
490 ivs.push_back(cast<scf::ForOp>(nextOp).getInductionVar());
491 }
492
493 // Rewrite IR.
494 FailureOr<Value> replacement = failure();
495 if (auto allocaOp = dyn_cast<memref::AllocaOp>(target)) {
496 replacement = memref::replaceWithIndependentOp(rewriter, allocaOp, ivs);
497 } else {
498 DiagnosedSilenceableFailure diag = emitSilenceableError()
499 << "unsupported target op";
500 diag.attachNote(target->getLoc()) << "target op";
501 return diag;
502 }
503 if (failed(replacement)) {
505 emitSilenceableError() << "could not make target op loop-independent";
506 diag.attachNote(target->getLoc()) << "target op";
507 return diag;
508 }
509 results.push_back(replacement->getDefiningOp());
511}
512
513//===----------------------------------------------------------------------===//
514// Transform op registration
515//===----------------------------------------------------------------------===//
516
517namespace {
518class MemRefTransformDialectExtension
520 MemRefTransformDialectExtension> {
521public:
522 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(MemRefTransformDialectExtension)
523
524 using Base::Base;
525
526 void init() {
527 declareGeneratedDialect<affine::AffineDialect>();
528 declareGeneratedDialect<arith::ArithDialect>();
529 declareGeneratedDialect<memref::MemRefDialect>();
530 declareGeneratedDialect<nvgpu::NVGPUDialect>();
531 declareGeneratedDialect<vector::VectorDialect>();
532
533 registerTransformOps<
534#define GET_OP_LIST
535#include "mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp.inc"
536 >();
537 }
538};
539} // namespace
540
541#define GET_OP_CLASSES
542#include "mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp.inc"
543
545 DialectRegistry &registry) {
546 registry.addExtensions<MemRefTransformDialectExtension>();
547}
return success()
static uint64_t getIndexBitwidth(DataLayoutEntryListRef params)
Returns the bitwidth of the index type if specified in the param list.
b getContext())
*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 DiagnosedSilenceableFailure checkAllocToGlobalPreconditions(AllocLikeOp allocLikeOp)
Checks whether an allocation operation can be converted to a memref.global.
static DiagnosedSilenceableFailure allocLikeToGlobal(transform::TransformRewriter &rewriter, AllocLikeOp allocLikeOp, StringRef globalName, memref::GlobalOp &globalOp, memref::GetGlobalOp &getGlobalOp)
Converts an allocation operation (memref.alloca or memref.alloc) to a memref.global operation in the ...
#define DBGS()
static std::string diag(const llvm::Value &value)
static llvm::ManagedStatic< PassManagerOptions > options
#define MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CLASS_NAME)
Definition TypeID.h:331
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.
Definition Attributes.h:25
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
IntegerType getI64Type()
Definition Builders.cpp:73
IntegerType getI1Type()
Definition Builders.cpp:61
MLIRContext * getContext() const
Definition Builders.h:56
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...
Definition Location.h:76
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.
Definition MLIRContext.h:63
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.
Definition Builders.h:210
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition Builders.h:401
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
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...
Definition SymbolTable.h:24
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...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
A list of results of applying a transform op with ApplyEachOpTrait to a single payload operation,...
void push_back(Operation *op)
Appends an element to the list.
Base class for extensions of the Transform dialect that supports injecting operations into the Transf...
Local mapping between values defined by a specific op implementing the TransformOpInterface and the p...
void set(OpResult value, Range &&ops)
Indicates that the result of the transform IR op at the given position corresponds to the given list ...
This is a special rewriter to be used in transform op implementations, providing additional helper fu...
The state maintained across applications of various ops implementing the TransformOpInterface.
auto getPayloadOps(Value value) const
Returns an iterator that enumerates all ops that the given transform IR value corresponds to.
Operation * getTopLevel() const
Returns the op at which the transformation state is rooted.
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 &registry)
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
void producesHandle(ResultRange handles, SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
void consumesHandle(MutableArrayRef< OpOperand > handles, SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
Populates effects with the memory effects indicating the operation on the given handle value:
void onlyReadsHandle(MutableArrayRef< OpOperand > handles, SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
void modifiesPayload(SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
Populates effects with the memory effects indicating the access to payload IR resource.
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.