1 | //===-------- llvm/unittest/CodeGen/ScalableVectorMVTsTest.cpp ------------===// |
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 "llvm/CodeGen/ValueTypes.h" |
10 | #include "llvm/CodeGenTypes/MachineValueType.h" |
11 | #include "llvm/IR/DerivedTypes.h" |
12 | #include "llvm/IR/LLVMContext.h" |
13 | #include "llvm/Support/TypeSize.h" |
14 | #include "gtest/gtest.h" |
15 | |
16 | using namespace llvm; |
17 | |
18 | namespace { |
19 | |
20 | TEST(ScalableVectorMVTsTest, IntegerMVTs) { |
21 | for (MVT VecTy : MVT::integer_scalable_vector_valuetypes()) { |
22 | ASSERT_TRUE(VecTy.isValid()); |
23 | ASSERT_TRUE(VecTy.isInteger()); |
24 | ASSERT_TRUE(VecTy.isVector()); |
25 | ASSERT_TRUE(VecTy.isScalableVector()); |
26 | ASSERT_TRUE(VecTy.getScalarType().isValid()); |
27 | |
28 | ASSERT_FALSE(VecTy.isFloatingPoint()); |
29 | } |
30 | } |
31 | |
32 | TEST(ScalableVectorMVTsTest, FloatMVTs) { |
33 | for (MVT VecTy : MVT::fp_scalable_vector_valuetypes()) { |
34 | ASSERT_TRUE(VecTy.isValid()); |
35 | ASSERT_TRUE(VecTy.isFloatingPoint()); |
36 | ASSERT_TRUE(VecTy.isVector()); |
37 | ASSERT_TRUE(VecTy.isScalableVector()); |
38 | ASSERT_TRUE(VecTy.getScalarType().isValid()); |
39 | |
40 | ASSERT_FALSE(VecTy.isInteger()); |
41 | } |
42 | } |
43 | |
44 | TEST(ScalableVectorMVTsTest, HelperFuncs) { |
45 | LLVMContext Ctx; |
46 | |
47 | // Create with scalable flag |
48 | EVT Vnx4i32 = EVT::getVectorVT(Ctx, MVT::i32, 4, /*Scalable=*/true); |
49 | ASSERT_TRUE(Vnx4i32.isScalableVector()); |
50 | |
51 | // Create with separate llvm::ElementCount |
52 | auto EltCnt = ElementCount::getScalable(MinVal: 2); |
53 | EVT Vnx2i32 = EVT::getVectorVT(Ctx, MVT::i32, EltCnt); |
54 | ASSERT_TRUE(Vnx2i32.isScalableVector()); |
55 | |
56 | // Create with inline llvm::ElementCount |
57 | EVT Vnx2i64 = EVT::getVectorVT(Ctx, MVT::i64, ElementCount::getScalable(MinVal: 2)); |
58 | ASSERT_TRUE(Vnx2i64.isScalableVector()); |
59 | |
60 | // Check that changing scalar types/element count works |
61 | EXPECT_EQ(Vnx2i32.widenIntegerVectorElementType(Ctx), Vnx2i64); |
62 | EXPECT_EQ(Vnx4i32.getHalfNumVectorElementsVT(Ctx), Vnx2i32); |
63 | |
64 | // Check that operators work |
65 | EXPECT_EQ(EVT::getVectorVT(Ctx, MVT::i64, EltCnt * 2), MVT::nxv4i64); |
66 | EXPECT_EQ(EVT::getVectorVT(Ctx, MVT::i64, EltCnt.divideCoefficientBy(2)), |
67 | MVT::nxv1i64); |
68 | |
69 | // Check that float->int conversion works |
70 | EVT Vnx2f64 = EVT::getVectorVT(Ctx, MVT::f64, ElementCount::getScalable(MinVal: 2)); |
71 | EXPECT_EQ(Vnx2f64.changeTypeToInteger(), Vnx2i64); |
72 | |
73 | // Check fields inside llvm::ElementCount |
74 | EltCnt = Vnx4i32.getVectorElementCount(); |
75 | EXPECT_EQ(EltCnt.getKnownMinValue(), 4U); |
76 | ASSERT_TRUE(EltCnt.isScalable()); |
77 | |
78 | // Check that fixed-length vector types aren't scalable. |
79 | EVT V8i32 = EVT::getVectorVT(Ctx, MVT::i32, 8); |
80 | ASSERT_FALSE(V8i32.isScalableVector()); |
81 | EVT V4f64 = EVT::getVectorVT(Ctx, MVT::f64, ElementCount::getFixed(MinVal: 4)); |
82 | ASSERT_FALSE(V4f64.isScalableVector()); |
83 | |
84 | // Check that llvm::ElementCount works for fixed-length types. |
85 | EltCnt = V8i32.getVectorElementCount(); |
86 | EXPECT_EQ(EltCnt.getKnownMinValue(), 8U); |
87 | ASSERT_FALSE(EltCnt.isScalable()); |
88 | } |
89 | |
90 | TEST(ScalableVectorMVTsTest, IRToVTTranslation) { |
91 | LLVMContext Ctx; |
92 | |
93 | Type *Int64Ty = Type::getInt64Ty(C&: Ctx); |
94 | VectorType *ScV8Int64Ty = |
95 | VectorType::get(ElementType: Int64Ty, EC: ElementCount::getScalable(MinVal: 8)); |
96 | |
97 | // Check that we can map a scalable IR type to an MVT |
98 | MVT Mnxv8i64 = MVT::getVT(Ty: ScV8Int64Ty); |
99 | ASSERT_TRUE(Mnxv8i64.isScalableVector()); |
100 | ASSERT_EQ(ScV8Int64Ty->getElementCount(), Mnxv8i64.getVectorElementCount()); |
101 | ASSERT_EQ(MVT::getVT(ScV8Int64Ty->getElementType()), |
102 | Mnxv8i64.getScalarType()); |
103 | |
104 | // Check that we can map a scalable IR type to an EVT |
105 | EVT Enxv8i64 = EVT::getEVT(Ty: ScV8Int64Ty); |
106 | ASSERT_TRUE(Enxv8i64.isScalableVector()); |
107 | ASSERT_EQ(ScV8Int64Ty->getElementCount(), Enxv8i64.getVectorElementCount()); |
108 | ASSERT_EQ(EVT::getEVT(ScV8Int64Ty->getElementType()), |
109 | Enxv8i64.getScalarType()); |
110 | } |
111 | |
112 | TEST(ScalableVectorMVTsTest, VTToIRTranslation) { |
113 | LLVMContext Ctx; |
114 | |
115 | EVT Enxv4f64 = EVT::getVectorVT(Ctx, MVT::f64, ElementCount::getScalable(MinVal: 4)); |
116 | |
117 | Type *Ty = Enxv4f64.getTypeForEVT(Context&: Ctx); |
118 | VectorType *ScV4Float64Ty = cast<VectorType>(Val: Ty); |
119 | ASSERT_TRUE(isa<ScalableVectorType>(ScV4Float64Ty)); |
120 | ASSERT_EQ(Enxv4f64.getVectorElementCount(), ScV4Float64Ty->getElementCount()); |
121 | ASSERT_EQ(Enxv4f64.getScalarType().getTypeForEVT(Ctx), |
122 | ScV4Float64Ty->getElementType()); |
123 | } |
124 | |
125 | TEST(ScalableVectorMVTsTest, SizeQueries) { |
126 | LLVMContext Ctx; |
127 | |
128 | EVT nxv4i32 = EVT::getVectorVT(Ctx, MVT::i32, 4, /*Scalable=*/ true); |
129 | EVT nxv2i32 = EVT::getVectorVT(Ctx, MVT::i32, 2, /*Scalable=*/ true); |
130 | EVT nxv2i64 = EVT::getVectorVT(Ctx, MVT::i64, 2, /*Scalable=*/ true); |
131 | EVT nxv2f64 = EVT::getVectorVT(Ctx, MVT::f64, 2, /*Scalable=*/ true); |
132 | |
133 | EVT v4i32 = EVT::getVectorVT(Ctx, MVT::i32, 4); |
134 | EVT v2i32 = EVT::getVectorVT(Ctx, MVT::i32, 2); |
135 | EVT v2i64 = EVT::getVectorVT(Ctx, MVT::i64, 2); |
136 | EVT v2f64 = EVT::getVectorVT(Ctx, MVT::f64, 2); |
137 | |
138 | EVT nxv5i32 = EVT::getVectorVT(Ctx, MVT::i32, 5, /*Scalable=*/true); |
139 | ASSERT_FALSE(nxv5i32.is16BitVector()); |
140 | ASSERT_FALSE(nxv5i32.is32BitVector()); |
141 | ASSERT_FALSE(nxv5i32.is64BitVector()); |
142 | ASSERT_FALSE(nxv5i32.is128BitVector()); |
143 | ASSERT_FALSE(nxv5i32.is256BitVector()); |
144 | ASSERT_FALSE(nxv5i32.is512BitVector()); |
145 | ASSERT_FALSE(nxv5i32.is1024BitVector()); |
146 | ASSERT_FALSE(nxv5i32.is2048BitVector()); |
147 | |
148 | // Check equivalence and ordering on scalable types. |
149 | EXPECT_EQ(nxv4i32.getSizeInBits(), nxv2i64.getSizeInBits()); |
150 | EXPECT_EQ(nxv2f64.getSizeInBits(), nxv2i64.getSizeInBits()); |
151 | EXPECT_NE(nxv2i32.getSizeInBits(), nxv4i32.getSizeInBits()); |
152 | EXPECT_LT(nxv2i32.getSizeInBits().getKnownMinValue(), |
153 | nxv2i64.getSizeInBits().getKnownMinValue()); |
154 | EXPECT_LE(nxv4i32.getSizeInBits().getKnownMinValue(), |
155 | nxv2i64.getSizeInBits().getKnownMinValue()); |
156 | EXPECT_GT(nxv4i32.getSizeInBits().getKnownMinValue(), |
157 | nxv2i32.getSizeInBits().getKnownMinValue()); |
158 | EXPECT_GE(nxv2i64.getSizeInBits().getKnownMinValue(), |
159 | nxv4i32.getSizeInBits().getKnownMinValue()); |
160 | |
161 | // Check equivalence and ordering on fixed types. |
162 | EXPECT_EQ(v4i32.getSizeInBits(), v2i64.getSizeInBits()); |
163 | EXPECT_EQ(v2f64.getSizeInBits(), v2i64.getSizeInBits()); |
164 | EXPECT_NE(v2i32.getSizeInBits(), v4i32.getSizeInBits()); |
165 | EXPECT_LT(v2i32.getFixedSizeInBits(), v2i64.getFixedSizeInBits()); |
166 | EXPECT_LE(v4i32.getFixedSizeInBits(), v2i64.getFixedSizeInBits()); |
167 | EXPECT_GT(v4i32.getFixedSizeInBits(), v2i32.getFixedSizeInBits()); |
168 | EXPECT_GE(v2i64.getFixedSizeInBits(), v4i32.getFixedSizeInBits()); |
169 | |
170 | // Check that scalable and non-scalable types with the same minimum size |
171 | // are not considered equal. |
172 | ASSERT_TRUE(v4i32.getSizeInBits() != nxv4i32.getSizeInBits()); |
173 | ASSERT_FALSE(v2i64.getSizeInBits() == nxv2f64.getSizeInBits()); |
174 | |
175 | // Check that we can obtain a known-exact size from a non-scalable type. |
176 | EXPECT_EQ(v4i32.getFixedSizeInBits(), 128U); |
177 | EXPECT_EQ(v2i64.getFixedSizeInBits(), 128U); |
178 | |
179 | // Check that we can query the known minimum size for both scalable and |
180 | // fixed length types. |
181 | EXPECT_EQ(nxv2i32.getSizeInBits().getKnownMinValue(), 64U); |
182 | EXPECT_EQ(nxv2f64.getSizeInBits().getKnownMinValue(), 128U); |
183 | EXPECT_EQ(v2i32.getSizeInBits().getKnownMinValue(), |
184 | nxv2i32.getSizeInBits().getKnownMinValue()); |
185 | |
186 | // Check scalable property. |
187 | ASSERT_FALSE(v4i32.getSizeInBits().isScalable()); |
188 | ASSERT_TRUE(nxv4i32.getSizeInBits().isScalable()); |
189 | |
190 | // Check convenience size scaling methods. |
191 | EXPECT_EQ(v2i32.getSizeInBits() * 2, v4i32.getSizeInBits()); |
192 | EXPECT_EQ(2 * nxv2i32.getSizeInBits(), nxv4i32.getSizeInBits()); |
193 | EXPECT_EQ(nxv2f64.getSizeInBits().divideCoefficientBy(2), |
194 | nxv2i32.getSizeInBits()); |
195 | } |
196 | |
197 | } // end anonymous namespace |
198 | |