1//===------- VFABIDemanglerTest.cpp - VFABI 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 "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"
18#include <optional>
19
20using namespace llvm;
21
22namespace {
23
24static LLVMContext Ctx;
25
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,
34/// GlobalPredicate).
35/// 4. The vector function is correctly found to have a mask.
36///
37class VFABIParserTest : public ::testing::Test {
38private:
39 // Parser output.
40 VFInfo Info;
41 /// Reset the data needed for the test.
42 void reset(const StringRef ScalarFTyStr) {
43 M = parseAssemblyString(AsmString: "declare void @dummy()", Err, Context&: Ctx);
44 EXPECT_NE(M.get(), nullptr)
45 << "Loading an invalid module.\n " << Err.getMessage() << "\n";
46 Type *Ty = parseType(Asm: ScalarFTyStr, Err, M: *(M.get()));
47 ScalarFTy = dyn_cast<FunctionType>(Val: Ty);
48 EXPECT_NE(ScalarFTy, nullptr)
49 << "Invalid function type string: " << ScalarFTyStr << "\n"
50 << Err.getMessage() << "\n";
51 // Reset the VFInfo
52 Info = VFInfo();
53 }
54
55 // Data needed to load the optional IR passed to invokeParser
56 SMDiagnostic Err;
57 std::unique_ptr<Module> M;
58 FunctionType *ScalarFTy = nullptr;
59
60protected:
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;
68
69 /// Invoke the parser. Every time this method is invoked the state of the test
70 /// is reset.
71 ///
72 /// \p MangledName string the parser has to demangle.
73 ///
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
81 // the same test.
82 reset(ScalarFTyStr);
83
84 const auto OptInfo = VFABI::tryDemangleForVFABI(MangledName, FTy: ScalarFTy);
85 if (OptInfo)
86 Info = *OptInfo;
87
88 return OptInfo.has_value();
89 }
90
91 /// Returns whether the parsed function contains a mask.
92 bool isMasked() const { return Info.isMasked(); }
93
94 FunctionType *getFunctionType() {
95 return VFABI::createFunctionType(Info, ScalarFTy);
96 }
97};
98} // unnamed namespace
99
100// Function Types commonly used in tests
101FunctionType *FTyMaskVLen2_i32 = FunctionType::get(
102 Result: Type::getVoidTy(C&: Ctx),
103 Params: {
104 VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getFixed(MinVal: 2)),
105 VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), EC: ElementCount::getFixed(MinVal: 2)),
106 },
107 isVarArg: false);
108
109FunctionType *FTyNoMaskVLen2_i32 = FunctionType::get(
110 Result: Type::getVoidTy(C&: Ctx),
111 Params: {
112 VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getFixed(MinVal: 2)),
113 },
114 isVarArg: false);
115
116FunctionType *FTyMaskedVLA_i32 = FunctionType::get(
117 Result: Type::getVoidTy(C&: Ctx),
118 Params: {
119 VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 4)),
120 VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 4)),
121 },
122 isVarArg: false);
123
124// This test makes sure that the demangling method succeeds only on
125// valid values of the string.
126TEST_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"));
139 // Missing <isa>.
140 EXPECT_FALSE(invokeParser("_ZGVN2v_foo"));
141 // Missing <mask>.
142 EXPECT_FALSE(invokeParser("_ZGVn2v_foo"));
143 // Missing <vlen>.
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"));
153}
154
155TEST_F(VFABIParserTest, ParamListParsing) {
156 EXPECT_TRUE(
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 Result: Type::getVoidTy(C&: Ctx),
162 Params: {VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getFixed(MinVal: 2)),
163 Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx),
164 Type::getInt32Ty(C&: Ctx)->getPointerTo(), Type::getInt32Ty(C&: Ctx)},
165 isVarArg: false);
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");
175}
176
177TEST_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");
184}
185
186TEST_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");
193}
194
195TEST_F(VFABIParserTest, ScalarNameAndVectorName_03) {
196 EXPECT_TRUE(
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");
203}
204
205TEST_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
211 // mangled name.
212 EXPECT_EQ(VectorName, "_ZGVnM2v___foo_bar_abc");
213}
214
215TEST_F(VFABIParserTest, Parse) {
216 EXPECT_TRUE(
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 Result: Type::getVoidTy(C&: Ctx),
223 Params: {
224 VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getFixed(MinVal: 2)),
225 Type::getInt32Ty(C&: Ctx),
226 Type::getInt32Ty(C&: Ctx),
227 Type::getInt32Ty(C&: Ctx),
228 Type::getInt32Ty(C&: Ctx)->getPointerTo(),
229 Type::getInt32Ty(C&: Ctx),
230 Type::getInt32Ty(C&: Ctx),
231 Type::getInt32Ty(C&: Ctx),
232 Type::getInt32Ty(C&: Ctx)->getPointerTo(),
233 },
234 isVarArg: false);
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");
249}
250
251TEST_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");
261}
262
263TEST_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 Result: Type::getVoidTy(C&: Ctx),
270 Params: {Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx),
271 Type::getInt32Ty(C&: Ctx)->getPointerTo()},
272 isVarArg: false);
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");
282}
283
284TEST_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");
295}
296
297TEST_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");
308}
309
310TEST_F(VFABIParserTest, NotAVectorFunctionABIName) {
311 // Vector names should start with `_ZGV`.
312 EXPECT_FALSE(invokeParser("ZGVnN2v_foo"));
313}
314
315TEST_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)"));
328}
329
330TEST_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 Result: Type::getVoidTy(C&: Ctx),
337 Params: {Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx),
338 Type::getInt32Ty(C&: Ctx)->getPointerTo(), Type::getInt32Ty(C&: Ctx),
339 Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx),
340 Type::getInt32Ty(C&: Ctx)->getPointerTo(), Type::getInt32Ty(C&: Ctx)},
341 isVarArg: false);
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");
354}
355
356TEST_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");
366}
367
368TEST_F(VFABIParserTest, InvalidMask) {
369 EXPECT_FALSE(invokeParser("_ZGVsK2v_foo"));
370}
371
372TEST_F(VFABIParserTest, InvalidParameter) {
373 EXPECT_FALSE(invokeParser("_ZGVsM2vX_foo"));
374}
375
376TEST_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");
384 FunctionType *FTy =
385 FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {Type::getInt32Ty(C&: Ctx)}, isVarArg: 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"));
398}
399
400TEST_F(VFABIParserTest, ParseUniform) {
401 EXPECT_TRUE(invokeParser("_ZGVnN2u_foo(vector_foo)", "void(i32)"));
402 EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
403 EXPECT_FALSE(isMasked());
404 FunctionType *FTy =
405 FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {Type::getInt32Ty(C&: Ctx)}, isVarArg: 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");
412
413 // Uniform doesn't expect extra data.
414 EXPECT_FALSE(invokeParser("_ZGVnN2u0_foo"));
415}
416
417TEST_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 Result: Type::getVoidTy(C&: Ctx),
424 Params: {VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getFixed(MinVal: 2)),
425 Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx),
426 Type::getInt32Ty(C&: Ctx)->getPointerTo(), Type::getInt32Ty(C&: Ctx),
427 Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx), Type::getInt32Ty(C&: Ctx),
428 Type::getInt32Ty(C&: Ctx)},
429 isVarArg: false);
430
431 const SmallVector<VFParameter, 8> ExpectedParams = {
432 VFParameter({.ParamPos: 0, .ParamKind: VFParamKind::Vector, .LinearStepOrPos: 0}),
433 VFParameter({.ParamPos: 1, .ParamKind: VFParamKind::OMP_LinearPos, .LinearStepOrPos: 2}),
434 VFParameter({.ParamPos: 2, .ParamKind: VFParamKind::OMP_LinearValPos, .LinearStepOrPos: 27}),
435 VFParameter({.ParamPos: 3, .ParamKind: VFParamKind::OMP_LinearUValPos, .LinearStepOrPos: 4}),
436 VFParameter({.ParamPos: 4, .ParamKind: VFParamKind::OMP_LinearRefPos, .LinearStepOrPos: 5}),
437 VFParameter({.ParamPos: 5, .ParamKind: VFParamKind::OMP_Linear, .LinearStepOrPos: 1}),
438 VFParameter({.ParamPos: 6, .ParamKind: VFParamKind::OMP_LinearVal, .LinearStepOrPos: 10}),
439 VFParameter({.ParamPos: 7, .ParamKind: VFParamKind::OMP_LinearUVal, .LinearStepOrPos: 100}),
440 VFParameter({.ParamPos: 8, .ParamKind: VFParamKind::OMP_LinearRef, .LinearStepOrPos: 1000}),
441 VFParameter({.ParamPos: 9, .ParamKind: VFParamKind::OMP_Uniform, .LinearStepOrPos: 0}),
442 };
443
444#define __COMMON_CHECKS \
445 do { \
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"); \
453 } while (0)
454
455 // Advanced SIMD: <isa> = "n"
456 EXPECT_TRUE(invokeParser(
457 "_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy));
458 EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
459 __COMMON_CHECKS;
460
461 // SVE: <isa> = "s"
462 EXPECT_TRUE(invokeParser(
463 "_ZGVsN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy));
464 EXPECT_EQ(ISA, VFISAKind::SVE);
465 __COMMON_CHECKS;
466
467 // SSE: <isa> = "b"
468 EXPECT_TRUE(invokeParser(
469 "_ZGVbN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy));
470 EXPECT_EQ(ISA, VFISAKind::SSE);
471 __COMMON_CHECKS;
472
473 // AVX: <isa> = "c"
474 EXPECT_TRUE(invokeParser(
475 "_ZGVcN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy));
476 EXPECT_EQ(ISA, VFISAKind::AVX);
477 __COMMON_CHECKS;
478
479 // AVX2: <isa> = "d"
480 EXPECT_TRUE(invokeParser(
481 "_ZGVdN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy));
482 EXPECT_EQ(ISA, VFISAKind::AVX2);
483 __COMMON_CHECKS;
484
485 // AVX512: <isa> = "e"
486 EXPECT_TRUE(invokeParser(
487 "_ZGVeN2vls2Ls27Us4Rs5l1L10U100R1000u_foo(vector_foo)", IRTy));
488 EXPECT_EQ(ISA, VFISAKind::AVX512);
489 __COMMON_CHECKS;
490
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);
495 __COMMON_CHECKS;
496
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);
502 __COMMON_CHECKS;
503
504#undef __COMMON_CHECKS
505}
506
507TEST_F(VFABIParserTest, MissingScalarName) {
508 EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
509}
510
511TEST_F(VFABIParserTest, MissingVectorName) {
512 EXPECT_FALSE(invokeParser("_ZGVnN2v_foo()"));
513}
514
515TEST_F(VFABIParserTest, MissingVectorNameTermination) {
516 EXPECT_FALSE(invokeParser("_ZGVnN2v_foo(bar"));
517}
518
519TEST_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");
530}
531
532TEST_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");
543}
544
545TEST_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");
556}
557
558TEST_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");
569}
570
571TEST_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");
582}
583
584TEST_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");
595}
596
597TEST_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");
608}
609
610TEST_F(VFABIParserTest, ParseScalableMaskingLLVM) {
611 EXPECT_FALSE(invokeParser("_ZGV_LLVM_Mxv_foo(vector_foo)"));
612}
613
614TEST_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");
624}
625
626TEST_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 Result: Type::getVoidTy(C&: Ctx),
633 Params: {
634 VectorType::get(ElementType: Type::getFloatTy(C&: Ctx), EC: ElementCount::getFixed(MinVal: 4)),
635 VectorType::get(ElementType: Type::getFloatTy(C&: Ctx), EC: ElementCount::getFixed(MinVal: 4)),
636 },
637 isVarArg: false);
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");
645}
646
647TEST_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");
659}
660
661TEST_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"));
666}
667
668TEST_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 Result: VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 4)),
674 Params: {VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 4)),
675 VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 4))},
676 isVarArg: false);
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");
684}
685
686TEST_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 Result: Type::getVoidTy(C&: Ctx),
693 Params: {
694 VectorType::get(ElementType: Type::getDoubleTy(C&: Ctx), EC: ElementCount::getScalable(MinVal: 2)),
695 Type::getInt32Ty(C&: Ctx)->getPointerTo(),
696 Type::getInt32Ty(C&: Ctx)->getPointerTo(),
697 VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 2)),
698 },
699 isVarArg: false);
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");
709}
710
711// Make sure that we get the correct VF if the return type is wider than any
712// parameter type.
713TEST_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 Result: VectorType::get(ElementType: Type::getInt64Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 2)),
719 Params: {
720 VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 2)),
721 VectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 2)),
722 VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 2)),
723 },
724 isVarArg: false);
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");
733}
734
735// Make sure we handle void return types.
736TEST_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 Result: Type::getVoidTy(C&: Ctx),
742 Params: {
743 VectorType::get(ElementType: Type::getInt16Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 8)),
744 VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), EC: ElementCount::getScalable(MinVal: 8)),
745 },
746 isVarArg: false);
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");
754}
755
756// Make sure we reject unsupported parameter types.
757TEST_F(VFABIParserTest, ParseUnsupportedElementTypeSVE) {
758 EXPECT_FALSE(invokeParser("_ZGVsMxv_foo(vector_foo)", "void(i128)"));
759}
760
761// Make sure we reject unsupported return types
762TEST_F(VFABIParserTest, ParseUnsupportedReturnTypeSVE) {
763 EXPECT_FALSE(invokeParser("_ZGVsMxv_foo(vector_foo)", "fp128(float)"));
764}
765
766class VFABIAttrTest : public testing::Test {
767protected:
768 void SetUp() override {
769 M = parseAssemblyString(AsmString: IR, Err, Context&: Ctx);
770 // Get the only call instruction in the block, which is the first
771 // instruction.
772 CI = dyn_cast<CallInst>(Val: &*(instructions(F: M->getFunction(Name: "f")).begin()));
773 }
774 const char *IR = "define i32 @f(i32 %a) {\n"
775 " %1 = call i32 @g(i32 %a) #0\n"
776 " ret i32 %1\n"
777 "}\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>)"
782 "attributes #0 = { "
783 "\"vector-function-abi-variant\"=\""
784 "_ZGVnN2v_g(custom_vg),_ZGVnN4v_g\" }";
785 LLVMContext Ctx;
786 SMDiagnostic Err;
787 std::unique_ptr<Module> M;
788 CallInst *CI;
789 SmallVector<std::string, 8> Mappings;
790};
791
792TEST_F(VFABIAttrTest, Read) {
793 VFABI::getVectorVariantNames(CI: *CI, VariantMappings&: Mappings);
794 SmallVector<std::string, 8> Exp;
795 Exp.push_back(Elt: "_ZGVnN2v_g(custom_vg)");
796 Exp.push_back(Elt: "_ZGVnN4v_g");
797 EXPECT_EQ(Mappings, Exp);
798}
799
800TEST_F(VFABIAttrTest, Write) {
801 Mappings.push_back(Elt: "_ZGVnN8v_g");
802 Mappings.push_back(Elt: "_ZGVnN2v_g(custom_vg)");
803 VFABI::setVectorVariantNames(CI, VariantMappings: Mappings);
804 const StringRef S =
805 CI->getFnAttr(Kind: "vector-function-abi-variant").getValueAsString();
806 EXPECT_EQ(S, "_ZGVnN8v_g,_ZGVnN2v_g(custom_vg)");
807}
808
809static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
810 SMDiagnostic Err;
811 std::unique_ptr<Module> Mod = parseAssemblyString(AsmString: IR, Err, Context&: C);
812 if (!Mod)
813 Err.print(ProgName: "VectorFunctionABITests", S&: errs());
814 return Mod;
815}
816
817TEST(VFABIGetMappingsTest, IndirectCallInst) {
818 LLVMContext C;
819 std::unique_ptr<Module> M = parseIR(C, IR: R"IR(
820define void @call(void () * %f) {
821entry:
822 call void %f()
823 ret void
824}
825)IR");
826 auto *F = dyn_cast_or_null<Function>(Val: M->getNamedValue(Name: "call"));
827 ASSERT_TRUE(F);
828 auto *CI = dyn_cast<CallInst>(Val: &F->front().front());
829 ASSERT_TRUE(CI);
830 ASSERT_TRUE(CI->isIndirectCall());
831 auto Mappings = VFDatabase::getMappings(CI: *CI);
832 EXPECT_EQ(Mappings.size(), (unsigned)0);
833}
834

source code of llvm/unittests/IR/VFABIDemanglerTest.cpp