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