Skip to content

Commit bac621f

Browse files
committed
* make packed_storage as a type of iree_encoding attribute, and make type converters accept it.
* `i1` tensors with `#iree_encoding.packed_storage` will be interpreted as packed i1 type, same as specifying `--iree-experimental-packed-i1-storage`. * `--iree-experimental-packed-i1-storage` are kept for testing purposes. We can drop this option after frontend enables emitting `i1` tensors with attributes. Signed-off-by: Alan Li <me@alanli.org>
1 parent c618134 commit bac621f

File tree

10 files changed

+93
-18
lines changed

10 files changed

+93
-18
lines changed

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "iree/compiler/Codegen/Common/EncodingUtils.h"
88
#include "iree/compiler/Codegen/Dialect/Codegen/Utils/Utils.h"
9+
#include "iree/compiler/Dialect/Encoding/IR/EncodingTypes.h"
910
#include "mlir/Dialect/Linalg/IR/LinalgInterfaces.h"
1011
#include "mlir/Dialect/Tensor/IR/Tensor.h"
1112
#include "mlir/Dialect/Utils/IndexingUtils.h"
@@ -133,7 +134,10 @@ MaterializeEncodingConversionTarget::MaterializeEncodingConversionTarget(
133134
markUnknownOpDynamicallyLegal([](Operation *op) {
134135
auto typeHasEncoding = [](Type t) -> bool {
135136
auto tensorType = dyn_cast<RankedTensorType>(t);
136-
return tensorType && tensorType.getEncoding();
137+
if (!(tensorType && tensorType.getEncoding()))
138+
return false;
139+
// Allow iree_encoding::packed_storage to pass through.
140+
return !IREE::Encoding::hasPackedStorageAttr(tensorType);
137141
};
138142
auto valueHasEncoding = [=](Value v) -> bool {
139143
return typeHasEncoding(v.getType());

compiler/src/iree/compiler/Dialect/Encoding/IR/EncodingAttrs.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ EncodingAttr getEncodingAttr(RankedTensorType type) {
243243
return dyn_cast_or_null<EncodingAttr>(type.getEncoding());
244244
}
245245

246+
bool hasPackedStorageAttr(RankedTensorType type) {
247+
return dyn_cast_or_null<PackedStorageAttr>(type.getEncoding()) != nullptr;
248+
}
249+
246250
FailureOr<linalg::ContractionDimensions>
247251
getEncodingContractionDims(EncodingAttr encoding) {
248252
auto indexingMapsAttr = encoding.getUserIndexingMaps();

compiler/src/iree/compiler/Dialect/Encoding/IR/EncodingAttrs.td

+11
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ def EncodingOpType : IREEEncoding_I32EnumAttr<"EncodingOpType",
4141
def EncodingOpTypeAttr:
4242
IREEEncoding_EnumAttr<EncodingOpType, "optype">;
4343

44+
45+
def PackedStorageAttr : IREEEncoding_Attr<"PackedStorage"> {
46+
let mnemonic = "packed_storage";
47+
let summary = [{Indicates packed storage datatype.}];
48+
let description = [{
49+
This attribute indicates this is a back-to-back packed storage in memory.
50+
This attribute takes no arguments.
51+
}];
52+
let genVerifyDecl = 0;
53+
}
54+
4455
def EncodingAttr :
4556
IREEEncoding_Attr<"Encoding", [
4657
DeclareAttrInterfaceMethods<IREEEncoding_EncodingLayoutAttrInterface, [

compiler/src/iree/compiler/Dialect/Encoding/IR/EncodingTypes.h

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ namespace mlir::iree_compiler::IREE::Encoding {
3838
/// Otherwise, returns null.
3939
EncodingAttr getEncodingAttr(RankedTensorType type);
4040

41+
/// Returns true if the type contains packed_storage attribute.
42+
bool hasPackedStorageAttr(RankedTensorType type);
43+
4144
/// Returns the ContractionDimensions for the encoding user_indexing_maps.
4245
FailureOr<linalg::ContractionDimensions>
4346
getEncodingContractionDims(EncodingAttr encoding);

compiler/src/iree/compiler/Dialect/Stream/Conversion/HALToStream/Patterns.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
#include "iree/compiler/Dialect/Stream/IR/StreamOps.h"
1313
#include "mlir/Dialect/Arith/IR/Arith.h"
1414

15+
namespace mlir::iree_compiler::IREE::Encoding {
16+
bool hasPackedStorageAttr(mlir::RankedTensorType);
17+
} // namespace mlir::iree_compiler::IREE::Encoding
18+
1519
namespace mlir::iree_compiler {
1620

1721
namespace {
@@ -90,6 +94,11 @@ struct ConvertTensorImportOp
9094
RankedTensorType tensorType,
9195
ValueRange dynamicDims,
9296
OpBuilder &builder) {
97+
// If the encoding attr is about packed storage then we don't need all this
98+
if (IREE::Encoding::hasPackedStorageAttr(tensorType)) {
99+
return success();
100+
}
101+
93102
auto expectedElementType = builder.create<IREE::HAL::ElementTypeOp>(
94103
loc, tensorType.getElementType());
95104
auto expectedEncodingType = builder.create<IREE::HAL::EncodingTypeOp>(

compiler/src/iree/compiler/Dialect/Stream/Transforms/EncodeTensors.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ static LogicalResult checkEncoding(Operation *op, RankedTensorType encodingType,
4646
ValueRange encodingDims,
4747
PatternRewriter &rewriter) {
4848
auto encoding = encodingType.getEncoding();
49-
if (encoding && !llvm::isa<IREE::Encoding::EncodingAttr>(encoding)) {
49+
if (encoding && !llvm::isa<IREE::Encoding::EncodingAttr,
50+
IREE::Encoding::PackedStorageAttr>(encoding)) {
5051
return rewriter.notifyMatchFailure(op, [=](Diagnostic &d) {
5152
d << "unsupported tensor encoding: " << encodingType;
5253
});

compiler/src/iree/compiler/Dialect/Stream/Transforms/test/encode_host_tensors_packing_i1.mlir

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
// RUN: iree-opt --split-input-file --iree-stream-encode-host-tensors --iree-experimental-packed-i1-storage %s | FileCheck %s
1+
// RUN: iree-opt --split-input-file --iree-stream-encode-host-tensors %s | FileCheck %s
22

3+
#packed = #iree_encoding.packed_storage
34
func.func @unaligned_i1_size() -> index {
4-
%0 = stream.tensor.sizeof tensor<12xi1> : index
5+
%0 = stream.tensor.sizeof tensor<12xi1, #packed> : index
56
return %0 : index
67
}
78
// CHECK: func @unaligned_i1_size() -> index {
@@ -10,8 +11,9 @@ func.func @unaligned_i1_size() -> index {
1011

1112
// -----
1213

14+
#packed = #iree_encoding.packed_storage
1315
func.func @aligned_i1_size() -> index {
14-
%0 = stream.tensor.sizeof tensor<24xi1> : index
16+
%0 = stream.tensor.sizeof tensor<24xi1, #packed> : index
1517
return %0 : index
1618
}
1719

compiler/src/iree/compiler/DispatchCreation/SetEncoding.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace mlir::iree_compiler::DispatchCreation {
3232
#include "iree/compiler/DispatchCreation/Passes.h.inc"
3333

3434
using IREE::Encoding::EncodingAttr;
35+
using IREE::Encoding::PackedStorageAttr;
3536

3637
//===---------------------------------------------------------------------===//
3738
// Utility functions

compiler/src/iree/compiler/Utils/ElementPackingUtils.cpp

+41-13
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,29 @@
1515
#include "mlir/Dialect/Arith/IR/Arith.h"
1616
#include "mlir/IR/BuiltinTypes.h"
1717

18-
namespace mlir::iree_compiler {
19-
2018
llvm::cl::opt<bool> clEnableI1Support(
2119
"iree-experimental-packed-i1-storage",
2220
llvm::cl::desc(
23-
"Experimental feature: enable i1 data type support in codegen"),
21+
"Experimental feature: force to use packed storage for i1 tensors."
22+
"Turning on this option will see i1 tensors as if it has "
23+
"#iree_encoding.packed_storage attribute."
24+
"This is to allow an alternative way to test the packed storage "
25+
"feature before frontend can emit packed i1 tensors."
26+
"This option can be dropped once the frontend can emit packed i1 "
27+
"tensors."),
2428
llvm::cl::init(false));
2529

30+
namespace mlir::iree_compiler {
31+
2632
bool needToPackSubByteElementBitWidth(unsigned bitWidth) {
33+
return needToPackSubByteElementBitWidth(
34+
bitWidth, /*isI1PackedStorage=*/clEnableI1Support);
35+
}
36+
37+
bool needToPackSubByteElementBitWidth(unsigned bitWidth,
38+
bool isI1PackedStorage) {
2739
// Enable i1 support if requested.
28-
if (clEnableI1Support && bitWidth == 1) {
40+
if (isI1PackedStorage && bitWidth == 1) {
2941
return true;
3042
}
3143
// Require the original bit width to be some power of two for now to avoid
@@ -37,18 +49,28 @@ bool needToPackSubByteElementBitWidth(unsigned bitWidth) {
3749

3850
bool needToPackSubByteElements(RankedTensorType shapedType) {
3951
unsigned bitWidth = IREE::Util::getTypeBitWidth(shapedType.getElementType());
40-
return needToPackSubByteElementBitWidth(bitWidth);
52+
// Two paths to enable packed storage for i1 tensors: the attribute or cl
53+
// option. The cl option will be dropped once frontend supports emitting
54+
// tensors with attributes.
55+
bool isI1PackedStorage =
56+
IREE::Encoding::hasPackedStorageAttr(shapedType) || clEnableI1Support;
57+
return needToPackSubByteElementBitWidth(bitWidth, isI1PackedStorage);
4158
}
4259

4360
Type legalizeStorageElementType(Type elementType) {
61+
return legalizeStorageElementType(elementType,
62+
/*isI1PackedStorage=*/clEnableI1Support);
63+
}
64+
65+
Type legalizeStorageElementType(Type elementType, bool isI1PackedStorage) {
4466
// Only handle integers; floats in MLIR all have aligned widths (today).
4567
auto intType = dyn_cast<IntegerType>(elementType);
4668
if (!intType)
4769
return elementType;
4870

4971
// For sub-byte elements, default to pack them into bytes.
5072
unsigned bitWidth = intType.getWidth();
51-
if (needToPackSubByteElementBitWidth(bitWidth))
73+
if (needToPackSubByteElementBitWidth(bitWidth, isI1PackedStorage))
5274
return elementType;
5375

5476
// Otherwise, extend them to the next power-of-two bit width.
@@ -72,13 +94,16 @@ Value calculateStorageElementCountInBytes(Location loc,
7294
loc, builder, shapedType, dynamicDims);
7395
}
7496

97+
// TODO: remove cl options once frontend can emit packed i1 tensors.
98+
bool packedStorage =
99+
IREE::Encoding::hasPackedStorageAttr(shapedType) || clEnableI1Support;
75100
Type alignedElementType =
76-
legalizeStorageElementType(shapedType.getElementType());
101+
legalizeStorageElementType(shapedType.getElementType(), packedStorage);
77102
unsigned elementBits = IREE::Util::getTypeBitWidth(alignedElementType);
78103

79104
// Calculate all static dims first, if any.
80105
int64_t staticCount = 1;
81-
if (!needToPackSubByteElementBitWidth(elementBits)) {
106+
if (!needToPackSubByteElementBitWidth(elementBits, packedStorage)) {
82107
staticCount *= IREE::Util::getRoundedElementByteWidth(alignedElementType);
83108
}
84109

@@ -93,13 +118,13 @@ Value calculateStorageElementCountInBytes(Location loc,
93118
value = builder.createOrFold<arith::MulIOp>(loc, value, dim);
94119
}
95120
// Sub-byte packing requires putting multiple elements in the same byte.
96-
if (needToPackSubByteElementBitWidth(elementBits)) {
121+
if (needToPackSubByteElementBitWidth(elementBits, packedStorage)) {
97122
assert(8 % elementBits == 0);
98123
unsigned byteElements = 8 / elementBits;
99124
// TODO(antiagainst): We may want to emit runtime check to make sure this is
100125
// divisible.
101126
auto divisor = builder.create<arith::ConstantIndexOp>(loc, byteElements);
102-
if (!clEnableI1Support && dynamicDims.empty() &&
127+
if (!packedStorage && dynamicDims.empty() &&
103128
(staticCount * elementBits) % 8 != 0) {
104129
return nullptr;
105130
}
@@ -113,12 +138,15 @@ Value calculateStorageElementOffsetInBytes(Location loc,
113138
RankedTensorType originalType,
114139
Value linearizedIndex,
115140
OpBuilder &builder) {
116-
Type alignedElementType =
117-
legalizeStorageElementType(originalType.getElementType());
141+
// TODO: remove cl options once frontend can emit packed i1 tensors.
142+
bool isI1PackedStorage =
143+
IREE::Encoding::hasPackedStorageAttr(originalType) || clEnableI1Support;
144+
Type alignedElementType = legalizeStorageElementType(
145+
originalType.getElementType(), isI1PackedStorage);
118146
unsigned elementBits = IREE::Util::getTypeBitWidth(alignedElementType);
119147

120148
// Sub-byte packing requires putting multiple elements in the same byte.
121-
if (needToPackSubByteElementBitWidth(elementBits)) {
149+
if (needToPackSubByteElementBitWidth(elementBits, isI1PackedStorage)) {
122150
Value byteElements =
123151
builder.create<arith::ConstantIndexOp>(loc, 8 / elementBits);
124152
// TODO(antiagainst): We may want to emit runtime check to make sure this is

compiler/src/iree/compiler/Utils/ElementPackingUtils.h

+12
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ namespace mlir::iree_compiler {
1515

1616
/// Returns true if the given |bitWidth|, if appearing at runtime-kernel
1717
/// interface, is less than a byte that should be tightly packed together.
18+
bool needToPackSubByteElementBitWidth(unsigned bitWidth,
19+
bool isI1PackedStorage);
20+
21+
/// Temporary wrapper for the above function. `isI1PackedStorage` will be
22+
/// determined by the cl option. This allows enabling packed storage for i1
23+
/// in both attribute and cl option ways.
1824
bool needToPackSubByteElementBitWidth(unsigned bitWidth);
25+
1926
/// Returns true if the given |shapedType|, if appearing at runtime-kernel
2027
/// interface, has sub-byte element types that should be tightly packed
2128
/// together.
@@ -27,6 +34,11 @@ bool needToPackSubByteElements(RankedTensorType shapedType);
2734
/// runtime and kernel. For such cases, we perform tight packing for supported
2835
/// sub-byte elements, and expand to the next power-of-two bit width for other
2936
/// cases.
37+
Type legalizeStorageElementType(Type elementType, bool isI1PackedStorage);
38+
39+
/// Temporary wrapper for the above function. `isI1PackedStorage` will be
40+
/// determined by the cl option. This allows enabling packed storage for i1
41+
/// in both attribute and cl option ways.
3042
Type legalizeStorageElementType(Type elementType);
3143

3244
/// Emits IR with the given |builder| to calculate the total number of bytes

0 commit comments

Comments
 (0)