1 //===------- VFABIDemanglerTest.cpp - VFABI unit tests -------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/VFABIDemangler.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/Analysis/VectorUtils.h"
12 #include "llvm/AsmParser/Parser.h"
13 #include "llvm/IR/DerivedTypes.h"
14 #include "llvm/IR/InstIterator.h"
15 #include "llvm/IR/Module.h"
16 #include "llvm/Support/SourceMgr.h"
17 #include "gtest/gtest.h"
24 static LLVMContext Ctx
;
26 /// Perform tests against VFABI Rules. `invokeParser` creates a VFInfo object
27 /// and a scalar FunctionType, which are used by tests to check that:
28 /// 1. The scalar and vector names are correct.
29 /// 2. The number of parameters from the parsed mangled name matches the number
30 /// of arguments in the scalar function passed as FunctionType string.
31 /// 3. The number of vector parameters and their types match the values
32 /// specified in the test.
33 /// On masked functions it also checks that the last parameter is a mask (ie,
35 /// 4. The vector function is correctly found to have a mask.
37 class VFABIParserTest
: public ::testing::Test
{
41 /// Reset the data needed for the test.
42 void reset(const StringRef ScalarFTyStr
) {
43 M
= parseAssemblyString("declare void @dummy()", Err
, Ctx
);
44 EXPECT_NE(M
.get(), nullptr)
45 << "Loading an invalid module.\n " << Err
.getMessage() << "\n";
46 Type
*Ty
= parseType(ScalarFTyStr
, Err
, *(M
));
47 ScalarFTy
= dyn_cast
<FunctionType
>(Ty
);
48 EXPECT_NE(ScalarFTy
, nullptr)
49 << "Invalid function type string: " << ScalarFTyStr
<< "\n"
50 << Err
.getMessage() << "\n";
55 // Data needed to load the optional IR passed to invokeParser
57 std::unique_ptr
<Module
> M
;
58 FunctionType
*ScalarFTy
= nullptr;
61 // References to the parser output field.
62 ElementCount
&VF
= Info
.Shape
.VF
;
63 VFISAKind
&ISA
= Info
.ISA
;
64 /// Parameters for the vectorized function
65 SmallVector
<VFParameter
, 8> &Parameters
= Info
.Shape
.Parameters
;
66 std::string
&ScalarName
= Info
.ScalarName
;
67 std::string
&VectorName
= Info
.VectorName
;
69 /// Invoke the parser. Every time this method is invoked the state of the test
72 /// \p MangledName string the parser has to demangle.
74 /// \p ScalarFTyStr FunctionType string to get the signature of the scalar
75 /// function, which is used by `tryDemangleForVFABI` to check for the number
76 /// of arguments on scalable vectors, and by `matchParameters` to perform some
77 /// additional checking in the tests in this file.
78 bool invokeParser(const StringRef MangledName
,
79 const StringRef ScalarFTyStr
= "void()") {
80 // Reset the VFInfo to be able to call `invokeParser` multiple times in
84 const auto OptInfo
= VFABI::tryDemangleForVFABI(MangledName
, ScalarFTy
);
88 return OptInfo
.has_value();
91 /// Returns whether the parsed function contains a mask.
92 bool isMasked() const { return Info
.isMasked(); }
94 FunctionType
*getFunctionType() {
95 return VFABI::createFunctionType(Info
, ScalarFTy
);
98 } // unnamed namespace
100 // Function Types commonly used in tests
101 FunctionType
*FTyMaskVLen2_i32
= FunctionType::get(
102 Type::getVoidTy(Ctx
),
104 VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getFixed(2)),
105 VectorType::get(Type::getInt1Ty(Ctx
), ElementCount::getFixed(2)),
109 FunctionType
*FTyNoMaskVLen2_i32
= FunctionType::get(
110 Type::getVoidTy(Ctx
),
112 VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getFixed(2)),
116 FunctionType
*FTyMaskedVLA_i32
= FunctionType::get(
117 Type::getVoidTy(Ctx
),
119 VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getScalable(4)),
120 VectorType::get(Type::getInt1Ty(Ctx
), ElementCount::getScalable(4)),
124 // This test makes sure that the demangling method succeeds only on
125 // valid values of the string.
126 TEST_F(VFABIParserTest
, OnlyValidNames
) {
127 // Incomplete string.
128 EXPECT_FALSE(invokeParser(""));
129 EXPECT_FALSE(invokeParser("_ZGV"));
130 EXPECT_FALSE(invokeParser("_ZGVn"));
131 EXPECT_FALSE(invokeParser("_ZGVnN"));
132 EXPECT_FALSE(invokeParser("_ZGVnN2"));
133 EXPECT_FALSE(invokeParser("_ZGVnN2v"));
134 EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
135 // Missing parameters.
136 EXPECT_FALSE(invokeParser("_ZGVnN2_foo"));
137 // Missing _ZGV prefix.
138 EXPECT_FALSE(invokeParser("_ZVnN2v_foo"));
140 EXPECT_FALSE(invokeParser("_ZGVN2v_foo"));
142 EXPECT_FALSE(invokeParser("_ZGVn2v_foo"));
144 EXPECT_FALSE(invokeParser("_ZGVnNv_foo"));
145 // Missing <scalarname>.
146 EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
147 // Missing _ separator.
148 EXPECT_FALSE(invokeParser("_ZGVnN2vfoo"));
149 // Missing <vectorname>.
150 EXPECT_FALSE(invokeParser("_ZGVnN2v_foo()"));
151 // Unterminated name.
152 EXPECT_FALSE(invokeParser("_ZGVnN2v_foo(bar"));
155 TEST_F(VFABIParserTest
, ParamListParsing
) {
157 invokeParser("_ZGVnN2vl16Ls32R3l_foo", "void(i32, i32, i32, ptr, i32)"));
158 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
159 EXPECT_EQ(false, isMasked());
160 FunctionType
*FTy
= FunctionType::get(
161 Type::getVoidTy(Ctx
),
162 {VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getFixed(2)),
163 Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
),
164 Type::getInt32Ty(Ctx
)->getPointerTo(), Type::getInt32Ty(Ctx
)},
166 EXPECT_EQ(getFunctionType(), FTy
);
167 EXPECT_EQ(Parameters
.size(), (unsigned)5);
168 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
, 0}));
169 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::OMP_Linear
, 16}));
170 EXPECT_EQ(Parameters
[2], VFParameter({2, VFParamKind::OMP_LinearValPos
, 32}));
171 EXPECT_EQ(Parameters
[3], VFParameter({3, VFParamKind::OMP_LinearRef
, 3}));
172 EXPECT_EQ(Parameters
[4], VFParameter({4, VFParamKind::OMP_Linear
, 1}));
173 EXPECT_EQ(ScalarName
, "foo");
174 EXPECT_EQ(VectorName
, "_ZGVnN2vl16Ls32R3l_foo");
177 TEST_F(VFABIParserTest
, ScalarNameAndVectorName_01
) {
178 EXPECT_TRUE(invokeParser("_ZGVnM2v_foo(vector_foo)", "void(i32)"));
179 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
180 EXPECT_EQ(true, isMasked());
181 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
182 EXPECT_EQ(ScalarName
, "foo");
183 EXPECT_EQ(VectorName
, "vector_foo");
186 TEST_F(VFABIParserTest
, ScalarNameAndVectorName_02
) {
187 EXPECT_TRUE(invokeParser("_ZGVnM2v_foo(vector_foo)", "void(i32)"));
188 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
189 EXPECT_EQ(true, isMasked());
190 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
191 EXPECT_EQ(ScalarName
, "foo");
192 EXPECT_EQ(VectorName
, "vector_foo");
195 TEST_F(VFABIParserTest
, ScalarNameAndVectorName_03
) {
197 invokeParser("_ZGVnM2v___foo_bar_abc(fooBarAbcVec)", "void(i32)"));
198 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
199 EXPECT_EQ(true, isMasked());
200 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
201 EXPECT_EQ(ScalarName
, "__foo_bar_abc");
202 EXPECT_EQ(VectorName
, "fooBarAbcVec");
205 TEST_F(VFABIParserTest
, ScalarNameOnly
) {
206 EXPECT_TRUE(invokeParser("_ZGVnM2v___foo_bar_abc", "void(i32)"));
207 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
208 EXPECT_EQ(true, isMasked());
209 EXPECT_EQ(ScalarName
, "__foo_bar_abc");
210 // no vector name specified (as it's optional), so it should have the entire
212 EXPECT_EQ(VectorName
, "_ZGVnM2v___foo_bar_abc");
215 TEST_F(VFABIParserTest
, Parse
) {
217 invokeParser("_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_foo",
218 "void(i32, i32, i32, i32, ptr, i32, i32, i32, ptr)"));
219 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
220 EXPECT_FALSE(isMasked());
221 FunctionType
*FTy
= FunctionType::get(
222 Type::getVoidTy(Ctx
),
224 VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getFixed(2)),
225 Type::getInt32Ty(Ctx
),
226 Type::getInt32Ty(Ctx
),
227 Type::getInt32Ty(Ctx
),
228 Type::getInt32Ty(Ctx
)->getPointerTo(),
229 Type::getInt32Ty(Ctx
),
230 Type::getInt32Ty(Ctx
),
231 Type::getInt32Ty(Ctx
),
232 Type::getInt32Ty(Ctx
)->getPointerTo(),
235 EXPECT_EQ(getFunctionType(), FTy
);
236 EXPECT_EQ(VF
, ElementCount::getFixed(2));
237 EXPECT_EQ(Parameters
.size(), (unsigned)9);
238 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
, 0}));
239 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::OMP_LinearPos
, 2}));
240 EXPECT_EQ(Parameters
[2], VFParameter({2, VFParamKind::OMP_LinearValPos
, 27}));
241 EXPECT_EQ(Parameters
[3], VFParameter({3, VFParamKind::OMP_LinearUValPos
, 4}));
242 EXPECT_EQ(Parameters
[4], VFParameter({4, VFParamKind::OMP_LinearRefPos
, 5}));
243 EXPECT_EQ(Parameters
[5], VFParameter({5, VFParamKind::OMP_Linear
, 1}));
244 EXPECT_EQ(Parameters
[6], VFParameter({6, VFParamKind::OMP_LinearVal
, 10}));
245 EXPECT_EQ(Parameters
[7], VFParameter({7, VFParamKind::OMP_LinearUVal
, 100}));
246 EXPECT_EQ(Parameters
[8], VFParameter({8, VFParamKind::OMP_LinearRef
, 1000}));
247 EXPECT_EQ(ScalarName
, "foo");
248 EXPECT_EQ(VectorName
, "_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_foo");
251 TEST_F(VFABIParserTest
, ParseVectorName
) {
252 EXPECT_TRUE(invokeParser("_ZGVnN2v_foo(vector_foo)", "void(i32)"));
253 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
254 EXPECT_FALSE(isMasked());
255 EXPECT_EQ(getFunctionType(), FTyNoMaskVLen2_i32
);
256 EXPECT_EQ(VF
, ElementCount::getFixed(2));
257 EXPECT_EQ(Parameters
.size(), (unsigned)1);
258 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
, 0}));
259 EXPECT_EQ(ScalarName
, "foo");
260 EXPECT_EQ(VectorName
, "vector_foo");
263 TEST_F(VFABIParserTest
, LinearWithCompileTimeNegativeStep
) {
264 EXPECT_TRUE(invokeParser("_ZGVnN2ln1Ln10Un100Rn1000_foo(vector_foo)",
265 "void(i32, i32, i32, ptr)"));
266 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
267 EXPECT_FALSE(isMasked());
268 FunctionType
*FTy
= FunctionType::get(
269 Type::getVoidTy(Ctx
),
270 {Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
),
271 Type::getInt32Ty(Ctx
)->getPointerTo()},
273 EXPECT_EQ(getFunctionType(), FTy
);
274 EXPECT_EQ(VF
, ElementCount::getFixed(2));
275 EXPECT_EQ(Parameters
.size(), (unsigned)4);
276 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::OMP_Linear
, -1}));
277 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::OMP_LinearVal
, -10}));
278 EXPECT_EQ(Parameters
[2], VFParameter({2, VFParamKind::OMP_LinearUVal
, -100}));
279 EXPECT_EQ(Parameters
[3], VFParameter({3, VFParamKind::OMP_LinearRef
, -1000}));
280 EXPECT_EQ(ScalarName
, "foo");
281 EXPECT_EQ(VectorName
, "vector_foo");
284 TEST_F(VFABIParserTest
, ParseScalableSVE
) {
285 EXPECT_TRUE(invokeParser("_ZGVsMxv_foo(vector_foo)", "void(i32)"));
286 EXPECT_EQ(ISA
, VFISAKind::SVE
);
287 EXPECT_TRUE(isMasked());
288 EXPECT_EQ(getFunctionType(), FTyMaskedVLA_i32
);
289 EXPECT_EQ(VF
, ElementCount::getScalable(4));
290 EXPECT_EQ(Parameters
.size(), (unsigned)2);
291 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
292 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
293 EXPECT_EQ(ScalarName
, "foo");
294 EXPECT_EQ(VectorName
, "vector_foo");
297 TEST_F(VFABIParserTest
, ParseFixedWidthSVE
) {
298 EXPECT_TRUE(invokeParser("_ZGVsM2v_foo(vector_foo)", "void(i32)"));
299 EXPECT_EQ(ISA
, VFISAKind::SVE
);
300 EXPECT_TRUE(isMasked());
301 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
302 EXPECT_EQ(VF
, ElementCount::getFixed(2));
303 EXPECT_EQ(Parameters
.size(), (unsigned)2);
304 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
305 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
306 EXPECT_EQ(ScalarName
, "foo");
307 EXPECT_EQ(VectorName
, "vector_foo");
310 TEST_F(VFABIParserTest
, NotAVectorFunctionABIName
) {
311 // Vector names should start with `_ZGV`.
312 EXPECT_FALSE(invokeParser("ZGVnN2v_foo"));
315 TEST_F(VFABIParserTest
, LinearWithRuntimeStep
) {
316 EXPECT_FALSE(invokeParser("_ZGVnN2ls_foo"))
317 << "A number should be present after \"ls\".";
318 EXPECT_TRUE(invokeParser("_ZGVnN2ls2_foo", "void(i32)"));
319 EXPECT_FALSE(invokeParser("_ZGVnN2Rs_foo"))
320 << "A number should be present after \"Rs\".";
321 EXPECT_TRUE(invokeParser("_ZGVnN2Rs4_foo", "void(i32)"));
322 EXPECT_FALSE(invokeParser("_ZGVnN2Ls_foo"))
323 << "A number should be present after \"Ls\".";
324 EXPECT_TRUE(invokeParser("_ZGVnN2Ls6_foo", "void(i32)"));
325 EXPECT_FALSE(invokeParser("_ZGVnN2Us_foo"))
326 << "A number should be present after \"Us\".";
327 EXPECT_TRUE(invokeParser("_ZGVnN2Us8_foo", "void(i32)"));
330 TEST_F(VFABIParserTest
, LinearWithoutCompileTime
) {
331 EXPECT_TRUE(invokeParser("_ZGVnN3lLRUlnLnRnUn_foo(vector_foo)",
332 "void(i32, i32, ptr, i32, i32, i32, ptr, i32)"));
333 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
334 EXPECT_FALSE(isMasked());
335 FunctionType
*FTy
= FunctionType::get(
336 Type::getVoidTy(Ctx
),
337 {Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
),
338 Type::getInt32Ty(Ctx
)->getPointerTo(), Type::getInt32Ty(Ctx
),
339 Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
),
340 Type::getInt32Ty(Ctx
)->getPointerTo(), Type::getInt32Ty(Ctx
)},
342 EXPECT_EQ(getFunctionType(), FTy
);
343 EXPECT_EQ(Parameters
.size(), (unsigned)8);
344 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::OMP_Linear
, 1}));
345 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::OMP_LinearVal
, 1}));
346 EXPECT_EQ(Parameters
[2], VFParameter({2, VFParamKind::OMP_LinearRef
, 1}));
347 EXPECT_EQ(Parameters
[3], VFParameter({3, VFParamKind::OMP_LinearUVal
, 1}));
348 EXPECT_EQ(Parameters
[4], VFParameter({4, VFParamKind::OMP_Linear
, -1}));
349 EXPECT_EQ(Parameters
[5], VFParameter({5, VFParamKind::OMP_LinearVal
, -1}));
350 EXPECT_EQ(Parameters
[6], VFParameter({6, VFParamKind::OMP_LinearRef
, -1}));
351 EXPECT_EQ(Parameters
[7], VFParameter({7, VFParamKind::OMP_LinearUVal
, -1}));
352 EXPECT_EQ(ScalarName
, "foo");
353 EXPECT_EQ(VectorName
, "vector_foo");
356 TEST_F(VFABIParserTest
, LLVM_ISA
) {
357 EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_foo"));
358 EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_foo(vector_foo)", "void(i32)"));
359 EXPECT_EQ(ISA
, VFISAKind::LLVM
);
360 EXPECT_FALSE(isMasked());
361 EXPECT_EQ(getFunctionType(), FTyNoMaskVLen2_i32
);
362 EXPECT_EQ(Parameters
.size(), (unsigned)1);
363 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
364 EXPECT_EQ(ScalarName
, "foo");
365 EXPECT_EQ(VectorName
, "vector_foo");
368 TEST_F(VFABIParserTest
, InvalidMask
) {
369 EXPECT_FALSE(invokeParser("_ZGVsK2v_foo"));
372 TEST_F(VFABIParserTest
, InvalidParameter
) {
373 EXPECT_FALSE(invokeParser("_ZGVsM2vX_foo"));
376 TEST_F(VFABIParserTest
, Align
) {
377 EXPECT_TRUE(invokeParser("_ZGVsN2l2a2_foo(vector_foo)", "void(i32)"));
378 EXPECT_EQ(ISA
, VFISAKind::SVE
);
379 EXPECT_FALSE(isMasked());
380 EXPECT_EQ(Parameters
.size(), (unsigned)1);
381 EXPECT_EQ(Parameters
[0].Alignment
, Align(2));
382 EXPECT_EQ(ScalarName
, "foo");
383 EXPECT_EQ(VectorName
, "vector_foo");
385 FunctionType::get(Type::getVoidTy(Ctx
), {Type::getInt32Ty(Ctx
)}, false);
386 EXPECT_EQ(getFunctionType(), FTy
);
387 // Missing alignment value.
388 EXPECT_FALSE(invokeParser("_ZGVsM2l2a_foo"));
389 // Invalid alignment token "x".
390 EXPECT_FALSE(invokeParser("_ZGVsM2l2ax_foo"));
391 // Alignment MUST be associated to a paramater.
392 EXPECT_FALSE(invokeParser("_ZGVsM2a2_foo"));
393 // Alignment must be a power of 2.
394 EXPECT_FALSE(invokeParser("_ZGVsN2l2a0_foo"));
395 EXPECT_TRUE(invokeParser("_ZGVsN2l2a1_foo", "void(i32)"));
396 EXPECT_FALSE(invokeParser("_ZGVsN2l2a3_foo"));
397 EXPECT_FALSE(invokeParser("_ZGVsN2l2a6_foo"));
400 TEST_F(VFABIParserTest
, ParseUniform
) {
401 EXPECT_TRUE(invokeParser("_ZGVnN2u_foo(vector_foo)", "void(i32)"));
402 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
403 EXPECT_FALSE(isMasked());
405 FunctionType::get(Type::getVoidTy(Ctx
), {Type::getInt32Ty(Ctx
)}, false);
406 EXPECT_EQ(getFunctionType(), FTy
);
407 EXPECT_EQ(VF
, ElementCount::getFixed(2));
408 EXPECT_EQ(Parameters
.size(), (unsigned)1);
409 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::OMP_Uniform
, 0}));
410 EXPECT_EQ(ScalarName
, "foo");
411 EXPECT_EQ(VectorName
, "vector_foo");
413 // Uniform doesn't expect extra data.
414 EXPECT_FALSE(invokeParser("_ZGVnN2u0_foo"));
417 TEST_F(VFABIParserTest
, ISAIndependentMangling
) {
418 // This test makes sure that the mangling of the parameters in
419 // independent on the <isa> token.
420 const StringRef IRTy
=
421 "void(i32, i32, i32, i32, ptr, i32, i32, i32, i32, i32)";
422 FunctionType
*FTy
= FunctionType::get(
423 Type::getVoidTy(Ctx
),
424 {VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getFixed(2)),
425 Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
),
426 Type::getInt32Ty(Ctx
)->getPointerTo(), Type::getInt32Ty(Ctx
),
427 Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
), Type::getInt32Ty(Ctx
),
428 Type::getInt32Ty(Ctx
)},
431 const SmallVector
<VFParameter
, 8> ExpectedParams
= {
432 VFParameter({0, VFParamKind::Vector
, 0}),
433 VFParameter({1, VFParamKind::OMP_LinearPos
, 2}),
434 VFParameter({2, VFParamKind::OMP_LinearValPos
, 27}),
435 VFParameter({3, VFParamKind::OMP_LinearUValPos
, 4}),
436 VFParameter({4, VFParamKind::OMP_LinearRefPos
, 5}),
437 VFParameter({5, VFParamKind::OMP_Linear
, 1}),
438 VFParameter({6, VFParamKind::OMP_LinearVal
, 10}),
439 VFParameter({7, VFParamKind::OMP_LinearUVal
, 100}),
440 VFParameter({8, VFParamKind::OMP_LinearRef
, 1000}),
441 VFParameter({9, VFParamKind::OMP_Uniform
, 0}),
444 #define __COMMON_CHECKS \
446 EXPECT_EQ(VF, ElementCount::getFixed(2)); \
447 EXPECT_FALSE(isMasked()); \
448 EXPECT_EQ(getFunctionType(), FTy); \
449 EXPECT_EQ(Parameters.size(), (unsigned)10); \
450 EXPECT_EQ(Parameters, ExpectedParams); \
451 EXPECT_EQ(ScalarName, "foo"); \
452 EXPECT_EQ(VectorName, "vector_foo"); \
455 // Advanced SIMD: <isa> = "n"
456 EXPECT_TRUE(invokeParser(
457 "_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
458 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
462 EXPECT_TRUE(invokeParser(
463 "_ZGVsN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
464 EXPECT_EQ(ISA
, VFISAKind::SVE
);
468 EXPECT_TRUE(invokeParser(
469 "_ZGVbN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
470 EXPECT_EQ(ISA
, VFISAKind::SSE
);
474 EXPECT_TRUE(invokeParser(
475 "_ZGVcN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
476 EXPECT_EQ(ISA
, VFISAKind::AVX
);
480 EXPECT_TRUE(invokeParser(
481 "_ZGVdN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
482 EXPECT_EQ(ISA
, VFISAKind::AVX2
);
485 // AVX512: <isa> = "e"
486 EXPECT_TRUE(invokeParser(
487 "_ZGVeN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
488 EXPECT_EQ(ISA
, VFISAKind::AVX512
);
491 // LLVM: <isa> = "_LLVM_" internal vector function.
492 EXPECT_TRUE(invokeParser(
493 "_ZGV_LLVM_N2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
494 EXPECT_EQ(ISA
, VFISAKind::LLVM
);
497 // Unknown ISA (randomly using "q"). This test will need update if
498 // some targets decide to use "q" as their ISA token.
499 EXPECT_TRUE(invokeParser(
500 "_ZGVqN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy
));
501 EXPECT_EQ(ISA
, VFISAKind::Unknown
);
504 #undef __COMMON_CHECKS
507 TEST_F(VFABIParserTest
, MissingScalarName
) {
508 EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
511 TEST_F(VFABIParserTest
, MissingVectorName
) {
512 EXPECT_FALSE(invokeParser("_ZGVnN2v_foo()"));
515 TEST_F(VFABIParserTest
, MissingVectorNameTermination
) {
516 EXPECT_FALSE(invokeParser("_ZGVnN2v_foo(bar"));
519 TEST_F(VFABIParserTest
, ParseMaskingNEON
) {
520 EXPECT_TRUE(invokeParser("_ZGVnM2v_foo(vector_foo)", "void(i32)"));
521 EXPECT_EQ(ISA
, VFISAKind::AdvancedSIMD
);
522 EXPECT_TRUE(isMasked());
523 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
524 EXPECT_EQ(VF
, ElementCount::getFixed(2));
525 EXPECT_EQ(Parameters
.size(), (unsigned)2);
526 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
527 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
528 EXPECT_EQ(ScalarName
, "foo");
529 EXPECT_EQ(VectorName
, "vector_foo");
532 TEST_F(VFABIParserTest
, ParseMaskingSVE
) {
533 EXPECT_TRUE(invokeParser("_ZGVsM2v_foo(vector_foo)", "void(i32)"));
534 EXPECT_EQ(ISA
, VFISAKind::SVE
);
535 EXPECT_TRUE(isMasked());
536 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
537 EXPECT_EQ(VF
, ElementCount::getFixed(2));
538 EXPECT_EQ(Parameters
.size(), (unsigned)2);
539 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
540 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
541 EXPECT_EQ(ScalarName
, "foo");
542 EXPECT_EQ(VectorName
, "vector_foo");
545 TEST_F(VFABIParserTest
, ParseMaskingSSE
) {
546 EXPECT_TRUE(invokeParser("_ZGVbM2v_foo(vector_foo)", "void(i32)"));
547 EXPECT_EQ(ISA
, VFISAKind::SSE
);
548 EXPECT_TRUE(isMasked());
549 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
550 EXPECT_EQ(VF
, ElementCount::getFixed(2));
551 EXPECT_EQ(Parameters
.size(), (unsigned)2);
552 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
553 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
554 EXPECT_EQ(ScalarName
, "foo");
555 EXPECT_EQ(VectorName
, "vector_foo");
558 TEST_F(VFABIParserTest
, ParseMaskingAVX
) {
559 EXPECT_TRUE(invokeParser("_ZGVcM2v_foo(vector_foo)", "void(i32)"));
560 EXPECT_EQ(ISA
, VFISAKind::AVX
);
561 EXPECT_TRUE(isMasked());
562 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
563 EXPECT_EQ(VF
, ElementCount::getFixed(2));
564 EXPECT_EQ(Parameters
.size(), (unsigned)2);
565 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
566 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
567 EXPECT_EQ(ScalarName
, "foo");
568 EXPECT_EQ(VectorName
, "vector_foo");
571 TEST_F(VFABIParserTest
, ParseMaskingAVX2
) {
572 EXPECT_TRUE(invokeParser("_ZGVdM2v_foo(vector_foo)", "void(i32)"));
573 EXPECT_EQ(ISA
, VFISAKind::AVX2
);
574 EXPECT_TRUE(isMasked());
575 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
576 EXPECT_EQ(VF
, ElementCount::getFixed(2));
577 EXPECT_EQ(Parameters
.size(), (unsigned)2);
578 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
579 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
580 EXPECT_EQ(ScalarName
, "foo");
581 EXPECT_EQ(VectorName
, "vector_foo");
584 TEST_F(VFABIParserTest
, ParseMaskingAVX512
) {
585 EXPECT_TRUE(invokeParser("_ZGVeM2v_foo(vector_foo)", "void(i32)"));
586 EXPECT_EQ(ISA
, VFISAKind::AVX512
);
587 EXPECT_TRUE(isMasked());
588 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
589 EXPECT_EQ(VF
, ElementCount::getFixed(2));
590 EXPECT_EQ(Parameters
.size(), (unsigned)2);
591 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
592 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
593 EXPECT_EQ(ScalarName
, "foo");
594 EXPECT_EQ(VectorName
, "vector_foo");
597 TEST_F(VFABIParserTest
, ParseMaskingLLVM
) {
598 EXPECT_TRUE(invokeParser("_ZGV_LLVM_M2v_foo(vector_foo)", "void(i32)"));
599 EXPECT_EQ(ISA
, VFISAKind::LLVM
);
600 EXPECT_TRUE(isMasked());
601 EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32
);
602 EXPECT_EQ(VF
, ElementCount::getFixed(2));
603 EXPECT_EQ(Parameters
.size(), (unsigned)2);
604 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
605 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
606 EXPECT_EQ(ScalarName
, "foo");
607 EXPECT_EQ(VectorName
, "vector_foo");
610 TEST_F(VFABIParserTest
, ParseScalableMaskingLLVM
) {
611 EXPECT_FALSE(invokeParser("_ZGV_LLVM_Mxv_foo(vector_foo)"));
614 TEST_F(VFABIParserTest
, LLVM_InternalISA
) {
615 EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_foo"));
616 EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_foo(vector_foo)", "void(i32)"));
617 EXPECT_EQ(ISA
, VFISAKind::LLVM
);
618 EXPECT_FALSE(isMasked());
619 EXPECT_EQ(getFunctionType(), FTyNoMaskVLen2_i32
);
620 EXPECT_EQ(Parameters
.size(), (unsigned)1);
621 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
622 EXPECT_EQ(ScalarName
, "foo");
623 EXPECT_EQ(VectorName
, "vector_foo");
626 TEST_F(VFABIParserTest
, LLVM_Intrinsics
) {
627 EXPECT_TRUE(invokeParser("_ZGV_LLVM_N4vv_llvm.pow.f32(__svml_powf4)",
628 "void(float, float)"));
629 EXPECT_EQ(ISA
, VFISAKind::LLVM
);
630 EXPECT_FALSE(isMasked());
631 FunctionType
*FTy
= FunctionType::get(
632 Type::getVoidTy(Ctx
),
634 VectorType::get(Type::getFloatTy(Ctx
), ElementCount::getFixed(4)),
635 VectorType::get(Type::getFloatTy(Ctx
), ElementCount::getFixed(4)),
638 EXPECT_EQ(getFunctionType(), FTy
);
639 EXPECT_EQ(VF
, ElementCount::getFixed(4));
640 EXPECT_EQ(Parameters
.size(), (unsigned)2);
641 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
642 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::Vector
}));
643 EXPECT_EQ(ScalarName
, "llvm.pow.f32");
644 EXPECT_EQ(VectorName
, "__svml_powf4");
647 TEST_F(VFABIParserTest
, ParseScalableRequiresDeclaration
) {
648 const char *MangledName
= "_ZGVsMxv_sin(custom_vg)";
649 EXPECT_FALSE(invokeParser(MangledName
));
650 EXPECT_TRUE(invokeParser(MangledName
, "void(i32)"));
651 EXPECT_EQ(ISA
, VFISAKind::SVE
);
652 EXPECT_TRUE(isMasked());
653 EXPECT_EQ(getFunctionType(), FTyMaskedVLA_i32
);
654 EXPECT_EQ(Parameters
.size(), (unsigned)2);
655 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
656 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
657 EXPECT_EQ(ScalarName
, "sin");
658 EXPECT_EQ(VectorName
, "custom_vg");
661 TEST_F(VFABIParserTest
, ZeroIsInvalidVLEN
) {
662 EXPECT_FALSE(invokeParser("_ZGVeM0v_foo"));
663 EXPECT_FALSE(invokeParser("_ZGVeN0v_foo"));
664 EXPECT_FALSE(invokeParser("_ZGVsM0v_foo"));
665 EXPECT_FALSE(invokeParser("_ZGVsN0v_foo"));
668 TEST_F(VFABIParserTest
, ParseScalableMaskingSVE
) {
669 EXPECT_TRUE(invokeParser("_ZGVsMxv_foo(vector_foo)", "i32(i32)"));
670 EXPECT_EQ(ISA
, VFISAKind::SVE
);
671 EXPECT_TRUE(isMasked());
672 FunctionType
*FTy
= FunctionType::get(
673 VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getScalable(4)),
674 {VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getScalable(4)),
675 VectorType::get(Type::getInt1Ty(Ctx
), ElementCount::getScalable(4))},
677 EXPECT_EQ(getFunctionType(), FTy
);
678 EXPECT_EQ(VF
, ElementCount::getScalable(4));
679 EXPECT_EQ(Parameters
.size(), (unsigned)2);
680 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
681 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
682 EXPECT_EQ(ScalarName
, "foo");
683 EXPECT_EQ(VectorName
, "vector_foo");
686 TEST_F(VFABIParserTest
, ParseScalableMaskingSVESincos
) {
687 EXPECT_TRUE(invokeParser("_ZGVsMxvl8l8_sincos(custom_vector_sincos)",
688 "void(double, ptr, ptr)"));
689 EXPECT_EQ(ISA
, VFISAKind::SVE
);
690 EXPECT_TRUE(isMasked());
691 FunctionType
*FTy
= FunctionType::get(
692 Type::getVoidTy(Ctx
),
694 VectorType::get(Type::getDoubleTy(Ctx
), ElementCount::getScalable(2)),
695 Type::getInt32Ty(Ctx
)->getPointerTo(),
696 Type::getInt32Ty(Ctx
)->getPointerTo(),
697 VectorType::get(Type::getInt1Ty(Ctx
), ElementCount::getScalable(2)),
700 EXPECT_EQ(getFunctionType(), FTy
);
701 EXPECT_EQ(VF
, ElementCount::getScalable(2));
702 EXPECT_EQ(Parameters
.size(), (unsigned)4);
703 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
704 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::OMP_Linear
, 8}));
705 EXPECT_EQ(Parameters
[2], VFParameter({2, VFParamKind::OMP_Linear
, 8}));
706 EXPECT_EQ(Parameters
[3], VFParameter({3, VFParamKind::GlobalPredicate
}));
707 EXPECT_EQ(ScalarName
, "sincos");
708 EXPECT_EQ(VectorName
, "custom_vector_sincos");
711 // Make sure that we get the correct VF if the return type is wider than any
713 TEST_F(VFABIParserTest
, ParseWiderReturnTypeSVE
) {
714 EXPECT_TRUE(invokeParser("_ZGVsMxvv_foo(vector_foo)", "i64(i32, i32)"));
715 EXPECT_EQ(ISA
, VFISAKind::SVE
);
716 EXPECT_TRUE(isMasked());
717 FunctionType
*FTy
= FunctionType::get(
718 VectorType::get(Type::getInt64Ty(Ctx
), ElementCount::getScalable(2)),
720 VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getScalable(2)),
721 VectorType::get(Type::getInt32Ty(Ctx
), ElementCount::getScalable(2)),
722 VectorType::get(Type::getInt1Ty(Ctx
), ElementCount::getScalable(2)),
725 EXPECT_EQ(getFunctionType(), FTy
);
726 EXPECT_EQ(Parameters
.size(), (unsigned)3);
727 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
728 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::Vector
}));
729 EXPECT_EQ(Parameters
[2], VFParameter({2, VFParamKind::GlobalPredicate
}));
730 EXPECT_EQ(VF
, ElementCount::getScalable(2));
731 EXPECT_EQ(ScalarName
, "foo");
732 EXPECT_EQ(VectorName
, "vector_foo");
735 // Make sure we handle void return types.
736 TEST_F(VFABIParserTest
, ParseVoidReturnTypeSVE
) {
737 EXPECT_TRUE(invokeParser("_ZGVsMxv_foo(vector_foo)", "void(i16)"));
738 EXPECT_EQ(ISA
, VFISAKind::SVE
);
739 EXPECT_TRUE(isMasked());
740 FunctionType
*FTy
= FunctionType::get(
741 Type::getVoidTy(Ctx
),
743 VectorType::get(Type::getInt16Ty(Ctx
), ElementCount::getScalable(8)),
744 VectorType::get(Type::getInt1Ty(Ctx
), ElementCount::getScalable(8)),
747 EXPECT_EQ(getFunctionType(), FTy
);
748 EXPECT_EQ(Parameters
.size(), (unsigned)2);
749 EXPECT_EQ(Parameters
[0], VFParameter({0, VFParamKind::Vector
}));
750 EXPECT_EQ(Parameters
[1], VFParameter({1, VFParamKind::GlobalPredicate
}));
751 EXPECT_EQ(VF
, ElementCount::getScalable(8));
752 EXPECT_EQ(ScalarName
, "foo");
753 EXPECT_EQ(VectorName
, "vector_foo");
756 // Make sure we reject unsupported parameter types.
757 TEST_F(VFABIParserTest
, ParseUnsupportedElementTypeSVE
) {
758 EXPECT_FALSE(invokeParser("_ZGVsMxv_foo(vector_foo)", "void(i128)"));
761 // Make sure we reject unsupported return types
762 TEST_F(VFABIParserTest
, ParseUnsupportedReturnTypeSVE
) {
763 EXPECT_FALSE(invokeParser("_ZGVsMxv_foo(vector_foo)", "fp128(float)"));
766 class VFABIAttrTest
: public testing::Test
{
768 void SetUp() override
{
769 M
= parseAssemblyString(IR
, Err
, Ctx
);
770 // Get the only call instruction in the block, which is the first
772 CI
= dyn_cast
<CallInst
>(&*(instructions(M
->getFunction("f")).begin()));
774 const char *IR
= "define i32 @f(i32 %a) {\n"
775 " %1 = call i32 @g(i32 %a) #0\n"
778 "declare i32 @g(i32)\n"
779 "declare <2 x i32> @custom_vg(<2 x i32>)"
780 "declare <4 x i32> @_ZGVnN4v_g(<4 x i32>)"
781 "declare <8 x i32> @_ZGVnN8v_g(<8 x i32>)"
783 "\"vector-function-abi-variant\"=\""
784 "_ZGVnN2v_g(custom_vg),_ZGVnN4v_g\" }";
787 std::unique_ptr
<Module
> M
;
789 SmallVector
<std::string
, 8> Mappings
;
792 TEST_F(VFABIAttrTest
, Read
) {
793 VFABI::getVectorVariantNames(*CI
, Mappings
);
794 SmallVector
<std::string
, 8> Exp
;
795 Exp
.push_back("_ZGVnN2v_g(custom_vg)");
796 Exp
.push_back("_ZGVnN4v_g");
797 EXPECT_EQ(Mappings
, Exp
);
800 TEST_F(VFABIAttrTest
, Write
) {
801 Mappings
.push_back("_ZGVnN8v_g");
802 Mappings
.push_back("_ZGVnN2v_g(custom_vg)");
803 VFABI::setVectorVariantNames(CI
, Mappings
);
805 CI
->getFnAttr("vector-function-abi-variant").getValueAsString();
806 EXPECT_EQ(S
, "_ZGVnN8v_g,_ZGVnN2v_g(custom_vg)");
809 static std::unique_ptr
<Module
> parseIR(LLVMContext
&C
, const char *IR
) {
811 std::unique_ptr
<Module
> Mod
= parseAssemblyString(IR
, Err
, C
);
813 Err
.print("VectorFunctionABITests", errs());
817 TEST(VFABIGetMappingsTest
, IndirectCallInst
) {
819 std::unique_ptr
<Module
> M
= parseIR(C
, R
"IR(
820 define void @call(void () * %f) {
826 auto *F
= dyn_cast_or_null
<Function
>(M
->getNamedValue("call"));
828 auto *CI
= dyn_cast
<CallInst
>(&F
->front().front());
830 ASSERT_TRUE(CI
->isIndirectCall());
831 auto Mappings
= VFDatabase::getMappings(*CI
);
832 EXPECT_EQ(Mappings
.size(), (unsigned)0);