1 //===- AttributeTest.cpp - Attribute unit tests ---------------------------===//
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/IR/BuiltinAttributes.h"
10 #include "mlir/IR/BuiltinTypes.h"
11 #include "mlir/IR/Identifier.h"
12 #include "gtest/gtest.h"
13 
14 using namespace mlir;
15 using namespace mlir::detail;
16 
17 template <typename EltTy>
18 static void testSplat(Type eltType, const EltTy &splatElt) {
19   RankedTensorType shape = RankedTensorType::get({2, 1}, eltType);
20 
21   // Check that the generated splat is the same for 1 element and N elements.
22   DenseElementsAttr splat = DenseElementsAttr::get(shape, splatElt);
23   EXPECT_TRUE(splat.isSplat());
24 
25   auto detectedSplat =
26       DenseElementsAttr::get(shape, llvm::makeArrayRef({splatElt, splatElt}));
27   EXPECT_EQ(detectedSplat, splat);
28 
29   for (auto newValue : detectedSplat.template getValues<EltTy>())
30     EXPECT_TRUE(newValue == splatElt);
31 }
32 
33 namespace {
34 TEST(DenseSplatTest, BoolSplat) {
35   MLIRContext context;
36   IntegerType boolTy = IntegerType::get(&context, 1);
37   RankedTensorType shape = RankedTensorType::get({2, 2}, boolTy);
38 
39   // Check that splat is automatically detected for boolean values.
40   /// True.
41   DenseElementsAttr trueSplat = DenseElementsAttr::get(shape, true);
42   EXPECT_TRUE(trueSplat.isSplat());
43   /// False.
44   DenseElementsAttr falseSplat = DenseElementsAttr::get(shape, false);
45   EXPECT_TRUE(falseSplat.isSplat());
46   EXPECT_NE(falseSplat, trueSplat);
47 
48   /// Detect and handle splat within 8 elements (bool values are bit-packed).
49   /// True.
50   auto detectedSplat = DenseElementsAttr::get(shape, {true, true, true, true});
51   EXPECT_EQ(detectedSplat, trueSplat);
52   /// False.
53   detectedSplat = DenseElementsAttr::get(shape, {false, false, false, false});
54   EXPECT_EQ(detectedSplat, falseSplat);
55 }
56 
57 TEST(DenseSplatTest, LargeBoolSplat) {
58   constexpr int64_t boolCount = 56;
59 
60   MLIRContext context;
61   IntegerType boolTy = IntegerType::get(&context, 1);
62   RankedTensorType shape = RankedTensorType::get({boolCount}, boolTy);
63 
64   // Check that splat is automatically detected for boolean values.
65   /// True.
66   DenseElementsAttr trueSplat = DenseElementsAttr::get(shape, true);
67   DenseElementsAttr falseSplat = DenseElementsAttr::get(shape, false);
68   EXPECT_TRUE(trueSplat.isSplat());
69   EXPECT_TRUE(falseSplat.isSplat());
70 
71   /// Detect that the large boolean arrays are properly splatted.
72   /// True.
73   SmallVector<bool, 64> trueValues(boolCount, true);
74   auto detectedSplat = DenseElementsAttr::get(shape, trueValues);
75   EXPECT_EQ(detectedSplat, trueSplat);
76   /// False.
77   SmallVector<bool, 64> falseValues(boolCount, false);
78   detectedSplat = DenseElementsAttr::get(shape, falseValues);
79   EXPECT_EQ(detectedSplat, falseSplat);
80 }
81 
82 TEST(DenseSplatTest, BoolNonSplat) {
83   MLIRContext context;
84   IntegerType boolTy = IntegerType::get(&context, 1);
85   RankedTensorType shape = RankedTensorType::get({6}, boolTy);
86 
87   // Check that we properly handle non-splat values.
88   DenseElementsAttr nonSplat =
89       DenseElementsAttr::get(shape, {false, false, true, false, false, true});
90   EXPECT_FALSE(nonSplat.isSplat());
91 }
92 
93 TEST(DenseSplatTest, OddIntSplat) {
94   // Test detecting a splat with an odd(non 8-bit) integer bitwidth.
95   MLIRContext context;
96   constexpr size_t intWidth = 19;
97   IntegerType intTy = IntegerType::get(&context, intWidth);
98   APInt value(intWidth, 10);
99 
100   testSplat(intTy, value);
101 }
102 
103 TEST(DenseSplatTest, Int32Splat) {
104   MLIRContext context;
105   IntegerType intTy = IntegerType::get(&context, 32);
106   int value = 64;
107 
108   testSplat(intTy, value);
109 }
110 
111 TEST(DenseSplatTest, IntAttrSplat) {
112   MLIRContext context;
113   IntegerType intTy = IntegerType::get(&context, 85);
114   Attribute value = IntegerAttr::get(intTy, 109);
115 
116   testSplat(intTy, value);
117 }
118 
119 TEST(DenseSplatTest, F32Splat) {
120   MLIRContext context;
121   FloatType floatTy = FloatType::getF32(&context);
122   float value = 10.0;
123 
124   testSplat(floatTy, value);
125 }
126 
127 TEST(DenseSplatTest, F64Splat) {
128   MLIRContext context;
129   FloatType floatTy = FloatType::getF64(&context);
130   double value = 10.0;
131 
132   testSplat(floatTy, APFloat(value));
133 }
134 
135 TEST(DenseSplatTest, FloatAttrSplat) {
136   MLIRContext context;
137   FloatType floatTy = FloatType::getF32(&context);
138   Attribute value = FloatAttr::get(floatTy, 10.0);
139 
140   testSplat(floatTy, value);
141 }
142 
143 TEST(DenseSplatTest, BF16Splat) {
144   MLIRContext context;
145   FloatType floatTy = FloatType::getBF16(&context);
146   Attribute value = FloatAttr::get(floatTy, 10.0);
147 
148   testSplat(floatTy, value);
149 }
150 
151 TEST(DenseSplatTest, StringSplat) {
152   MLIRContext context;
153   Type stringType =
154       OpaqueType::get(Identifier::get("test", &context), "string");
155   StringRef value = "test-string";
156   testSplat(stringType, value);
157 }
158 
159 TEST(DenseSplatTest, StringAttrSplat) {
160   MLIRContext context;
161   Type stringType =
162       OpaqueType::get(Identifier::get("test", &context), "string");
163   Attribute stringAttr = StringAttr::get("test-string", stringType);
164   testSplat(stringType, stringAttr);
165 }
166 
167 TEST(DenseComplexTest, ComplexFloatSplat) {
168   MLIRContext context;
169   ComplexType complexType = ComplexType::get(FloatType::getF32(&context));
170   std::complex<float> value(10.0, 15.0);
171   testSplat(complexType, value);
172 }
173 
174 TEST(DenseComplexTest, ComplexIntSplat) {
175   MLIRContext context;
176   ComplexType complexType = ComplexType::get(IntegerType::get(&context, 64));
177   std::complex<int64_t> value(10, 15);
178   testSplat(complexType, value);
179 }
180 
181 TEST(DenseComplexTest, ComplexAPFloatSplat) {
182   MLIRContext context;
183   ComplexType complexType = ComplexType::get(FloatType::getF32(&context));
184   std::complex<APFloat> value(APFloat(10.0f), APFloat(15.0f));
185   testSplat(complexType, value);
186 }
187 
188 TEST(DenseComplexTest, ComplexAPIntSplat) {
189   MLIRContext context;
190   ComplexType complexType = ComplexType::get(IntegerType::get(&context, 64));
191   std::complex<APInt> value(APInt(64, 10), APInt(64, 15));
192   testSplat(complexType, value);
193 }
194 
195 TEST(DenseScalarTest, ExtractZeroRankElement) {
196   MLIRContext context;
197   const int elementValue = 12;
198   IntegerType intTy = IntegerType::get(&context, 32);
199   Attribute value = IntegerAttr::get(intTy, elementValue);
200   RankedTensorType shape = RankedTensorType::get({}, intTy);
201 
202   auto attr = DenseElementsAttr::get(shape, llvm::makeArrayRef({elementValue}));
203   EXPECT_TRUE(attr.getValue({0}) == value);
204 }
205 
206 } // end namespace
207