13ba14fa0SAlex Zinenko //===- DataLayoutInterfacesTest.cpp - Unit Tests for Data Layouts ---------===//
23ba14fa0SAlex Zinenko //
33ba14fa0SAlex Zinenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43ba14fa0SAlex Zinenko // See https://llvm.org/LICENSE.txt for license information.
53ba14fa0SAlex Zinenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63ba14fa0SAlex Zinenko //
73ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
83ba14fa0SAlex Zinenko 
93ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutInterfaces.h"
103ba14fa0SAlex Zinenko #include "mlir/Dialect/DLTI/DLTI.h"
113ba14fa0SAlex Zinenko #include "mlir/IR/Builders.h"
123ba14fa0SAlex Zinenko #include "mlir/IR/BuiltinOps.h"
133ba14fa0SAlex Zinenko #include "mlir/IR/Dialect.h"
143ba14fa0SAlex Zinenko #include "mlir/IR/DialectImplementation.h"
153ba14fa0SAlex Zinenko #include "mlir/IR/OpDefinition.h"
163ba14fa0SAlex Zinenko #include "mlir/IR/OpImplementation.h"
179eaff423SRiver Riddle #include "mlir/Parser/Parser.h"
183ba14fa0SAlex Zinenko 
193ba14fa0SAlex Zinenko #include <gtest/gtest.h>
203ba14fa0SAlex Zinenko 
213ba14fa0SAlex Zinenko using namespace mlir;
223ba14fa0SAlex Zinenko 
233ba14fa0SAlex Zinenko namespace {
243ba14fa0SAlex Zinenko constexpr static llvm::StringLiteral kAttrName = "dltest.layout";
253ba14fa0SAlex Zinenko 
263ba14fa0SAlex Zinenko /// Trivial array storage for the custom data layout spec attribute, just a list
273ba14fa0SAlex Zinenko /// of entries.
283ba14fa0SAlex Zinenko class DataLayoutSpecStorage : public AttributeStorage {
293ba14fa0SAlex Zinenko public:
303ba14fa0SAlex Zinenko   using KeyTy = ArrayRef<DataLayoutEntryInterface>;
313ba14fa0SAlex Zinenko 
DataLayoutSpecStorage(ArrayRef<DataLayoutEntryInterface> entries)323ba14fa0SAlex Zinenko   DataLayoutSpecStorage(ArrayRef<DataLayoutEntryInterface> entries)
333ba14fa0SAlex Zinenko       : entries(entries) {}
343ba14fa0SAlex Zinenko 
operator ==(const KeyTy & key) const353ba14fa0SAlex Zinenko   bool operator==(const KeyTy &key) const { return key == entries; }
363ba14fa0SAlex Zinenko 
construct(AttributeStorageAllocator & allocator,const KeyTy & key)373ba14fa0SAlex Zinenko   static DataLayoutSpecStorage *construct(AttributeStorageAllocator &allocator,
383ba14fa0SAlex Zinenko                                           const KeyTy &key) {
393ba14fa0SAlex Zinenko     return new (allocator.allocate<DataLayoutSpecStorage>())
403ba14fa0SAlex Zinenko         DataLayoutSpecStorage(allocator.copyInto(key));
413ba14fa0SAlex Zinenko   }
423ba14fa0SAlex Zinenko 
433ba14fa0SAlex Zinenko   ArrayRef<DataLayoutEntryInterface> entries;
443ba14fa0SAlex Zinenko };
453ba14fa0SAlex Zinenko 
463ba14fa0SAlex Zinenko /// Simple data layout spec containing a list of entries that always verifies
473ba14fa0SAlex Zinenko /// as valid.
483ba14fa0SAlex Zinenko struct CustomDataLayoutSpec
493ba14fa0SAlex Zinenko     : public Attribute::AttrBase<CustomDataLayoutSpec, Attribute,
503ba14fa0SAlex Zinenko                                  DataLayoutSpecStorage,
513ba14fa0SAlex Zinenko                                  DataLayoutSpecInterface::Trait> {
525e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CustomDataLayoutSpec)
535e50dd04SRiver Riddle 
543ba14fa0SAlex Zinenko   using Base::Base;
get__anon730820e40111::CustomDataLayoutSpec553ba14fa0SAlex Zinenko   static CustomDataLayoutSpec get(MLIRContext *ctx,
563ba14fa0SAlex Zinenko                                   ArrayRef<DataLayoutEntryInterface> entries) {
573ba14fa0SAlex Zinenko     return Base::get(ctx, entries);
583ba14fa0SAlex Zinenko   }
593ba14fa0SAlex Zinenko   CustomDataLayoutSpec
combineWith__anon730820e40111::CustomDataLayoutSpec603ba14fa0SAlex Zinenko   combineWith(ArrayRef<DataLayoutSpecInterface> specs) const {
613ba14fa0SAlex Zinenko     return *this;
623ba14fa0SAlex Zinenko   }
getEntries__anon730820e40111::CustomDataLayoutSpec633ba14fa0SAlex Zinenko   DataLayoutEntryListRef getEntries() const { return getImpl()->entries; }
verifySpec__anon730820e40111::CustomDataLayoutSpec643ba14fa0SAlex Zinenko   LogicalResult verifySpec(Location loc) { return success(); }
653ba14fa0SAlex Zinenko };
663ba14fa0SAlex Zinenko 
673ba14fa0SAlex Zinenko /// A type subject to data layout that exits the program if it is queried more
683ba14fa0SAlex Zinenko /// than once. Handy to check if the cache works.
693ba14fa0SAlex Zinenko struct SingleQueryType
703ba14fa0SAlex Zinenko     : public Type::TypeBase<SingleQueryType, Type, TypeStorage,
713ba14fa0SAlex Zinenko                             DataLayoutTypeInterface::Trait> {
725e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(SingleQueryType)
735e50dd04SRiver Riddle 
743ba14fa0SAlex Zinenko   using Base::Base;
753ba14fa0SAlex Zinenko 
get__anon730820e40111::SingleQueryType763ba14fa0SAlex Zinenko   static SingleQueryType get(MLIRContext *ctx) { return Base::get(ctx); }
773ba14fa0SAlex Zinenko 
getTypeSizeInBits__anon730820e40111::SingleQueryType78f9cdc61dSAlex Zinenko   unsigned getTypeSizeInBits(const DataLayout &layout,
79f9cdc61dSAlex Zinenko                              DataLayoutEntryListRef params) const {
803ba14fa0SAlex Zinenko     static bool executed = false;
813ba14fa0SAlex Zinenko     if (executed)
823ba14fa0SAlex Zinenko       llvm::report_fatal_error("repeated call");
833ba14fa0SAlex Zinenko 
843ba14fa0SAlex Zinenko     executed = true;
853ba14fa0SAlex Zinenko     return 1;
863ba14fa0SAlex Zinenko   }
873ba14fa0SAlex Zinenko 
getABIAlignment__anon730820e40111::SingleQueryType883ba14fa0SAlex Zinenko   unsigned getABIAlignment(const DataLayout &layout,
893ba14fa0SAlex Zinenko                            DataLayoutEntryListRef params) {
903ba14fa0SAlex Zinenko     static bool executed = false;
913ba14fa0SAlex Zinenko     if (executed)
923ba14fa0SAlex Zinenko       llvm::report_fatal_error("repeated call");
933ba14fa0SAlex Zinenko 
943ba14fa0SAlex Zinenko     executed = true;
953ba14fa0SAlex Zinenko     return 2;
963ba14fa0SAlex Zinenko   }
973ba14fa0SAlex Zinenko 
getPreferredAlignment__anon730820e40111::SingleQueryType983ba14fa0SAlex Zinenko   unsigned getPreferredAlignment(const DataLayout &layout,
993ba14fa0SAlex Zinenko                                  DataLayoutEntryListRef params) {
1003ba14fa0SAlex Zinenko     static bool executed = false;
1013ba14fa0SAlex Zinenko     if (executed)
1023ba14fa0SAlex Zinenko       llvm::report_fatal_error("repeated call");
1033ba14fa0SAlex Zinenko 
1043ba14fa0SAlex Zinenko     executed = true;
1053ba14fa0SAlex Zinenko     return 4;
1063ba14fa0SAlex Zinenko   }
1073ba14fa0SAlex Zinenko };
1083ba14fa0SAlex Zinenko 
1093ba14fa0SAlex Zinenko /// A types that is not subject to data layout.
1103ba14fa0SAlex Zinenko struct TypeNoLayout : public Type::TypeBase<TypeNoLayout, Type, TypeStorage> {
1115e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TypeNoLayout)
1125e50dd04SRiver Riddle 
1133ba14fa0SAlex Zinenko   using Base::Base;
1143ba14fa0SAlex Zinenko 
get__anon730820e40111::TypeNoLayout1153ba14fa0SAlex Zinenko   static TypeNoLayout get(MLIRContext *ctx) { return Base::get(ctx); }
1163ba14fa0SAlex Zinenko };
1173ba14fa0SAlex Zinenko 
1183ba14fa0SAlex Zinenko /// An op that serves as scope for data layout queries with the relevant
1193ba14fa0SAlex Zinenko /// attribute attached. This can handle data layout requests for the built-in
1203ba14fa0SAlex Zinenko /// types itself.
1213ba14fa0SAlex Zinenko struct OpWithLayout : public Op<OpWithLayout, DataLayoutOpInterface::Trait> {
1225e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpWithLayout)
1235e50dd04SRiver Riddle 
1243ba14fa0SAlex Zinenko   using Op::Op;
getAttributeNames__anon730820e40111::OpWithLayout125e4e31e19SRiver Riddle   static ArrayRef<StringRef> getAttributeNames() { return {}; }
1263ba14fa0SAlex Zinenko 
getOperationName__anon730820e40111::OpWithLayout1273ba14fa0SAlex Zinenko   static StringRef getOperationName() { return "dltest.op_with_layout"; }
1283ba14fa0SAlex Zinenko 
getDataLayoutSpec__anon730820e40111::OpWithLayout1293ba14fa0SAlex Zinenko   DataLayoutSpecInterface getDataLayoutSpec() {
1303ba14fa0SAlex Zinenko     return getOperation()->getAttrOfType<DataLayoutSpecInterface>(kAttrName);
1313ba14fa0SAlex Zinenko   }
1323ba14fa0SAlex Zinenko 
getTypeSizeInBits__anon730820e40111::OpWithLayout133f9cdc61dSAlex Zinenko   static unsigned getTypeSizeInBits(Type type, const DataLayout &dataLayout,
1343ba14fa0SAlex Zinenko                                     DataLayoutEntryListRef params) {
1353ba14fa0SAlex Zinenko     // Make a recursive query.
1363ba14fa0SAlex Zinenko     if (type.isa<FloatType>())
137f9cdc61dSAlex Zinenko       return dataLayout.getTypeSizeInBits(
1383ba14fa0SAlex Zinenko           IntegerType::get(type.getContext(), type.getIntOrFloatBitWidth()));
1393ba14fa0SAlex Zinenko 
1403ba14fa0SAlex Zinenko     // Handle built-in types that are not handled by the default process.
1413ba14fa0SAlex Zinenko     if (auto iType = type.dyn_cast<IntegerType>()) {
1423ba14fa0SAlex Zinenko       for (DataLayoutEntryInterface entry : params)
1433ba14fa0SAlex Zinenko         if (entry.getKey().dyn_cast<Type>() == type)
144f9cdc61dSAlex Zinenko           return 8 *
145f9cdc61dSAlex Zinenko                  entry.getValue().cast<IntegerAttr>().getValue().getZExtValue();
146f9cdc61dSAlex Zinenko       return 8 * iType.getIntOrFloatBitWidth();
1473ba14fa0SAlex Zinenko     }
1483ba14fa0SAlex Zinenko 
1493ba14fa0SAlex Zinenko     // Use the default process for everything else.
1503ba14fa0SAlex Zinenko     return detail::getDefaultTypeSize(type, dataLayout, params);
1513ba14fa0SAlex Zinenko   }
1523ba14fa0SAlex Zinenko 
getTypeABIAlignment__anon730820e40111::OpWithLayout1533ba14fa0SAlex Zinenko   static unsigned getTypeABIAlignment(Type type, const DataLayout &dataLayout,
1543ba14fa0SAlex Zinenko                                       DataLayoutEntryListRef params) {
1553ba14fa0SAlex Zinenko     return llvm::PowerOf2Ceil(getTypeSize(type, dataLayout, params));
1563ba14fa0SAlex Zinenko   }
1573ba14fa0SAlex Zinenko 
getTypePreferredAlignment__anon730820e40111::OpWithLayout1583ba14fa0SAlex Zinenko   static unsigned getTypePreferredAlignment(Type type,
1593ba14fa0SAlex Zinenko                                             const DataLayout &dataLayout,
1603ba14fa0SAlex Zinenko                                             DataLayoutEntryListRef params) {
1613ba14fa0SAlex Zinenko     return 2 * getTypeABIAlignment(type, dataLayout, params);
1623ba14fa0SAlex Zinenko   }
1633ba14fa0SAlex Zinenko };
1643ba14fa0SAlex Zinenko 
165f9cdc61dSAlex Zinenko struct OpWith7BitByte
166f9cdc61dSAlex Zinenko     : public Op<OpWith7BitByte, DataLayoutOpInterface::Trait> {
1675e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpWith7BitByte)
1685e50dd04SRiver Riddle 
169f9cdc61dSAlex Zinenko   using Op::Op;
getAttributeNames__anon730820e40111::OpWith7BitByte170e4e31e19SRiver Riddle   static ArrayRef<StringRef> getAttributeNames() { return {}; }
171f9cdc61dSAlex Zinenko 
getOperationName__anon730820e40111::OpWith7BitByte172f9cdc61dSAlex Zinenko   static StringRef getOperationName() { return "dltest.op_with_7bit_byte"; }
173f9cdc61dSAlex Zinenko 
getDataLayoutSpec__anon730820e40111::OpWith7BitByte174f9cdc61dSAlex Zinenko   DataLayoutSpecInterface getDataLayoutSpec() {
175f9cdc61dSAlex Zinenko     return getOperation()->getAttrOfType<DataLayoutSpecInterface>(kAttrName);
176f9cdc61dSAlex Zinenko   }
177f9cdc61dSAlex Zinenko 
178f9cdc61dSAlex Zinenko   // Bytes are assumed to be 7-bit here.
getTypeSize__anon730820e40111::OpWith7BitByte179f9cdc61dSAlex Zinenko   static unsigned getTypeSize(Type type, const DataLayout &dataLayout,
180f9cdc61dSAlex Zinenko                               DataLayoutEntryListRef params) {
181f9cdc61dSAlex Zinenko     return llvm::divideCeil(dataLayout.getTypeSizeInBits(type), 7);
182f9cdc61dSAlex Zinenko   }
183f9cdc61dSAlex Zinenko };
184f9cdc61dSAlex Zinenko 
1853ba14fa0SAlex Zinenko /// A dialect putting all the above together.
1863ba14fa0SAlex Zinenko struct DLTestDialect : Dialect {
1875e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(DLTestDialect)
1885e50dd04SRiver Riddle 
DLTestDialect__anon730820e40111::DLTestDialect1893ba14fa0SAlex Zinenko   explicit DLTestDialect(MLIRContext *ctx)
1903ba14fa0SAlex Zinenko       : Dialect(getDialectNamespace(), ctx, TypeID::get<DLTestDialect>()) {
1913ba14fa0SAlex Zinenko     ctx->getOrLoadDialect<DLTIDialect>();
1923ba14fa0SAlex Zinenko     addAttributes<CustomDataLayoutSpec>();
193f9cdc61dSAlex Zinenko     addOperations<OpWithLayout, OpWith7BitByte>();
1943ba14fa0SAlex Zinenko     addTypes<SingleQueryType, TypeNoLayout>();
1953ba14fa0SAlex Zinenko   }
getDialectNamespace__anon730820e40111::DLTestDialect1963ba14fa0SAlex Zinenko   static StringRef getDialectNamespace() { return "dltest"; }
1973ba14fa0SAlex Zinenko 
printAttribute__anon730820e40111::DLTestDialect1983ba14fa0SAlex Zinenko   void printAttribute(Attribute attr,
1993ba14fa0SAlex Zinenko                       DialectAsmPrinter &printer) const override {
2003ba14fa0SAlex Zinenko     printer << "spec<";
2013ba14fa0SAlex Zinenko     llvm::interleaveComma(attr.cast<CustomDataLayoutSpec>().getEntries(),
2023ba14fa0SAlex Zinenko                           printer);
2033ba14fa0SAlex Zinenko     printer << ">";
2043ba14fa0SAlex Zinenko   }
2053ba14fa0SAlex Zinenko 
parseAttribute__anon730820e40111::DLTestDialect2063ba14fa0SAlex Zinenko   Attribute parseAttribute(DialectAsmParser &parser, Type type) const override {
2073ba14fa0SAlex Zinenko     bool ok =
2083ba14fa0SAlex Zinenko         succeeded(parser.parseKeyword("spec")) && succeeded(parser.parseLess());
2093ba14fa0SAlex Zinenko     (void)ok;
2103ba14fa0SAlex Zinenko     assert(ok);
2113ba14fa0SAlex Zinenko     if (succeeded(parser.parseOptionalGreater()))
212fb093c83SChris Lattner       return CustomDataLayoutSpec::get(parser.getContext(), {});
2133ba14fa0SAlex Zinenko 
2143ba14fa0SAlex Zinenko     SmallVector<DataLayoutEntryInterface> entries;
215*1d7b5cd5SChris Lattner     ok = succeeded(parser.parseCommaSeparatedList([&]() {
2163ba14fa0SAlex Zinenko       entries.emplace_back();
2173ba14fa0SAlex Zinenko       ok = succeeded(parser.parseAttribute(entries.back()));
2183ba14fa0SAlex Zinenko       assert(ok);
219167bbfcbSJakub Tucholski       return success();
220*1d7b5cd5SChris Lattner     }));
221*1d7b5cd5SChris Lattner     assert(ok);
2223ba14fa0SAlex Zinenko     ok = succeeded(parser.parseGreater());
2233ba14fa0SAlex Zinenko     assert(ok);
224fb093c83SChris Lattner     return CustomDataLayoutSpec::get(parser.getContext(), entries);
2253ba14fa0SAlex Zinenko   }
2263ba14fa0SAlex Zinenko 
printType__anon730820e40111::DLTestDialect2273ba14fa0SAlex Zinenko   void printType(Type type, DialectAsmPrinter &printer) const override {
2283ba14fa0SAlex Zinenko     if (type.isa<SingleQueryType>())
2293ba14fa0SAlex Zinenko       printer << "single_query";
2303ba14fa0SAlex Zinenko     else
2313ba14fa0SAlex Zinenko       printer << "no_layout";
2323ba14fa0SAlex Zinenko   }
2333ba14fa0SAlex Zinenko 
parseType__anon730820e40111::DLTestDialect2343ba14fa0SAlex Zinenko   Type parseType(DialectAsmParser &parser) const override {
2353ba14fa0SAlex Zinenko     bool ok = succeeded(parser.parseKeyword("single_query"));
2363ba14fa0SAlex Zinenko     (void)ok;
2373ba14fa0SAlex Zinenko     assert(ok);
238fb093c83SChris Lattner     return SingleQueryType::get(parser.getContext());
2393ba14fa0SAlex Zinenko   }
2403ba14fa0SAlex Zinenko };
2413ba14fa0SAlex Zinenko 
242be0a7e9fSMehdi Amini } // namespace
2433ba14fa0SAlex Zinenko 
TEST(DataLayout,FallbackDefault)2443ba14fa0SAlex Zinenko TEST(DataLayout, FallbackDefault) {
2453ba14fa0SAlex Zinenko   const char *ir = R"MLIR(
246842d2435SAlex Zinenko module {}
247842d2435SAlex Zinenko   )MLIR";
248842d2435SAlex Zinenko 
249842d2435SAlex Zinenko   DialectRegistry registry;
250842d2435SAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
251842d2435SAlex Zinenko   MLIRContext ctx(registry);
252842d2435SAlex Zinenko 
253dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
254842d2435SAlex Zinenko   DataLayout layout(module.get());
255842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 6u);
256842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 2u);
257842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 42u);
258842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 16u);
259842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 8u);
260842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 2u);
261842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 8u);
262842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 2u);
263842d2435SAlex Zinenko }
264842d2435SAlex Zinenko 
TEST(DataLayout,NullSpec)265842d2435SAlex Zinenko TEST(DataLayout, NullSpec) {
266842d2435SAlex Zinenko   const char *ir = R"MLIR(
2673ba14fa0SAlex Zinenko "dltest.op_with_layout"() : () -> ()
2683ba14fa0SAlex Zinenko   )MLIR";
2693ba14fa0SAlex Zinenko 
2703ba14fa0SAlex Zinenko   DialectRegistry registry;
2713ba14fa0SAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
2723ba14fa0SAlex Zinenko   MLIRContext ctx(registry);
2733ba14fa0SAlex Zinenko 
274dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
2753ba14fa0SAlex Zinenko   auto op =
2763ba14fa0SAlex Zinenko       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
2773ba14fa0SAlex Zinenko   DataLayout layout(op);
278842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 42u);
279842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 16u);
280842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 8u * 42u);
281842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 8u * 16u);
282842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 64u);
283842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 16u);
284842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 128u);
285842d2435SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 32u);
2863ba14fa0SAlex Zinenko }
2873ba14fa0SAlex Zinenko 
TEST(DataLayout,EmptySpec)2883ba14fa0SAlex Zinenko TEST(DataLayout, EmptySpec) {
2893ba14fa0SAlex Zinenko   const char *ir = R"MLIR(
2903ba14fa0SAlex Zinenko "dltest.op_with_layout"() { dltest.layout = #dltest.spec< > } : () -> ()
2913ba14fa0SAlex Zinenko   )MLIR";
2923ba14fa0SAlex Zinenko 
2933ba14fa0SAlex Zinenko   DialectRegistry registry;
2943ba14fa0SAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
2953ba14fa0SAlex Zinenko   MLIRContext ctx(registry);
2963ba14fa0SAlex Zinenko 
297dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
2983ba14fa0SAlex Zinenko   auto op =
2993ba14fa0SAlex Zinenko       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
3003ba14fa0SAlex Zinenko   DataLayout layout(op);
3013ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 42u);
3023ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 16u);
303f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 8u * 42u);
304f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 8u * 16u);
3053ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 64u);
3063ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 16u);
3073ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 128u);
3083ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 32u);
3093ba14fa0SAlex Zinenko }
3103ba14fa0SAlex Zinenko 
TEST(DataLayout,SpecWithEntries)3113ba14fa0SAlex Zinenko TEST(DataLayout, SpecWithEntries) {
3123ba14fa0SAlex Zinenko   const char *ir = R"MLIR(
3133ba14fa0SAlex Zinenko "dltest.op_with_layout"() { dltest.layout = #dltest.spec<
3143ba14fa0SAlex Zinenko   #dlti.dl_entry<i42, 5>,
3153ba14fa0SAlex Zinenko   #dlti.dl_entry<i16, 6>
3163ba14fa0SAlex Zinenko > } : () -> ()
3173ba14fa0SAlex Zinenko   )MLIR";
3183ba14fa0SAlex Zinenko 
3193ba14fa0SAlex Zinenko   DialectRegistry registry;
3203ba14fa0SAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
3213ba14fa0SAlex Zinenko   MLIRContext ctx(registry);
3223ba14fa0SAlex Zinenko 
323dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
3243ba14fa0SAlex Zinenko   auto op =
3253ba14fa0SAlex Zinenko       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
3263ba14fa0SAlex Zinenko   DataLayout layout(op);
3273ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 5u);
3283ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 6u);
329f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 40u);
330f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 48u);
3313ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 8u);
3323ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 8u);
3333ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 16u);
3343ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 16u);
3353ba14fa0SAlex Zinenko 
3363ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 32)), 32u);
3373ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(Float32Type::get(&ctx)), 32u);
338f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 32)), 256u);
339f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(Float32Type::get(&ctx)), 256u);
3403ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 32)), 32u);
3413ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeABIAlignment(Float32Type::get(&ctx)), 32u);
3423ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 32)), 64u);
3433ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypePreferredAlignment(Float32Type::get(&ctx)), 64u);
3443ba14fa0SAlex Zinenko }
3453ba14fa0SAlex Zinenko 
TEST(DataLayout,Caching)3463ba14fa0SAlex Zinenko TEST(DataLayout, Caching) {
3473ba14fa0SAlex Zinenko   const char *ir = R"MLIR(
3483ba14fa0SAlex Zinenko "dltest.op_with_layout"() { dltest.layout = #dltest.spec<> } : () -> ()
3493ba14fa0SAlex Zinenko   )MLIR";
3503ba14fa0SAlex Zinenko 
3513ba14fa0SAlex Zinenko   DialectRegistry registry;
3523ba14fa0SAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
3533ba14fa0SAlex Zinenko   MLIRContext ctx(registry);
3543ba14fa0SAlex Zinenko 
355dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
3563ba14fa0SAlex Zinenko   auto op =
3573ba14fa0SAlex Zinenko       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
3583ba14fa0SAlex Zinenko   DataLayout layout(op);
3593ba14fa0SAlex Zinenko 
3603ba14fa0SAlex Zinenko   unsigned sum = 0;
3613ba14fa0SAlex Zinenko   sum += layout.getTypeSize(SingleQueryType::get(&ctx));
3623ba14fa0SAlex Zinenko   // The second call should hit the cache. If it does not, the function in
3633ba14fa0SAlex Zinenko   // SingleQueryType will be called and will abort the process.
3643ba14fa0SAlex Zinenko   sum += layout.getTypeSize(SingleQueryType::get(&ctx));
3653ba14fa0SAlex Zinenko   // Make sure the complier doesn't optimize away the query code.
3663ba14fa0SAlex Zinenko   EXPECT_EQ(sum, 2u);
3673ba14fa0SAlex Zinenko 
3683ba14fa0SAlex Zinenko   // A fresh data layout has a new cache, so the call to it should be dispatched
3693ba14fa0SAlex Zinenko   // down to the type and abort the proces.
3703ba14fa0SAlex Zinenko   DataLayout second(op);
3713ba14fa0SAlex Zinenko   ASSERT_DEATH(second.getTypeSize(SingleQueryType::get(&ctx)), "repeated call");
3723ba14fa0SAlex Zinenko }
3733ba14fa0SAlex Zinenko 
TEST(DataLayout,CacheInvalidation)3743ba14fa0SAlex Zinenko TEST(DataLayout, CacheInvalidation) {
3753ba14fa0SAlex Zinenko   const char *ir = R"MLIR(
3763ba14fa0SAlex Zinenko "dltest.op_with_layout"() { dltest.layout = #dltest.spec<
3773ba14fa0SAlex Zinenko   #dlti.dl_entry<i42, 5>,
3783ba14fa0SAlex Zinenko   #dlti.dl_entry<i16, 6>
3793ba14fa0SAlex Zinenko > } : () -> ()
3803ba14fa0SAlex Zinenko   )MLIR";
3813ba14fa0SAlex Zinenko 
3823ba14fa0SAlex Zinenko   DialectRegistry registry;
3833ba14fa0SAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
3843ba14fa0SAlex Zinenko   MLIRContext ctx(registry);
3853ba14fa0SAlex Zinenko 
386dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
3873ba14fa0SAlex Zinenko   auto op =
3883ba14fa0SAlex Zinenko       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
3893ba14fa0SAlex Zinenko   DataLayout layout(op);
3903ba14fa0SAlex Zinenko 
3913ba14fa0SAlex Zinenko   // Normal query is fine.
3923ba14fa0SAlex Zinenko   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 6u);
3933ba14fa0SAlex Zinenko 
3943ba14fa0SAlex Zinenko   // Replace the data layout spec with a new, empty spec.
3953ba14fa0SAlex Zinenko   op->setAttr(kAttrName, CustomDataLayoutSpec::get(&ctx, {}));
3963ba14fa0SAlex Zinenko 
3973ba14fa0SAlex Zinenko   // Data layout is no longer valid and should trigger assertion when queried.
3983ba14fa0SAlex Zinenko #ifndef NDEBUG
3993ba14fa0SAlex Zinenko   ASSERT_DEATH(layout.getTypeSize(Float16Type::get(&ctx)), "no longer valid");
4003ba14fa0SAlex Zinenko #endif
4013ba14fa0SAlex Zinenko }
4023ba14fa0SAlex Zinenko 
TEST(DataLayout,UnimplementedTypeInterface)4033ba14fa0SAlex Zinenko TEST(DataLayout, UnimplementedTypeInterface) {
4043ba14fa0SAlex Zinenko   const char *ir = R"MLIR(
4053ba14fa0SAlex Zinenko "dltest.op_with_layout"() { dltest.layout = #dltest.spec<> } : () -> ()
4063ba14fa0SAlex Zinenko   )MLIR";
4073ba14fa0SAlex Zinenko 
4083ba14fa0SAlex Zinenko   DialectRegistry registry;
4093ba14fa0SAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
4103ba14fa0SAlex Zinenko   MLIRContext ctx(registry);
4113ba14fa0SAlex Zinenko 
412dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
4133ba14fa0SAlex Zinenko   auto op =
4143ba14fa0SAlex Zinenko       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
4153ba14fa0SAlex Zinenko   DataLayout layout(op);
4163ba14fa0SAlex Zinenko 
4173ba14fa0SAlex Zinenko   ASSERT_DEATH(layout.getTypeSize(TypeNoLayout::get(&ctx)),
4183ba14fa0SAlex Zinenko                "neither the scoping op nor the type class provide data layout "
4193ba14fa0SAlex Zinenko                "information");
4203ba14fa0SAlex Zinenko }
421f9cdc61dSAlex Zinenko 
TEST(DataLayout,SevenBitByte)422f9cdc61dSAlex Zinenko TEST(DataLayout, SevenBitByte) {
423f9cdc61dSAlex Zinenko   const char *ir = R"MLIR(
424f9cdc61dSAlex Zinenko "dltest.op_with_7bit_byte"() { dltest.layout = #dltest.spec<> } : () -> ()
425f9cdc61dSAlex Zinenko   )MLIR";
426f9cdc61dSAlex Zinenko 
427f9cdc61dSAlex Zinenko   DialectRegistry registry;
428f9cdc61dSAlex Zinenko   registry.insert<DLTIDialect, DLTestDialect>();
429f9cdc61dSAlex Zinenko   MLIRContext ctx(registry);
430f9cdc61dSAlex Zinenko 
431dfaadf6bSChristian Sigg   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
432f9cdc61dSAlex Zinenko   auto op =
433f9cdc61dSAlex Zinenko       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
434f9cdc61dSAlex Zinenko   DataLayout layout(op);
435f9cdc61dSAlex Zinenko 
436f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 42u);
437f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 32)), 32u);
438f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 6u);
439f9cdc61dSAlex Zinenko   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 32)), 5u);
440f9cdc61dSAlex Zinenko }
441