1 //===--- ReplaceWithVecLibTest.cpp - replace-with-veclib 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/CodeGen/ReplaceWithVeclib.h"
10 #include "llvm/Analysis/TargetLibraryInfo.h"
11 #include "llvm/AsmParser/Parser.h"
12 #include "llvm/IR/LLVMContext.h"
13 #include "llvm/IR/Module.h"
14 #include "llvm/Passes/PassBuilder.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "gtest/gtest.h"
20 /// NOTE: Assertions must be enabled for these tests to run.
25 static std::unique_ptr
<Module
> parseIR(LLVMContext
&C
, const char *IR
) {
27 std::unique_ptr
<Module
> Mod
= parseAssemblyString(IR
, Err
, C
);
29 Err
.print("ReplaceWithVecLibTest", errs());
33 /// Runs ReplaceWithVecLib with different TLIIs that have custom VecDescs. This
34 /// allows checking that the pass won't crash when the function to replace (from
35 /// the input IR) does not match the replacement function (derived from the
38 class ReplaceWithVecLibTest
: public ::testing::Test
{
40 std::string
getLastLine(std::string Out
) {
41 // remove any trailing '\n'
42 if (!Out
.empty() && *(Out
.cend() - 1) == '\n')
45 size_t LastNL
= Out
.find_last_of('\n');
46 return (LastNL
== std::string::npos
) ? Out
: Out
.substr(LastNL
+ 1);
52 /// Creates TLII using the given \p VD, and then runs the ReplaceWithVeclib
53 /// pass. The pass should not crash even when the replacement function
54 /// (derived from the \p VD mapping) does not match the function to be
55 /// replaced (from the input \p IR).
57 /// \returns the last line of the standard error to be compared for
59 std::string
run(const VecDesc
&VD
, const char *IR
) {
60 // Create TLII and register it with FAM so it's preserved when
61 // ReplaceWithVeclib pass runs.
62 TargetLibraryInfoImpl TLII
= TargetLibraryInfoImpl(Triple());
63 TLII
.addVectorizableFunctions({VD
});
64 FunctionAnalysisManager FAM
;
65 FAM
.registerPass([&TLII
]() { return TargetLibraryAnalysis(TLII
); });
67 // Register and run the pass on the 'foo' function from the input IR.
68 FunctionPassManager FPM
;
69 FPM
.addPass(ReplaceWithVeclib());
70 std::unique_ptr
<Module
> M
= parseIR(Ctx
, IR
);
72 PB
.registerFunctionAnalyses(FAM
);
74 // Enable debugging and capture std error
75 bool DebugFlagPrev
= llvm::DebugFlag
;
76 llvm::DebugFlag
= true;
77 testing::internal::CaptureStderr();
78 FPM
.run(*M
->getFunction("foo"), FAM
);
79 llvm::DebugFlag
= DebugFlagPrev
;
80 return getLastLine(testing::internal::GetCapturedStderr());
84 } // end anonymous namespace
86 static const char *IR
= R
"IR(
87 define <vscale x 4 x float> @foo(<vscale x 4 x float> %in){
88 %call = call <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float> %in, i32 3)
89 ret <vscale x 4 x float> %call
92 declare <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float>, i32) #0
95 // The VFABI prefix in TLI describes signature which is matching the powi
96 // intrinsic declaration.
97 TEST_F(ReplaceWithVecLibTest
, TestValidMapping
) {
98 VecDesc CorrectVD
= {"llvm.powi.f32.i32", "_ZGVsMxvu_powi",
99 ElementCount::getScalable(4), /*Masked*/ true,
101 EXPECT_EQ(run(CorrectVD
, IR
),
102 "Intrinsic calls replaced with vector libraries: 1");
105 // The VFABI prefix in TLI describes signature which is not matching the powi
106 // intrinsic declaration.
107 TEST_F(ReplaceWithVecLibTest
, TestInvalidMapping
) {
108 VecDesc IncorrectVD
= {"llvm.powi.f32.i32", "_ZGVsMxvv_powi",
109 ElementCount::getScalable(4), /*Masked*/ true,
111 EXPECT_EQ(run(IncorrectVD
, IR
),
112 "replace-with-veclib: Will not replace: llvm.powi.f32.i32. Wrong "
113 "type at index 1: i32");