xref: /llvm-project/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp (revision a2acf3132334e3131ec584c2c54ec5ba2214e074)
1 //===- DataLayoutInterfacesTest.cpp - Unit Tests for Data Layouts ---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "mlir/Interfaces/DataLayoutInterfaces.h"
10 #include "mlir/Dialect/DLTI/DLTI.h"
11 #include "mlir/IR/Builders.h"
12 #include "mlir/IR/BuiltinOps.h"
13 #include "mlir/IR/Dialect.h"
14 #include "mlir/IR/DialectImplementation.h"
15 #include "mlir/IR/OpDefinition.h"
16 #include "mlir/IR/OpImplementation.h"
17 #include "mlir/Parser/Parser.h"
18 
19 #include <gtest/gtest.h>
20 
21 using namespace mlir;
22 
23 namespace {
24 constexpr static llvm::StringLiteral kAttrName = "dltest.layout";
25 constexpr static llvm::StringLiteral kEndiannesKeyName = "dltest.endianness";
26 constexpr static llvm::StringLiteral kAllocaKeyName =
27     "dltest.alloca_memory_space";
28 constexpr static llvm::StringLiteral kProgramKeyName =
29     "dltest.program_memory_space";
30 constexpr static llvm::StringLiteral kGlobalKeyName =
31     "dltest.global_memory_space";
32 constexpr static llvm::StringLiteral kStackAlignmentKeyName =
33     "dltest.stack_alignment";
34 
35 /// Trivial array storage for the custom data layout spec attribute, just a list
36 /// of entries.
37 class DataLayoutSpecStorage : public AttributeStorage {
38 public:
39   using KeyTy = ArrayRef<DataLayoutEntryInterface>;
40 
41   DataLayoutSpecStorage(ArrayRef<DataLayoutEntryInterface> entries)
42       : entries(entries) {}
43 
44   bool operator==(const KeyTy &key) const { return key == entries; }
45 
46   static DataLayoutSpecStorage *construct(AttributeStorageAllocator &allocator,
47                                           const KeyTy &key) {
48     return new (allocator.allocate<DataLayoutSpecStorage>())
49         DataLayoutSpecStorage(allocator.copyInto(key));
50   }
51 
52   ArrayRef<DataLayoutEntryInterface> entries;
53 };
54 
55 /// Simple data layout spec containing a list of entries that always verifies
56 /// as valid.
57 struct CustomDataLayoutSpec
58     : public Attribute::AttrBase<CustomDataLayoutSpec, Attribute,
59                                  DataLayoutSpecStorage,
60                                  DataLayoutSpecInterface::Trait> {
61   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CustomDataLayoutSpec)
62 
63   using Base::Base;
64 
65   static constexpr StringLiteral name = "test.custom_data_layout_spec";
66 
67   static CustomDataLayoutSpec get(MLIRContext *ctx,
68                                   ArrayRef<DataLayoutEntryInterface> entries) {
69     return Base::get(ctx, entries);
70   }
71   CustomDataLayoutSpec
72   combineWith(ArrayRef<DataLayoutSpecInterface> specs) const {
73     return *this;
74   }
75   DataLayoutEntryListRef getEntries() const { return getImpl()->entries; }
76   LogicalResult verifySpec(Location loc) { return success(); }
77   StringAttr getEndiannessIdentifier(MLIRContext *context) const {
78     return Builder(context).getStringAttr(kEndiannesKeyName);
79   }
80   StringAttr getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
81     return Builder(context).getStringAttr(kAllocaKeyName);
82   }
83   StringAttr getProgramMemorySpaceIdentifier(MLIRContext *context) const {
84     return Builder(context).getStringAttr(kProgramKeyName);
85   }
86   StringAttr getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
87     return Builder(context).getStringAttr(kGlobalKeyName);
88   }
89   StringAttr getStackAlignmentIdentifier(MLIRContext *context) const {
90     return Builder(context).getStringAttr(kStackAlignmentKeyName);
91   }
92 };
93 
94 /// A type subject to data layout that exits the program if it is queried more
95 /// than once. Handy to check if the cache works.
96 struct SingleQueryType
97     : public Type::TypeBase<SingleQueryType, Type, TypeStorage,
98                             DataLayoutTypeInterface::Trait> {
99   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(SingleQueryType)
100 
101   using Base::Base;
102 
103   static constexpr StringLiteral name = "test.single_query";
104 
105   static SingleQueryType get(MLIRContext *ctx) { return Base::get(ctx); }
106 
107   llvm::TypeSize getTypeSizeInBits(const DataLayout &layout,
108                                    DataLayoutEntryListRef params) const {
109     static bool executed = false;
110     if (executed)
111       llvm::report_fatal_error("repeated call");
112 
113     executed = true;
114     return llvm::TypeSize::getFixed(1);
115   }
116 
117   uint64_t getABIAlignment(const DataLayout &layout,
118                            DataLayoutEntryListRef params) {
119     static bool executed = false;
120     if (executed)
121       llvm::report_fatal_error("repeated call");
122 
123     executed = true;
124     return 2;
125   }
126 
127   uint64_t getPreferredAlignment(const DataLayout &layout,
128                                  DataLayoutEntryListRef params) {
129     static bool executed = false;
130     if (executed)
131       llvm::report_fatal_error("repeated call");
132 
133     executed = true;
134     return 4;
135   }
136 
137   Attribute getEndianness(DataLayoutEntryInterface entry) {
138     static bool executed = false;
139     if (executed)
140       llvm::report_fatal_error("repeated call");
141 
142     executed = true;
143     return Attribute();
144   }
145 
146   Attribute getAllocaMemorySpace(DataLayoutEntryInterface entry) {
147     static bool executed = false;
148     if (executed)
149       llvm::report_fatal_error("repeated call");
150 
151     executed = true;
152     return Attribute();
153   }
154 
155   Attribute getProgramMemorySpace(DataLayoutEntryInterface entry) {
156     static bool executed = false;
157     if (executed)
158       llvm::report_fatal_error("repeated call");
159 
160     executed = true;
161     return Attribute();
162   }
163 
164   Attribute getGlobalMemorySpace(DataLayoutEntryInterface entry) {
165     static bool executed = false;
166     if (executed)
167       llvm::report_fatal_error("repeated call");
168 
169     executed = true;
170     return Attribute();
171   }
172 };
173 
174 /// A types that is not subject to data layout.
175 struct TypeNoLayout : public Type::TypeBase<TypeNoLayout, Type, TypeStorage> {
176   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TypeNoLayout)
177 
178   using Base::Base;
179 
180   static constexpr StringLiteral name = "test.no_layout";
181 
182   static TypeNoLayout get(MLIRContext *ctx) { return Base::get(ctx); }
183 };
184 
185 /// An op that serves as scope for data layout queries with the relevant
186 /// attribute attached. This can handle data layout requests for the built-in
187 /// types itself.
188 struct OpWithLayout : public Op<OpWithLayout, DataLayoutOpInterface::Trait> {
189   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpWithLayout)
190 
191   using Op::Op;
192   static ArrayRef<StringRef> getAttributeNames() { return {}; }
193 
194   static StringRef getOperationName() { return "dltest.op_with_layout"; }
195 
196   DataLayoutSpecInterface getDataLayoutSpec() {
197     return getOperation()->getAttrOfType<DataLayoutSpecInterface>(kAttrName);
198   }
199 
200   static llvm::TypeSize getTypeSizeInBits(Type type,
201                                           const DataLayout &dataLayout,
202                                           DataLayoutEntryListRef params) {
203     // Make a recursive query.
204     if (isa<FloatType>(type))
205       return dataLayout.getTypeSizeInBits(
206           IntegerType::get(type.getContext(), type.getIntOrFloatBitWidth()));
207 
208     // Handle built-in types that are not handled by the default process.
209     if (auto iType = dyn_cast<IntegerType>(type)) {
210       for (DataLayoutEntryInterface entry : params)
211         if (llvm::dyn_cast_if_present<Type>(entry.getKey()) == type)
212           return llvm::TypeSize::getFixed(
213               8 *
214               cast<IntegerAttr>(entry.getValue()).getValue().getZExtValue());
215       return llvm::TypeSize::getFixed(8 * iType.getIntOrFloatBitWidth());
216     }
217 
218     // Use the default process for everything else.
219     return detail::getDefaultTypeSize(type, dataLayout, params);
220   }
221 
222   static uint64_t getTypeABIAlignment(Type type, const DataLayout &dataLayout,
223                                       DataLayoutEntryListRef params) {
224     return llvm::PowerOf2Ceil(getTypeSize(type, dataLayout, params));
225   }
226 
227   static uint64_t getTypePreferredAlignment(Type type,
228                                             const DataLayout &dataLayout,
229                                             DataLayoutEntryListRef params) {
230     return 2 * getTypeABIAlignment(type, dataLayout, params);
231   }
232 };
233 
234 struct OpWith7BitByte
235     : public Op<OpWith7BitByte, DataLayoutOpInterface::Trait> {
236   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpWith7BitByte)
237 
238   using Op::Op;
239   static ArrayRef<StringRef> getAttributeNames() { return {}; }
240 
241   static StringRef getOperationName() { return "dltest.op_with_7bit_byte"; }
242 
243   DataLayoutSpecInterface getDataLayoutSpec() {
244     return getOperation()->getAttrOfType<DataLayoutSpecInterface>(kAttrName);
245   }
246 
247   // Bytes are assumed to be 7-bit here.
248   static llvm::TypeSize getTypeSize(Type type, const DataLayout &dataLayout,
249                                     DataLayoutEntryListRef params) {
250     return mlir::detail::divideCeil(dataLayout.getTypeSizeInBits(type), 7);
251   }
252 };
253 
254 /// A dialect putting all the above together.
255 struct DLTestDialect : Dialect {
256   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(DLTestDialect)
257 
258   explicit DLTestDialect(MLIRContext *ctx)
259       : Dialect(getDialectNamespace(), ctx, TypeID::get<DLTestDialect>()) {
260     ctx->getOrLoadDialect<DLTIDialect>();
261     addAttributes<CustomDataLayoutSpec>();
262     addOperations<OpWithLayout, OpWith7BitByte>();
263     addTypes<SingleQueryType, TypeNoLayout>();
264   }
265   static StringRef getDialectNamespace() { return "dltest"; }
266 
267   void printAttribute(Attribute attr,
268                       DialectAsmPrinter &printer) const override {
269     printer << "spec<";
270     llvm::interleaveComma(cast<CustomDataLayoutSpec>(attr).getEntries(),
271                           printer);
272     printer << ">";
273   }
274 
275   Attribute parseAttribute(DialectAsmParser &parser, Type type) const override {
276     bool ok =
277         succeeded(parser.parseKeyword("spec")) && succeeded(parser.parseLess());
278     (void)ok;
279     assert(ok);
280     if (succeeded(parser.parseOptionalGreater()))
281       return CustomDataLayoutSpec::get(parser.getContext(), {});
282 
283     SmallVector<DataLayoutEntryInterface> entries;
284     ok = succeeded(parser.parseCommaSeparatedList([&]() {
285       entries.emplace_back();
286       ok = succeeded(parser.parseAttribute(entries.back()));
287       assert(ok);
288       return success();
289     }));
290     assert(ok);
291     ok = succeeded(parser.parseGreater());
292     assert(ok);
293     return CustomDataLayoutSpec::get(parser.getContext(), entries);
294   }
295 
296   void printType(Type type, DialectAsmPrinter &printer) const override {
297     if (isa<SingleQueryType>(type))
298       printer << "single_query";
299     else
300       printer << "no_layout";
301   }
302 
303   Type parseType(DialectAsmParser &parser) const override {
304     bool ok = succeeded(parser.parseKeyword("single_query"));
305     (void)ok;
306     assert(ok);
307     return SingleQueryType::get(parser.getContext());
308   }
309 };
310 
311 } // namespace
312 
313 TEST(DataLayout, FallbackDefault) {
314   const char *ir = R"MLIR(
315 module {}
316   )MLIR";
317 
318   DialectRegistry registry;
319   registry.insert<DLTIDialect, DLTestDialect>();
320   MLIRContext ctx(registry);
321 
322   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
323   DataLayout layout(module.get());
324   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 6u);
325   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 2u);
326   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 42u);
327   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 16u);
328   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 8u);
329   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 2u);
330   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 8u);
331   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 2u);
332 
333   EXPECT_EQ(layout.getEndianness(), Attribute());
334   EXPECT_EQ(layout.getAllocaMemorySpace(), Attribute());
335   EXPECT_EQ(layout.getProgramMemorySpace(), Attribute());
336   EXPECT_EQ(layout.getGlobalMemorySpace(), Attribute());
337   EXPECT_EQ(layout.getStackAlignment(), 0u);
338 }
339 
340 TEST(DataLayout, NullSpec) {
341   const char *ir = R"MLIR(
342 "dltest.op_with_layout"() : () -> ()
343   )MLIR";
344 
345   DialectRegistry registry;
346   registry.insert<DLTIDialect, DLTestDialect>();
347   MLIRContext ctx(registry);
348 
349   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
350   auto op =
351       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
352   DataLayout layout(op);
353 
354   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 42u);
355   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 16u);
356   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 8u * 42u);
357   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 8u * 16u);
358   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 64u);
359   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 16u);
360   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 128u);
361   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 32u);
362   EXPECT_EQ(layout.getTypeIndexBitwidth(Float16Type::get(&ctx)), std::nullopt);
363   EXPECT_EQ(layout.getTypeIndexBitwidth(IndexType::get(&ctx)), 64u);
364 
365   EXPECT_EQ(layout.getEndianness(), Attribute());
366   EXPECT_EQ(layout.getAllocaMemorySpace(), Attribute());
367   EXPECT_EQ(layout.getProgramMemorySpace(), Attribute());
368   EXPECT_EQ(layout.getGlobalMemorySpace(), Attribute());
369   EXPECT_EQ(layout.getStackAlignment(), 0u);
370 }
371 
372 TEST(DataLayout, EmptySpec) {
373   const char *ir = R"MLIR(
374 "dltest.op_with_layout"() { dltest.layout = #dltest.spec< > } : () -> ()
375   )MLIR";
376 
377   DialectRegistry registry;
378   registry.insert<DLTIDialect, DLTestDialect>();
379   MLIRContext ctx(registry);
380 
381   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
382   auto op =
383       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
384   DataLayout layout(op);
385   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 42u);
386   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 16u);
387   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 8u * 42u);
388   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 8u * 16u);
389   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 64u);
390   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 16u);
391   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 128u);
392   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 32u);
393   EXPECT_EQ(layout.getTypeIndexBitwidth(Float16Type::get(&ctx)), std::nullopt);
394   EXPECT_EQ(layout.getTypeIndexBitwidth(IndexType::get(&ctx)), 64u);
395 
396   EXPECT_EQ(layout.getEndianness(), Attribute());
397   EXPECT_EQ(layout.getAllocaMemorySpace(), Attribute());
398   EXPECT_EQ(layout.getProgramMemorySpace(), Attribute());
399   EXPECT_EQ(layout.getGlobalMemorySpace(), Attribute());
400   EXPECT_EQ(layout.getStackAlignment(), 0u);
401 }
402 
403 TEST(DataLayout, SpecWithEntries) {
404   const char *ir = R"MLIR(
405 "dltest.op_with_layout"() { dltest.layout = #dltest.spec<
406   #dlti.dl_entry<i42, 5>,
407   #dlti.dl_entry<i16, 6>,
408   #dlti.dl_entry<index, 42>,
409   #dlti.dl_entry<"dltest.endianness", "little">,
410   #dlti.dl_entry<"dltest.alloca_memory_space", 5 : i32>,
411   #dlti.dl_entry<"dltest.program_memory_space", 3 : i32>,
412   #dlti.dl_entry<"dltest.global_memory_space", 2 : i32>,
413   #dlti.dl_entry<"dltest.stack_alignment", 128 : i32>
414 > } : () -> ()
415   )MLIR";
416 
417   DialectRegistry registry;
418   registry.insert<DLTIDialect, DLTestDialect>();
419   MLIRContext ctx(registry);
420 
421   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
422   auto op =
423       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
424   DataLayout layout(op);
425   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 5u);
426   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 6u);
427   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 40u);
428   EXPECT_EQ(layout.getTypeSizeInBits(Float16Type::get(&ctx)), 48u);
429   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 42)), 8u);
430   EXPECT_EQ(layout.getTypeABIAlignment(Float16Type::get(&ctx)), 8u);
431   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 42)), 16u);
432   EXPECT_EQ(layout.getTypePreferredAlignment(Float16Type::get(&ctx)), 16u);
433   EXPECT_EQ(layout.getTypeIndexBitwidth(Float16Type::get(&ctx)), std::nullopt);
434   EXPECT_EQ(layout.getTypeIndexBitwidth(IndexType::get(&ctx)), 42u);
435 
436   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 32)), 32u);
437   EXPECT_EQ(layout.getTypeSize(Float32Type::get(&ctx)), 32u);
438   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 32)), 256u);
439   EXPECT_EQ(layout.getTypeSizeInBits(Float32Type::get(&ctx)), 256u);
440   EXPECT_EQ(layout.getTypeABIAlignment(IntegerType::get(&ctx, 32)), 32u);
441   EXPECT_EQ(layout.getTypeABIAlignment(Float32Type::get(&ctx)), 32u);
442   EXPECT_EQ(layout.getTypePreferredAlignment(IntegerType::get(&ctx, 32)), 64u);
443   EXPECT_EQ(layout.getTypePreferredAlignment(Float32Type::get(&ctx)), 64u);
444 
445   EXPECT_EQ(layout.getEndianness(), Builder(&ctx).getStringAttr("little"));
446   EXPECT_EQ(layout.getAllocaMemorySpace(), Builder(&ctx).getI32IntegerAttr(5));
447   EXPECT_EQ(layout.getProgramMemorySpace(), Builder(&ctx).getI32IntegerAttr(3));
448   EXPECT_EQ(layout.getGlobalMemorySpace(), Builder(&ctx).getI32IntegerAttr(2));
449   EXPECT_EQ(layout.getStackAlignment(), 128u);
450 }
451 
452 TEST(DataLayout, Caching) {
453   const char *ir = R"MLIR(
454 "dltest.op_with_layout"() { dltest.layout = #dltest.spec<> } : () -> ()
455   )MLIR";
456 
457   DialectRegistry registry;
458   registry.insert<DLTIDialect, DLTestDialect>();
459   MLIRContext ctx(registry);
460 
461   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
462   auto op =
463       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
464   DataLayout layout(op);
465 
466   unsigned sum = 0;
467   sum += layout.getTypeSize(SingleQueryType::get(&ctx));
468   // The second call should hit the cache. If it does not, the function in
469   // SingleQueryType will be called and will abort the process.
470   sum += layout.getTypeSize(SingleQueryType::get(&ctx));
471   // Make sure the complier doesn't optimize away the query code.
472   EXPECT_EQ(sum, 2u);
473 
474   // A fresh data layout has a new cache, so the call to it should be dispatched
475   // down to the type and abort the process.
476   DataLayout second(op);
477   ASSERT_DEATH(second.getTypeSize(SingleQueryType::get(&ctx)), "repeated call");
478 }
479 
480 TEST(DataLayout, CacheInvalidation) {
481   const char *ir = R"MLIR(
482 "dltest.op_with_layout"() { dltest.layout = #dltest.spec<
483   #dlti.dl_entry<i42, 5>,
484   #dlti.dl_entry<i16, 6>
485 > } : () -> ()
486   )MLIR";
487 
488   DialectRegistry registry;
489   registry.insert<DLTIDialect, DLTestDialect>();
490   MLIRContext ctx(registry);
491 
492   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
493   auto op =
494       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
495   DataLayout layout(op);
496 
497   // Normal query is fine.
498   EXPECT_EQ(layout.getTypeSize(Float16Type::get(&ctx)), 6u);
499 
500   // Replace the data layout spec with a new, empty spec.
501   op->setAttr(kAttrName, CustomDataLayoutSpec::get(&ctx, {}));
502 
503   // Data layout is no longer valid and should trigger assertion when queried.
504 #ifndef NDEBUG
505   ASSERT_DEATH(layout.getTypeSize(Float16Type::get(&ctx)), "no longer valid");
506 #endif
507 }
508 
509 TEST(DataLayout, UnimplementedTypeInterface) {
510   const char *ir = R"MLIR(
511 "dltest.op_with_layout"() { dltest.layout = #dltest.spec<> } : () -> ()
512   )MLIR";
513 
514   DialectRegistry registry;
515   registry.insert<DLTIDialect, DLTestDialect>();
516   MLIRContext ctx(registry);
517 
518   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
519   auto op =
520       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
521   DataLayout layout(op);
522 
523   ASSERT_DEATH(layout.getTypeSize(TypeNoLayout::get(&ctx)),
524                "neither the scoping op nor the type class provide data layout "
525                "information");
526 }
527 
528 TEST(DataLayout, SevenBitByte) {
529   const char *ir = R"MLIR(
530 "dltest.op_with_7bit_byte"() { dltest.layout = #dltest.spec<> } : () -> ()
531   )MLIR";
532 
533   DialectRegistry registry;
534   registry.insert<DLTIDialect, DLTestDialect>();
535   MLIRContext ctx(registry);
536 
537   OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
538   auto op =
539       cast<DataLayoutOpInterface>(module->getBody()->getOperations().front());
540   DataLayout layout(op);
541 
542   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 42)), 42u);
543   EXPECT_EQ(layout.getTypeSizeInBits(IntegerType::get(&ctx, 32)), 32u);
544   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 42)), 6u);
545   EXPECT_EQ(layout.getTypeSize(IntegerType::get(&ctx, 32)), 5u);
546 }
547