xref: /llvm-project/llvm/unittests/Analysis/ReplaceWithVecLibTest.cpp (revision e4790ce2096c805b7598c353f9e7fa513701f843)
1 //===--- ReplaceWithVecLibTest.cpp - replace-with-veclib 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/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"
17 
18 using namespace llvm;
19 
20 /// NOTE: Assertions must be enabled for these tests to run.
21 #ifndef NDEBUG
22 
23 namespace {
24 
parseIR(LLVMContext & C,const char * IR)25 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
26   SMDiagnostic Err;
27   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
28   if (!Mod)
29     Err.print("ReplaceWithVecLibTest", errs());
30   return Mod;
31 }
32 
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
36 /// VecDesc mapping).
37 ///
38 class ReplaceWithVecLibTest : public ::testing::Test {
39 
getLastLine(std::string Out)40   std::string getLastLine(std::string Out) {
41     // remove any trailing '\n'
42     if (!Out.empty() && *(Out.cend() - 1) == '\n')
43       Out.pop_back();
44 
45     size_t LastNL = Out.find_last_of('\n');
46     return (LastNL == std::string::npos) ? Out : Out.substr(LastNL + 1);
47   }
48 
49 protected:
50   LLVMContext Ctx;
51 
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).
56   ///
57   /// \returns the last line of the standard error to be compared for
58   /// correctness.
run(const VecDesc & VD,const char * IR)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); });
66 
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);
71     PassBuilder PB;
72     PB.registerFunctionAnalyses(FAM);
73 
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());
81   }
82 };
83 
84 } // end anonymous namespace
85 
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
90 }
91 
92 declare <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float>, i32) #0
93 )IR";
94 
95 // The VFABI prefix in TLI describes signature which is matching the powi
96 // intrinsic declaration.
TEST_F(ReplaceWithVecLibTest,TestValidMapping)97 TEST_F(ReplaceWithVecLibTest, TestValidMapping) {
98   VecDesc CorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvu_powi",
99                        ElementCount::getScalable(4), /*Masked*/ true,
100                        "_ZGVsMxvu"};
101   EXPECT_EQ(run(CorrectVD, IR),
102             "Intrinsic calls replaced with vector libraries: 1");
103 }
104 
105 // The VFABI prefix in TLI describes signature which is not matching the powi
106 // intrinsic declaration.
TEST_F(ReplaceWithVecLibTest,TestInvalidMapping)107 TEST_F(ReplaceWithVecLibTest, TestInvalidMapping) {
108   VecDesc IncorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvv_powi",
109                          ElementCount::getScalable(4), /*Masked*/ true,
110                          "_ZGVsMxvv"};
111   EXPECT_EQ(run(IncorrectVD, IR),
112             "replace-with-veclib: Will not replace: llvm.powi.f32.i32. Wrong "
113             "type at index 1: i32");
114 }
115 #endif