xref: /llvm-project/mlir/unittests/Bytecode/BytecodeTest.cpp (revision e605969efe95efd9941cf958d921006d0833889f)
1cfd90939SMehdi Amini //===- AdaptorTest.cpp - Adaptor unit tests -------------------------------===//
2cfd90939SMehdi Amini //
3cfd90939SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cfd90939SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
5cfd90939SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cfd90939SMehdi Amini //
7cfd90939SMehdi Amini //===----------------------------------------------------------------------===//
8cfd90939SMehdi Amini 
9985bb3a2SAlex Zinenko #include "mlir/Bytecode/BytecodeReader.h"
10cfd90939SMehdi Amini #include "mlir/Bytecode/BytecodeWriter.h"
11cfd90939SMehdi Amini #include "mlir/IR/AsmState.h"
12cfd90939SMehdi Amini #include "mlir/IR/BuiltinAttributes.h"
13cfd90939SMehdi Amini #include "mlir/IR/OpImplementation.h"
14cfd90939SMehdi Amini #include "mlir/IR/OwningOpRef.h"
15cfd90939SMehdi Amini #include "mlir/Parser/Parser.h"
16cfd90939SMehdi Amini 
17cfd90939SMehdi Amini #include "llvm/ADT/StringRef.h"
18bb0bbed6SUlrich Weigand #include "llvm/Support/Endian.h"
19985bb3a2SAlex Zinenko #include "llvm/Support/MemoryBufferRef.h"
20cfd90939SMehdi Amini #include "gmock/gmock.h"
21cfd90939SMehdi Amini #include "gtest/gtest.h"
22cfd90939SMehdi Amini 
23cfd90939SMehdi Amini using namespace llvm;
24cfd90939SMehdi Amini using namespace mlir;
25cfd90939SMehdi Amini 
26dd5696cdSMehdi Amini StringLiteral irWithResources = R"(
27cfd90939SMehdi Amini module @TestDialectResources attributes {
28cfd90939SMehdi Amini   bytecode.test = dense_resource<resource> : tensor<4xi32>
29cfd90939SMehdi Amini } {}
30cfd90939SMehdi Amini {-#
31cfd90939SMehdi Amini   dialect_resources: {
32cfd90939SMehdi Amini     builtin: {
332b5134f1SMogball       resource: "0x2000000001000000020000000300000004000000",
342b5134f1SMogball       resource_2: "0x2000000001000000020000000300000004000000"
35cfd90939SMehdi Amini     }
36cfd90939SMehdi Amini   }
37cfd90939SMehdi Amini #-}
38cfd90939SMehdi Amini )";
39cfd90939SMehdi Amini 
40cfd90939SMehdi Amini TEST(Bytecode, MultiModuleWithResource) {
41cfd90939SMehdi Amini   MLIRContext context;
42cfd90939SMehdi Amini   Builder builder(&context);
43cfd90939SMehdi Amini   ParserConfig parseConfig(&context);
44cfd90939SMehdi Amini   OwningOpRef<Operation *> module =
45dd5696cdSMehdi Amini       parseSourceString<Operation *>(irWithResources, parseConfig);
46cfd90939SMehdi Amini   ASSERT_TRUE(module);
47cfd90939SMehdi Amini 
48cfd90939SMehdi Amini   // Write the module to bytecode
49cfd90939SMehdi Amini   std::string buffer;
50cfd90939SMehdi Amini   llvm::raw_string_ostream ostream(buffer);
51cfd90939SMehdi Amini   ASSERT_TRUE(succeeded(writeBytecodeToFile(module.get(), ostream)));
521c8c365dSChristian Sigg 
531c8c365dSChristian Sigg   // Create copy of buffer which is aligned to requested resource alignment.
541c8c365dSChristian Sigg   constexpr size_t kAlignment = 0x20;
55dd5696cdSMehdi Amini   size_t bufferSize = buffer.size();
56dd5696cdSMehdi Amini   buffer.reserve(bufferSize + kAlignment - 1);
57d5746d73SFrank Schlimbach   size_t pad = (~(uintptr_t)buffer.data() + 1) & (kAlignment - 1);
581c8c365dSChristian Sigg   buffer.insert(0, pad, ' ');
59dd5696cdSMehdi Amini   StringRef alignedBuffer(buffer.data() + pad, bufferSize);
60cfd90939SMehdi Amini 
61cfd90939SMehdi Amini   // Parse it back
62cfd90939SMehdi Amini   OwningOpRef<Operation *> roundTripModule =
63dd5696cdSMehdi Amini       parseSourceString<Operation *>(alignedBuffer, parseConfig);
64cfd90939SMehdi Amini   ASSERT_TRUE(roundTripModule);
65cfd90939SMehdi Amini 
66bb0bbed6SUlrich Weigand   // FIXME: Parsing external resources does not work on big-endian
67bb0bbed6SUlrich Weigand   // platforms currently.
686b31b026SKazu Hirata   if (llvm::endianness::native == llvm::endianness::big)
69bb0bbed6SUlrich Weigand     GTEST_SKIP();
70bb0bbed6SUlrich Weigand 
71cfd90939SMehdi Amini   // Try to see if we have a valid resource in the parsed module.
72*e605969eSSoren Lassen   auto checkResourceAttribute = [](Operation *parsedModule) {
73*e605969eSSoren Lassen     Attribute attr = parsedModule->getDiscardableAttr("bytecode.test");
74cfd90939SMehdi Amini     ASSERT_TRUE(attr);
75cfd90939SMehdi Amini     auto denseResourceAttr = dyn_cast<DenseI32ResourceElementsAttr>(attr);
76cfd90939SMehdi Amini     ASSERT_TRUE(denseResourceAttr);
77cfd90939SMehdi Amini     std::optional<ArrayRef<int32_t>> attrData =
78cfd90939SMehdi Amini         denseResourceAttr.tryGetAsArrayRef();
79cfd90939SMehdi Amini     ASSERT_TRUE(attrData.has_value());
80cfd90939SMehdi Amini     ASSERT_EQ(attrData->size(), static_cast<size_t>(4));
81cfd90939SMehdi Amini     EXPECT_EQ((*attrData)[0], 1);
82cfd90939SMehdi Amini     EXPECT_EQ((*attrData)[1], 2);
83cfd90939SMehdi Amini     EXPECT_EQ((*attrData)[2], 3);
84cfd90939SMehdi Amini     EXPECT_EQ((*attrData)[3], 4);
85cfd90939SMehdi Amini   };
86cfd90939SMehdi Amini 
87cfd90939SMehdi Amini   checkResourceAttribute(*module);
88cfd90939SMehdi Amini   checkResourceAttribute(*roundTripModule);
89cfd90939SMehdi Amini }
90985bb3a2SAlex Zinenko 
91985bb3a2SAlex Zinenko namespace {
92985bb3a2SAlex Zinenko /// A custom operation for the purpose of showcasing how discardable attributes
93985bb3a2SAlex Zinenko /// are handled in absence of properties.
94985bb3a2SAlex Zinenko class OpWithoutProperties : public Op<OpWithoutProperties> {
95985bb3a2SAlex Zinenko public:
96985bb3a2SAlex Zinenko   // Begin boilerplate.
97985bb3a2SAlex Zinenko   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpWithoutProperties)
98985bb3a2SAlex Zinenko   using Op::Op;
99985bb3a2SAlex Zinenko   static ArrayRef<StringRef> getAttributeNames() {
100985bb3a2SAlex Zinenko     static StringRef attributeNames[] = {StringRef("inherent_attr")};
101985bb3a2SAlex Zinenko     return ArrayRef(attributeNames);
102985bb3a2SAlex Zinenko   };
103985bb3a2SAlex Zinenko   static StringRef getOperationName() {
104985bb3a2SAlex Zinenko     return "test_op_properties.op_without_properties";
105985bb3a2SAlex Zinenko   }
106985bb3a2SAlex Zinenko   // End boilerplate.
107985bb3a2SAlex Zinenko };
108985bb3a2SAlex Zinenko 
109985bb3a2SAlex Zinenko // A trivial supporting dialect to register the above operation.
110985bb3a2SAlex Zinenko class TestOpPropertiesDialect : public Dialect {
111985bb3a2SAlex Zinenko public:
112985bb3a2SAlex Zinenko   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOpPropertiesDialect)
113985bb3a2SAlex Zinenko   static constexpr StringLiteral getDialectNamespace() {
114985bb3a2SAlex Zinenko     return StringLiteral("test_op_properties");
115985bb3a2SAlex Zinenko   }
116985bb3a2SAlex Zinenko   explicit TestOpPropertiesDialect(MLIRContext *context)
117985bb3a2SAlex Zinenko       : Dialect(getDialectNamespace(), context,
118985bb3a2SAlex Zinenko                 TypeID::get<TestOpPropertiesDialect>()) {
119985bb3a2SAlex Zinenko     addOperations<OpWithoutProperties>();
120985bb3a2SAlex Zinenko   }
121985bb3a2SAlex Zinenko };
122985bb3a2SAlex Zinenko } // namespace
123985bb3a2SAlex Zinenko 
124985bb3a2SAlex Zinenko constexpr StringLiteral withoutPropertiesAttrsSrc = R"mlir(
125985bb3a2SAlex Zinenko     "test_op_properties.op_without_properties"()
126985bb3a2SAlex Zinenko       {inherent_attr = 42, other_attr = 56} : () -> ()
127985bb3a2SAlex Zinenko )mlir";
128985bb3a2SAlex Zinenko 
129985bb3a2SAlex Zinenko TEST(Bytecode, OpWithoutProperties) {
130985bb3a2SAlex Zinenko   MLIRContext context;
131985bb3a2SAlex Zinenko   context.getOrLoadDialect<TestOpPropertiesDialect>();
132985bb3a2SAlex Zinenko   ParserConfig config(&context);
133985bb3a2SAlex Zinenko   OwningOpRef<Operation *> op =
134985bb3a2SAlex Zinenko       parseSourceString(withoutPropertiesAttrsSrc, config);
135985bb3a2SAlex Zinenko 
136985bb3a2SAlex Zinenko   std::string bytecode;
137985bb3a2SAlex Zinenko   llvm::raw_string_ostream os(bytecode);
138985bb3a2SAlex Zinenko   ASSERT_TRUE(succeeded(writeBytecodeToFile(op.get(), os)));
139985bb3a2SAlex Zinenko   std::unique_ptr<Block> block = std::make_unique<Block>();
140985bb3a2SAlex Zinenko   ASSERT_TRUE(succeeded(readBytecodeFile(
141ffc80de8SJOE1994       llvm::MemoryBufferRef(bytecode, "string-buffer"), block.get(), config)));
142985bb3a2SAlex Zinenko   Operation *roundtripped = &block->front();
143985bb3a2SAlex Zinenko   EXPECT_EQ(roundtripped->getAttrs().size(), 2u);
144985bb3a2SAlex Zinenko   EXPECT_TRUE(roundtripped->getInherentAttr("inherent_attr") != std::nullopt);
145985bb3a2SAlex Zinenko   EXPECT_TRUE(roundtripped->getDiscardableAttr("other_attr") != Attribute());
146b336ab42SOleksandr "Alex" Zinenko 
147b336ab42SOleksandr "Alex" Zinenko   EXPECT_TRUE(OperationEquivalence::computeHash(op.get()) ==
148b336ab42SOleksandr "Alex" Zinenko               OperationEquivalence::computeHash(roundtripped));
149985bb3a2SAlex Zinenko }
150