Skip to content

Commit 985bb3a

Browse files
committed
[mlir] fix bytecode writer after c1eab57
The change in c1eab57 fixed the behavior of `getDiscardableAttrDictionary` for ops that are not using properties to only return discardable attributes. Bytecode writer was relying on the wrong behavior and would assume all attributes are discardable, without appropriate testing. Fix that and add a test.
1 parent 26993f6 commit 985bb3a

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

mlir/lib/Bytecode/Writer/BytecodeWriter.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,9 +962,12 @@ LogicalResult BytecodeWriter::writeOp(EncodingEmitter &emitter, Operation *op) {
962962
DictionaryAttr attrs = op->getDiscardableAttrDictionary();
963963
// Allow deployment to version <kNativePropertiesEncoding by merging inherent
964964
// attribute with the discardable ones. We should fail if there are any
965-
// conflicts.
966-
if (config.bytecodeVersion < bytecode::kNativePropertiesEncoding)
965+
// conflicts. When properties are not used by the op, also store everything as
966+
// attributes.
967+
if (config.bytecodeVersion < bytecode::kNativePropertiesEncoding ||
968+
!op->getPropertiesStorage()) {
967969
attrs = op->getAttrDictionary();
970+
}
968971
if (!attrs.empty()) {
969972
opEncodingMask |= bytecode::OpEncodingMask::kHasAttrs;
970973
emitter.emitVarInt(numberingState.getNumber(attrs));

mlir/lib/Bytecode/Writer/IRNumbering.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,10 @@ void IRNumberingState::number(Operation &op) {
425425

426426
// Only number the operation's dictionary if it isn't empty.
427427
DictionaryAttr dictAttr = op.getDiscardableAttrDictionary();
428-
// Prior to version 5 we need to number also the merged dictionnary
429-
// containing both the inherent and discardable attribute.
430-
if (config.getDesiredBytecodeVersion() < 5)
428+
// Prior to version 5, or when properties are not used, we need to number also
429+
// the merged dictionary containing both the inherent and discardable
430+
// attribute.
431+
if (config.getDesiredBytecodeVersion() < 5 || !op.getPropertiesStorage())
431432
dictAttr = op.getAttrDictionary();
432433
if (!dictAttr.empty())
433434
number(dictAttr);

mlir/unittests/Bytecode/BytecodeTest.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "mlir/Bytecode/BytecodeReader.h"
910
#include "mlir/Bytecode/BytecodeWriter.h"
1011
#include "mlir/IR/AsmState.h"
1112
#include "mlir/IR/BuiltinAttributes.h"
@@ -15,6 +16,7 @@
1516

1617
#include "llvm/ADT/StringRef.h"
1718
#include "llvm/Support/Endian.h"
19+
#include "llvm/Support/MemoryBufferRef.h"
1820
#include "gmock/gmock.h"
1921
#include "gtest/gtest.h"
2022

@@ -86,3 +88,60 @@ TEST(Bytecode, MultiModuleWithResource) {
8688
checkResourceAttribute(*module);
8789
checkResourceAttribute(*roundTripModule);
8890
}
91+
92+
namespace {
93+
/// A custom operation for the purpose of showcasing how discardable attributes
94+
/// are handled in absence of properties.
95+
class OpWithoutProperties : public Op<OpWithoutProperties> {
96+
public:
97+
// Begin boilerplate.
98+
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpWithoutProperties)
99+
using Op::Op;
100+
static ArrayRef<StringRef> getAttributeNames() {
101+
static StringRef attributeNames[] = {StringRef("inherent_attr")};
102+
return ArrayRef(attributeNames);
103+
};
104+
static StringRef getOperationName() {
105+
return "test_op_properties.op_without_properties";
106+
}
107+
// End boilerplate.
108+
};
109+
110+
// A trivial supporting dialect to register the above operation.
111+
class TestOpPropertiesDialect : public Dialect {
112+
public:
113+
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOpPropertiesDialect)
114+
static constexpr StringLiteral getDialectNamespace() {
115+
return StringLiteral("test_op_properties");
116+
}
117+
explicit TestOpPropertiesDialect(MLIRContext *context)
118+
: Dialect(getDialectNamespace(), context,
119+
TypeID::get<TestOpPropertiesDialect>()) {
120+
addOperations<OpWithoutProperties>();
121+
}
122+
};
123+
} // namespace
124+
125+
constexpr StringLiteral withoutPropertiesAttrsSrc = R"mlir(
126+
"test_op_properties.op_without_properties"()
127+
{inherent_attr = 42, other_attr = 56} : () -> ()
128+
)mlir";
129+
130+
TEST(Bytecode, OpWithoutProperties) {
131+
MLIRContext context;
132+
context.getOrLoadDialect<TestOpPropertiesDialect>();
133+
ParserConfig config(&context);
134+
OwningOpRef<Operation *> op =
135+
parseSourceString(withoutPropertiesAttrsSrc, config);
136+
137+
std::string bytecode;
138+
llvm::raw_string_ostream os(bytecode);
139+
ASSERT_TRUE(succeeded(writeBytecodeToFile(op.get(), os)));
140+
std::unique_ptr<Block> block = std::make_unique<Block>();
141+
ASSERT_TRUE(succeeded(readBytecodeFile(
142+
llvm::MemoryBufferRef(os.str(), "string-buffer"), block.get(), config)));
143+
Operation *roundtripped = &block->front();
144+
EXPECT_EQ(roundtripped->getAttrs().size(), 2u);
145+
EXPECT_TRUE(roundtripped->getInherentAttr("inherent_attr") != std::nullopt);
146+
EXPECT_TRUE(roundtripped->getDiscardableAttr("other_attr") != Attribute());
147+
}

0 commit comments

Comments
 (0)