Skip to content

Commit 166cda3

Browse files
authored
[DT] Implement MaterializeInterfaceBindingEncoding with interface methods. (#22467)
The revision implements `LayoutMaterializerAttr::convertType` for GPUPaddingResolverAttr; updates the `MaterializeInterfaceBindingEncoding` pattern to use interface methods to materialize the bindings. It also fixes a bug in `@dynamic_set_zero_pad_encoding_and_store` test that misses dynamic dimensions in binding ops. It is a step towards #20160 --------- Signed-off-by: hanhanW <[email protected]>
1 parent a348c0a commit 166cda3

File tree

5 files changed

+117
-190
lines changed

5 files changed

+117
-190
lines changed

compiler/src/iree/compiler/Codegen/Common/EncodingUtils.cpp

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,11 @@ MaterializeEncodingTypeConverter::MaterializeEncodingTypeConverter(
2525
addConversion([](FloatType floatType) { return floatType; });
2626
addConversion([](MemRefType memrefType) { return memrefType; });
2727
addConversion([=](RankedTensorType type) {
28-
// TODO(jornt): The isa<IREE::Encoding::PaddingAttr> check is
29-
// needed because PaddingAttr is a serializable attribute, but it
30-
// relies on its own type conversion for now. Once PaddingAttr
31-
// implements `convertType`, this can be removed.
32-
if (!isa<IREE::Encoding::PaddingAttr>(getLayoutAttr())) {
33-
return cast<RankedTensorType>(getLayoutAttr().convertType(type));
34-
}
35-
return type.dropEncoding();
28+
return cast<RankedTensorType>(getLayoutAttr().convertType(type));
3629
});
3730
addConversion([&](IREE::TensorExt::DispatchTensorType dispatchTensorType) {
38-
auto boundType =
39-
dyn_cast<RankedTensorType>(dispatchTensorType.getBoundType());
40-
if (!boundType || !boundType.getEncoding()) {
41-
return dispatchTensorType;
42-
}
43-
// TODO(jornt): The isa<IREE::Encoding::PaddingAttr> check is
44-
// needed because PaddingAttr is a serializable attribute, but it
45-
// relies on its own type conversion for now. Once PaddingAttr
46-
// implements `convertType`, this can be removed.
47-
if (!isa<IREE::Encoding::PaddingAttr>(getLayoutAttr())) {
48-
return cast<IREE::TensorExt::DispatchTensorType>(
49-
getLayoutAttr().convertType(dispatchTensorType));
50-
}
51-
Type convertedBoundType = convertType(boundType);
52-
return IREE::TensorExt::DispatchTensorType::get(
53-
dispatchTensorType.getAccess(), convertedBoundType);
31+
return cast<IREE::TensorExt::DispatchTensorType>(
32+
getLayoutAttr().convertType(dispatchTensorType));
5433
});
5534
}
5635

compiler/src/iree/compiler/Codegen/Common/MaterializeEncodingIntoPadding.cpp

Lines changed: 1 addition & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -36,116 +36,6 @@ namespace mlir::iree_compiler {
3636
using namespace IREE::Encoding;
3737

3838
namespace {
39-
40-
// Returns the pad encoding layout, or nullptr if this is not the only layout or
41-
// if there's no encoding at all.
42-
static PaddingAttr getPadLayout(Attribute layoutAttr, RankedTensorType type) {
43-
if (!type.getEncoding()) {
44-
return nullptr;
45-
}
46-
auto encoding =
47-
dyn_cast_or_null<IREE::Encoding::LayoutAttr>(type.getEncoding());
48-
if (encoding) {
49-
ArrayAttr layouts = encoding.getLayouts();
50-
if (layouts.size() != 1) {
51-
return nullptr;
52-
}
53-
return dyn_cast<PaddingAttr>(*layouts.begin());
54-
}
55-
Attribute resolvedEncoding =
56-
cast<IREE::Encoding::LayoutResolverAttr>(layoutAttr).getLayout(type);
57-
LLVM_DEBUG({
58-
llvm::dbgs() << "Unresolved type: " << type << "\n";
59-
llvm::dbgs() << "layoutAttr: " << layoutAttr << "\n";
60-
llvm::dbgs() << "Resolved into: " << resolvedEncoding << "\n";
61-
});
62-
return dyn_cast<PaddingAttr>(resolvedEncoding);
63-
}
64-
65-
// Returns a padded tensor type (without encoding) for tensor types with the pad
66-
// encoding layout, or the same type for all other tensors.
67-
static RankedTensorType getPaddedType(Attribute layoutAttr,
68-
RankedTensorType type) {
69-
PaddingAttr layout = getPadLayout(layoutAttr, type);
70-
if (layout.isIdentityLayout()) {
71-
return type.dropEncoding();
72-
}
73-
74-
ArrayRef<int64_t> padding = layout.getPadding().asArrayRef();
75-
auto newShape = llvm::to_vector_of<int64_t>(type.getShape());
76-
for (auto [newDim, padValue] : llvm::zip_equal(newShape, padding)) {
77-
assert((padValue == 0 || ShapedType::isStatic(newDim)) &&
78-
"Padding dynamic dims not supported");
79-
newDim += padValue;
80-
}
81-
82-
return RankedTensorType::get(newShape, type.getElementType());
83-
}
84-
85-
struct MaterializePadEncodingTypeConverter final
86-
: MaterializeEncodingTypeConverter {
87-
MaterializePadEncodingTypeConverter(
88-
IREE::Encoding::LayoutMaterializerAttr layoutAttr)
89-
: MaterializeEncodingTypeConverter(layoutAttr) {
90-
addConversion([](RankedTensorType type) -> std::optional<RankedTensorType> {
91-
// The type converter is designed for `padding` encoding
92-
// attribute. By the definition, the final converted type is the same
93-
// tensor type without encodings.
94-
return type.dropEncoding();
95-
});
96-
addConversion([&](IREE::TensorExt::DispatchTensorType dispatchTensorType)
97-
-> IREE::TensorExt::DispatchTensorType {
98-
auto type = dyn_cast<RankedTensorType>(dispatchTensorType.getBoundType());
99-
if (!type || !type.getEncoding()) {
100-
return dispatchTensorType;
101-
}
102-
// The incoming bindings have the padded type, if `padding` is
103-
// present.
104-
if (getPadLayout(getLayoutAttr(), type)) {
105-
type = getPaddedType(getLayoutAttr(), type);
106-
}
107-
return IREE::TensorExt::DispatchTensorType::get(
108-
dispatchTensorType.getAccess(), type);
109-
});
110-
}
111-
112-
bool hasNonZeroPadding(RankedTensorType type) const {
113-
PaddingAttr layout = getPadLayout(getLayoutAttr(), type);
114-
return layout && !layout.isIdentityLayout();
115-
}
116-
};
117-
118-
/// Pattern to convert `iree_tensor_ext.dispatch.tensor.store` operation when
119-
/// materializing the encoding. We can not reuse the existing one because it
120-
/// does not transform new dynamic dimension through interface. The other
121-
/// difference is that the converted type of the padding attribute is not as the
122-
/// same as the tensor type that drops encoding.
123-
/// TODO(#20160): Abstract new interface methods and collapse two patterns.
124-
struct MaterializeInterfaceBindingEncoding final
125-
: OpConversionPattern<IREE::HAL::InterfaceBindingSubspanOp> {
126-
using Base::Base;
127-
128-
LogicalResult
129-
matchAndRewrite(IREE::HAL::InterfaceBindingSubspanOp subspanOp,
130-
OpAdaptor adaptor,
131-
ConversionPatternRewriter &rewriter) const override {
132-
auto resultType = dyn_cast<IREE::TensorExt::DispatchTensorType>(
133-
subspanOp.getResult().getType());
134-
if (!resultType) {
135-
return rewriter.notifyMatchFailure(
136-
subspanOp,
137-
"expected result type to be !iree_tensor_ext.dispatch.tensor");
138-
}
139-
auto newResultType = getTypeConverter()->convertType(resultType);
140-
SmallVector<Value> newDynamicDims = subspanOp.getDynamicDims();
141-
rewriter.replaceOpWithNewOp<IREE::HAL::InterfaceBindingSubspanOp>(
142-
subspanOp, newResultType, subspanOp.getLayout(), subspanOp.getBinding(),
143-
subspanOp.getByteOffset(), newDynamicDims, subspanOp.getAlignmentAttr(),
144-
subspanOp.getDescriptorFlagsAttr());
145-
return success();
146-
}
147-
};
148-
14939
struct MaterializeEncodingIntoPaddingPass final
15040
: impl::MaterializeEncodingIntoPaddingPassBase<
15141
MaterializeEncodingIntoPaddingPass> {
@@ -194,18 +84,10 @@ struct MaterializeEncodingIntoPaddingPass final
19484
}
19585

19686
RewritePatternSet materializeEncodingPattern(context);
197-
MaterializePadEncodingTypeConverter typeConverter(layoutAttr);
87+
MaterializeEncodingTypeConverter typeConverter(layoutAttr);
19888
MaterializeEncodingConversionTarget target(*context);
19989
populateMaterializeEncodingPatterns(materializeEncodingPattern, target,
20090
typeConverter);
201-
202-
// The majority of this conversion is based on the 'Nop' materialization,
203-
// with the exception of a few ops that have to account for padding.
204-
// We add custom patterns with much higher priority to run before the
205-
// equivalent 'Nop' patterns.
206-
materializeEncodingPattern.add<MaterializeInterfaceBindingEncoding>(
207-
typeConverter, context, PatternBenefit{100});
208-
20991
if (failed(applyPartialConversion(operation, target,
21092
std::move(materializeEncodingPattern)))) {
21193
operation.emitOpError("materialization failed");

compiler/src/iree/compiler/Codegen/Common/MaterializeEncodingPatterns.cpp

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -140,29 +140,6 @@ lowerOpWithEncoding(RewriterBase &rewriter, tensor::EmptyOp emptyOp,
140140
return newEmptyOp;
141141
}
142142

143-
/// For `dispatchTensorType` that bind a `RankedTensorType` with encoding,
144-
/// returns the dynamic dimensions of the materialized shape of the
145-
/// `dispatchTensorType`. The dynamic dimensions of the `dispatchTensorType` are
146-
/// provided in `dynamicDims`.
147-
static FailureOr<SmallVector<Value>> getPackedDynamicDimsForDispatchTensor(
148-
OpBuilder &builder, Location loc,
149-
const MaterializeEncodingTypeConverter &typeConverter,
150-
IREE::TensorExt::DispatchTensorType dispatchTensorType,
151-
ValueRange dynamicDims) {
152-
FailureOr<SmallVector<OpFoldResult>> convertedTargetShape =
153-
typeConverter.getPackedDimsForDispatchTensor(
154-
builder, loc, dispatchTensorType, dynamicDims);
155-
if (failed(convertedTargetShape)) {
156-
return failure();
157-
}
158-
SmallVector<int64_t> convertedStaticTargetShape;
159-
SmallVector<Value> convertedDynamicTargetShape;
160-
dispatchIndexOpFoldResults(convertedTargetShape.value(),
161-
convertedDynamicTargetShape,
162-
convertedStaticTargetShape);
163-
return convertedDynamicTargetShape;
164-
}
165-
166143
namespace {
167144
/// Pattern to materialize the encoding for `hal.interface.binding.subspan`
168145
/// operations.
@@ -175,44 +152,60 @@ struct MaterializeInterfaceBindingEncoding
175152
matchAndRewrite(IREE::HAL::InterfaceBindingSubspanOp subspanOp,
176153
OpAdaptor adaptor,
177154
ConversionPatternRewriter &rewriter) const override {
178-
auto resultType = llvm::dyn_cast<IREE::TensorExt::DispatchTensorType>(
155+
auto origResultType = dyn_cast<IREE::TensorExt::DispatchTensorType>(
179156
subspanOp.getResult().getType());
180-
if (!resultType) {
157+
if (!origResultType) {
181158
return rewriter.notifyMatchFailure(
182159
subspanOp,
183160
"expected result type to be !iree_tensor_ext.dispatch.tensor");
184161
}
185-
auto boundTensorType =
186-
llvm::dyn_cast<RankedTensorType>(resultType.getBoundType());
187-
if (!boundTensorType) {
162+
auto origBoundTensorType =
163+
dyn_cast<RankedTensorType>(origResultType.getBoundType());
164+
if (!origBoundTensorType) {
188165
return rewriter.notifyMatchFailure(
189166
subspanOp, "bound type is not a RankedTensorType");
190167
}
191168

192-
auto convertedBoundType = getTypeConverter()->convertType(boundTensorType);
193-
if (convertedBoundType == boundTensorType) {
194-
return rewriter.notifyMatchFailure(subspanOp, "bound type already valid");
169+
auto typeConverter = getTypeConverter<MaterializeEncodingTypeConverter>();
170+
auto convertedResultType =
171+
typeConverter->convertType<IREE::TensorExt::DispatchTensorType>(
172+
origResultType);
173+
if (!convertedResultType) {
174+
return rewriter.notifyMatchFailure(subspanOp,
175+
"expected converted result type to be "
176+
"!iree_tensor_ext.dispatch.tensor");
177+
}
178+
if (origResultType == convertedResultType) {
179+
return rewriter.notifyMatchFailure(
180+
subspanOp, "DispatchTensorType type already valid");
195181
}
196182

197-
auto typeConverter = getTypeConverter<MaterializeEncodingTypeConverter>();
198183
// Get the dynamic dims of the target.
184+
// TODO(hanchung): We only have getOffsetsSizesStrides interface method that
185+
// handles all three together. It would be cleaner to have a separate method
186+
// to get dynamic sizes only.
199187
Location loc = subspanOp.getLoc();
200-
SmallVector<Value> newDynamicDims = subspanOp.getDynamicDims();
201-
FailureOr<SmallVector<Value>> convertedDynamicDims =
202-
getPackedDynamicDimsForDispatchTensor(rewriter, loc, *typeConverter,
203-
resultType,
204-
subspanOp.getDynamicDims());
205-
// Drop the encoding if the target does not support it.
206-
if (succeeded(convertedDynamicDims)) {
207-
newDynamicDims = convertedDynamicDims.value();
188+
ValueRange origDynamicDims = subspanOp.getDynamicDims();
189+
SmallVector<OpFoldResult> origSizes = getMixedValues(
190+
origBoundTensorType.getShape(), origDynamicDims, rewriter);
191+
SmallVector<OpFoldResult> origOffsets(origDynamicDims.size(),
192+
rewriter.getIndexAttr(0));
193+
SmallVector<OpFoldResult> origStrides(origDynamicDims.size(),
194+
rewriter.getIndexAttr(1));
195+
SmallVector<OpFoldResult> newOffsets, newSizes, newStrides;
196+
if (failed(typeConverter->getOffsetsSizesStrides(
197+
rewriter, loc, origResultType, origDynamicDims, origOffsets,
198+
origSizes, origStrides, newOffsets, newSizes, newStrides))) {
199+
return failure();
208200
}
209201

210-
auto newResultType = IREE::TensorExt::DispatchTensorType::get(
211-
resultType.getAccess(), convertedBoundType);
202+
SmallVector<int64_t> newStaticDims;
203+
SmallVector<Value> newDynamicDims;
204+
dispatchIndexOpFoldResults(newSizes, newDynamicDims, newStaticDims);
212205
rewriter.replaceOpWithNewOp<IREE::HAL::InterfaceBindingSubspanOp>(
213-
subspanOp, newResultType, subspanOp.getLayout(), subspanOp.getBinding(),
214-
subspanOp.getByteOffset(), newDynamicDims, subspanOp.getAlignmentAttr(),
215-
subspanOp.getDescriptorFlagsAttr());
206+
subspanOp, convertedResultType, subspanOp.getLayout(),
207+
subspanOp.getBinding(), subspanOp.getByteOffset(), newDynamicDims,
208+
subspanOp.getAlignmentAttr(), subspanOp.getDescriptorFlagsAttr());
216209
return success();
217210
}
218211
};

compiler/src/iree/compiler/Codegen/Common/test/materialize_encoding_into_padding.mlir

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ func.func @dynamic_set_zero_pad_encoding_and_store() {
113113
%2 = hal.interface.constant.load layout(<constants = 2, bindings = [#binding_ro, #binding], flags = Indirect>) ordinal(1) : i32
114114
%dynamic_sz = arith.index_castui %2 : i32 to index
115115
%3 = hal.interface.binding.subspan layout(<constants = 2, bindings = [#binding_ro, #binding], flags = Indirect>) binding(0) alignment(64) offset(%1) flags("ReadOnly|Indirect")
116-
: !iree_tensor_ext.dispatch.tensor<readonly:tensor<?x2048xf16>>
116+
: !iree_tensor_ext.dispatch.tensor<readonly:tensor<?x2048xf16>>{%dynamic_sz}
117117
%4 = hal.interface.binding.subspan layout(<constants = 2, bindings = [#binding_ro, #binding], flags = Indirect>) binding(1) alignment(64) offset(%c0) flags(Indirect)
118-
: !iree_tensor_ext.dispatch.tensor<writeonly:tensor<?x2048xf16, #pad_encoding>>
118+
: !iree_tensor_ext.dispatch.tensor<writeonly:tensor<?x2048xf16, #pad_encoding>>{%dynamic_sz}
119119
%5 = iree_tensor_ext.dispatch.tensor.load %3, offsets = [0, 0], sizes = [%dynamic_sz, 2048], strides = [1, 1]
120120
: !iree_tensor_ext.dispatch.tensor<readonly:tensor<?x2048xf16>>{%dynamic_sz} -> tensor<?x2048xf16>
121121
%6 = iree_encoding.set_encoding %5 : tensor<?x2048xf16> -> tensor<?x2048xf16, #encoding_mmt>

compiler/src/iree/compiler/Codegen/ExternalInterfaces/GPUEncodingExternalModels.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,10 +580,83 @@ struct GPULayoutResolverAttr final
580580
}
581581
};
582582

583+
// Returns the pad encoding layout, or nullptr if this is not the only layout or
584+
// if there's no encoding at all.
585+
static IREE::Encoding::PaddingAttr
586+
getPadLayout(IREE::Encoding::LayoutResolverAttr layoutAttr,
587+
RankedTensorType type) {
588+
if (!type.getEncoding()) {
589+
return nullptr;
590+
}
591+
auto encoding =
592+
dyn_cast_or_null<IREE::Encoding::LayoutAttr>(type.getEncoding());
593+
if (encoding) {
594+
ArrayAttr layouts = encoding.getLayouts();
595+
if (layouts.size() != 1) {
596+
return nullptr;
597+
}
598+
return dyn_cast<IREE::Encoding::PaddingAttr>(*layouts.begin());
599+
}
600+
Attribute resolvedEncoding = layoutAttr.getLayout(type);
601+
LDBG() << "Unresolved type: " << type;
602+
LDBG() << "layoutAttr: " << layoutAttr;
603+
LDBG() << "Resolved into: " << resolvedEncoding;
604+
return dyn_cast<IREE::Encoding::PaddingAttr>(resolvedEncoding);
605+
}
606+
607+
// Returns a padded tensor type (without encoding) for tensor types with the pad
608+
// encoding layout, or the same type for all other tensors.
609+
static RankedTensorType
610+
getPaddedType(IREE::Encoding::LayoutResolverAttr layoutAttr,
611+
RankedTensorType type) {
612+
IREE::Encoding::PaddingAttr layout = getPadLayout(layoutAttr, type);
613+
if (!layout) {
614+
return nullptr;
615+
}
616+
if (layout.isIdentityLayout()) {
617+
return type.dropEncoding();
618+
}
619+
620+
ArrayRef<int64_t> padding = layout.getPadding().asArrayRef();
621+
auto newShape = llvm::to_vector_of<int64_t>(type.getShape());
622+
for (auto [newDim, padValue] : llvm::zip_equal(newShape, padding)) {
623+
assert((padValue == 0 || ShapedType::isStatic(newDim)) &&
624+
"Padding dynamic dims not supported");
625+
newDim += padValue;
626+
}
627+
628+
return RankedTensorType::get(newShape, type.getElementType());
629+
}
630+
583631
struct GPUPadEncodingLayoutMaterializerAttr final
584632
: IREE::Encoding::LayoutMaterializerAttr::ExternalModel<
585633
GPUPadEncodingLayoutMaterializerAttr, GPUPaddingResolverAttr> {
586634

635+
Type convertType(Attribute attr, Type type) const {
636+
auto layoutAttr = cast<IREE::Encoding::LayoutResolverAttr>(attr);
637+
return TypeSwitch<Type, Type>(type)
638+
.Case([](RankedTensorType type) {
639+
// By the definition, the final converted type is the same tensor type
640+
// without encodings.
641+
return type.dropEncoding();
642+
})
643+
.Case([&](IREE::TensorExt::DispatchTensorType dispatchTensorType) {
644+
auto type =
645+
dyn_cast<RankedTensorType>(dispatchTensorType.getBoundType());
646+
if (!type || !type.getEncoding()) {
647+
return dispatchTensorType;
648+
}
649+
// The incoming bindings have the padded type, if `padding` is
650+
// present.
651+
if (getPadLayout(layoutAttr, type)) {
652+
type = getPaddedType(layoutAttr, type);
653+
}
654+
return IREE::TensorExt::DispatchTensorType::get(
655+
dispatchTensorType.getAccess(), type);
656+
})
657+
.Default([](Type type) { return type; });
658+
}
659+
587660
LogicalResult getOffsetsSizesStrides(
588661
Attribute attr, OpBuilder &builder, Location loc,
589662
IREE::TensorExt::DispatchTensorType type, ValueRange dynamicDims,

0 commit comments

Comments
 (0)