-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[mlir][memref] Introduce memref.distinct_objects op
#156913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -153,7 +153,7 @@ def AssumeAlignmentOp : MemRef_Op<"assume_alignment", [ | |
| The `assume_alignment` operation takes a memref and an integer alignment | ||
| value. It returns a new SSA value of the same memref type, but associated | ||
| with the assumption that the underlying buffer is aligned to the given | ||
| alignment. | ||
| alignment. | ||
|
|
||
| If the buffer isn't aligned to the given alignment, its result is poison. | ||
| This operation doesn't affect the semantics of a program where the | ||
|
|
@@ -168,14 +168,49 @@ def AssumeAlignmentOp : MemRef_Op<"assume_alignment", [ | |
| let assemblyFormat = "$memref `,` $alignment attr-dict `:` type($memref)"; | ||
| let extraClassDeclaration = [{ | ||
| MemRefType getType() { return ::llvm::cast<MemRefType>(getResult().getType()); } | ||
|
|
||
| Value getViewSource() { return getMemref(); } | ||
| }]; | ||
|
|
||
| let hasVerifier = 1; | ||
| let hasFolder = 1; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // DistinctObjectsOp | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def DistinctObjectsOp : MemRef_Op<"distinct_objects", [ | ||
| Pure, | ||
| DeclareOpInterfaceMethods<InferTypeOpInterface> | ||
| // ViewLikeOpInterface TODO: ViewLikeOpInterface only supports a single argument | ||
| ]> { | ||
| let summary = "assumption that acesses to specific memrefs will never alias"; | ||
| let description = [{ | ||
| The `distinct_objects` operation takes a list of memrefs and returns a list of | ||
| memrefs of the same types, with the additional assumption that accesses to | ||
| these memrefs will never alias with each other. This means that loads and | ||
| stores to different memrefs in the list can be safely reordered. | ||
|
|
||
| If the memrefs do alias, the behavior is undefined. This operation doesn't | ||
|
||
| affect the semantics of a program where the non-aliasing assumption holds | ||
|
||
| true. It is intended for optimization purposes, allowing the compiler to | ||
| generate more efficient code based on the non-aliasing assumption. The | ||
| optimization is best-effort. | ||
|
|
||
| Example: | ||
|
|
||
| ```mlir | ||
| %1, %2 = memref.distinct_objects %a, %b : memref<?xf32>, memref<?xf32> | ||
| ``` | ||
| }]; | ||
| let arguments = (ins Variadic<AnyMemRef>:$operands); | ||
| let results = (outs Variadic<AnyMemRef>:$results); | ||
|
|
||
| let assemblyFormat = "$operands attr-dict `:` type($operands)"; | ||
| let hasVerifier = 1; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // AllocOp | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -465,6 +465,48 @@ struct AssumeAlignmentOpLowering | |
| } | ||
| }; | ||
|
|
||
| struct DistinctObjectsOpLowering | ||
| : public ConvertOpToLLVMPattern<memref::DistinctObjectsOp> { | ||
| using ConvertOpToLLVMPattern< | ||
| memref::DistinctObjectsOp>::ConvertOpToLLVMPattern; | ||
| explicit DistinctObjectsOpLowering(const LLVMTypeConverter &converter) | ||
| : ConvertOpToLLVMPattern<memref::DistinctObjectsOp>(converter) {} | ||
|
|
||
| LogicalResult | ||
| matchAndRewrite(memref::DistinctObjectsOp op, OpAdaptor adaptor, | ||
| ConversionPatternRewriter &rewriter) const override { | ||
| ValueRange operands = adaptor.getOperands(); | ||
| if (operands.empty()) { | ||
| rewriter.eraseOp(op); | ||
|
||
| return success(); | ||
| } | ||
| Location loc = op.getLoc(); | ||
| SmallVector<Value> ptrs; | ||
| for (auto [origOperand, newOperand] : | ||
| llvm::zip_equal(op.getOperands(), operands)) { | ||
| auto memrefType = cast<MemRefType>(origOperand.getType()); | ||
| Value ptr = getStridedElementPtr(rewriter, loc, memrefType, newOperand, | ||
|
||
| /*indices=*/{}); | ||
| ptrs.push_back(ptr); | ||
| } | ||
|
|
||
| auto cond = | ||
| LLVM::ConstantOp::create(rewriter, loc, rewriter.getI1Type(), 1); | ||
| // Generate separate_storage assumptions for each pair of pointers. | ||
| for (auto i : llvm::seq<size_t>(ptrs.size() - 1)) { | ||
| for (auto j : llvm::seq<size_t>(i + 1, ptrs.size())) { | ||
| Value ptr1 = ptrs[i]; | ||
| Value ptr2 = ptrs[j]; | ||
| LLVM::AssumeOp::create(rewriter, loc, cond, | ||
| LLVM::AssumeSeparateStorageTag{}, ptr1, ptr2); | ||
| } | ||
| } | ||
|
|
||
| rewriter.replaceOp(op, operands); | ||
| return success(); | ||
| } | ||
| }; | ||
|
|
||
| // A `dealloc` is converted into a call to `free` on the underlying data buffer. | ||
| // The memref descriptor being an SSA value, there is no need to clean it up | ||
| // in any way. | ||
|
|
@@ -1997,22 +2039,23 @@ void mlir::populateFinalizeMemRefToLLVMConversionPatterns( | |
| patterns.add< | ||
| AllocaOpLowering, | ||
| AllocaScopeOpLowering, | ||
| AtomicRMWOpLowering, | ||
| AssumeAlignmentOpLowering, | ||
| AtomicRMWOpLowering, | ||
| ConvertExtractAlignedPointerAsIndex, | ||
| DimOpLowering, | ||
| DistinctObjectsOpLowering, | ||
| ExtractStridedMetadataOpLowering, | ||
| GenericAtomicRMWOpLowering, | ||
| GetGlobalMemrefOpLowering, | ||
| LoadOpLowering, | ||
| MemRefCastOpLowering, | ||
| MemorySpaceCastOpLowering, | ||
| MemRefReinterpretCastOpLowering, | ||
| MemRefReshapeOpLowering, | ||
| MemorySpaceCastOpLowering, | ||
| PrefetchOpLowering, | ||
| RankOpLowering, | ||
| ReassociatingReshapeOpConversion<memref::ExpandShapeOp>, | ||
| ReassociatingReshapeOpConversion<memref::CollapseShapeOp>, | ||
| ReassociatingReshapeOpConversion<memref::ExpandShapeOp>, | ||
| StoreOpLowering, | ||
| SubViewOpLowering, | ||
| TransposeOpLowering, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -542,6 +542,25 @@ OpFoldResult AssumeAlignmentOp::fold(FoldAdaptor adaptor) { | |
| return getMemref(); | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // DistinctObjectsOp | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| LogicalResult DistinctObjectsOp::verify() { | ||
| if (getOperandTypes() != getResultTypes()) | ||
| return emitOpError("operand types and result types must match"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Should be implementable with the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have a variadic number of inputs/results and we need their types to match pairwise. I didn't quite figured how to express it using existing constraints.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I missed that they are variadics! Makes sense.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a test though? It a custom verifier, so we should test it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added a test |
||
| return success(); | ||
| } | ||
|
|
||
| LogicalResult DistinctObjectsOp::inferReturnTypes( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be done with
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know how to express it using existing constraints, see my prev comment on
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could probably add a constraint - something like EachTypeMatches<"src", "res"> - and possibly use it to do return type inference But that's a separate PR |
||
| MLIRContext * /*context*/, std::optional<Location> /*location*/, | ||
| ValueRange operands, DictionaryAttr /*attributes*/, | ||
| OpaqueProperties /*properties*/, RegionRange /*regions*/, | ||
| SmallVectorImpl<Type> &inferredReturnTypes) { | ||
| llvm::copy(operands.getTypes(), std::back_inserter(inferredReturnTypes)); | ||
| return success(); | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // CastOp | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe phrase as "returns the same memrefs, with the additional assumption..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to rephrase the doc.