xref: /llvm-project/llvm/unittests/Analysis/ReplaceWithVecLibTest.cpp (revision e4790ce2096c805b7598c353f9e7fa513701f843)
18e514c57SPaschalis Mpeis //===--- ReplaceWithVecLibTest.cpp - replace-with-veclib unit tests -------===//
28e514c57SPaschalis Mpeis //
38e514c57SPaschalis Mpeis // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48e514c57SPaschalis Mpeis // See https://llvm.org/LICENSE.txt for license information.
58e514c57SPaschalis Mpeis // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68e514c57SPaschalis Mpeis //
78e514c57SPaschalis Mpeis //===----------------------------------------------------------------------===//
88e514c57SPaschalis Mpeis 
98e514c57SPaschalis Mpeis #include "llvm/CodeGen/ReplaceWithVeclib.h"
108e514c57SPaschalis Mpeis #include "llvm/Analysis/TargetLibraryInfo.h"
118e514c57SPaschalis Mpeis #include "llvm/AsmParser/Parser.h"
128e514c57SPaschalis Mpeis #include "llvm/IR/LLVMContext.h"
138e514c57SPaschalis Mpeis #include "llvm/IR/Module.h"
148e514c57SPaschalis Mpeis #include "llvm/Passes/PassBuilder.h"
158e514c57SPaschalis Mpeis #include "llvm/Support/SourceMgr.h"
168e514c57SPaschalis Mpeis #include "gtest/gtest.h"
178e514c57SPaschalis Mpeis 
188e514c57SPaschalis Mpeis using namespace llvm;
198e514c57SPaschalis Mpeis 
208e514c57SPaschalis Mpeis /// NOTE: Assertions must be enabled for these tests to run.
218e514c57SPaschalis Mpeis #ifndef NDEBUG
228e514c57SPaschalis Mpeis 
238e514c57SPaschalis Mpeis namespace {
248e514c57SPaschalis Mpeis 
parseIR(LLVMContext & C,const char * IR)258e514c57SPaschalis Mpeis static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
268e514c57SPaschalis Mpeis   SMDiagnostic Err;
278e514c57SPaschalis Mpeis   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
288e514c57SPaschalis Mpeis   if (!Mod)
298e514c57SPaschalis Mpeis     Err.print("ReplaceWithVecLibTest", errs());
308e514c57SPaschalis Mpeis   return Mod;
318e514c57SPaschalis Mpeis }
328e514c57SPaschalis Mpeis 
338e514c57SPaschalis Mpeis /// Runs ReplaceWithVecLib with different TLIIs that have custom VecDescs. This
348e514c57SPaschalis Mpeis /// allows checking that the pass won't crash when the function to replace (from
358e514c57SPaschalis Mpeis /// the input IR) does not match the replacement function (derived from the
368e514c57SPaschalis Mpeis /// VecDesc mapping).
378e514c57SPaschalis Mpeis ///
388e514c57SPaschalis Mpeis class ReplaceWithVecLibTest : public ::testing::Test {
398e514c57SPaschalis Mpeis 
getLastLine(std::string Out)408e514c57SPaschalis Mpeis   std::string getLastLine(std::string Out) {
418e514c57SPaschalis Mpeis     // remove any trailing '\n'
428e514c57SPaschalis Mpeis     if (!Out.empty() && *(Out.cend() - 1) == '\n')
438e514c57SPaschalis Mpeis       Out.pop_back();
448e514c57SPaschalis Mpeis 
458e514c57SPaschalis Mpeis     size_t LastNL = Out.find_last_of('\n');
468e514c57SPaschalis Mpeis     return (LastNL == std::string::npos) ? Out : Out.substr(LastNL + 1);
478e514c57SPaschalis Mpeis   }
488e514c57SPaschalis Mpeis 
498e514c57SPaschalis Mpeis protected:
508e514c57SPaschalis Mpeis   LLVMContext Ctx;
518e514c57SPaschalis Mpeis 
528e514c57SPaschalis Mpeis   /// Creates TLII using the given \p VD, and then runs the ReplaceWithVeclib
538e514c57SPaschalis Mpeis   /// pass. The pass should not crash even when the replacement function
548e514c57SPaschalis Mpeis   /// (derived from the \p VD mapping) does not match the function to be
558e514c57SPaschalis Mpeis   /// replaced (from the input \p IR).
568e514c57SPaschalis Mpeis   ///
578e514c57SPaschalis Mpeis   /// \returns the last line of the standard error to be compared for
588e514c57SPaschalis Mpeis   /// correctness.
run(const VecDesc & VD,const char * IR)598e514c57SPaschalis Mpeis   std::string run(const VecDesc &VD, const char *IR) {
608e514c57SPaschalis Mpeis     // Create TLII and register it with FAM so it's preserved when
618e514c57SPaschalis Mpeis     // ReplaceWithVeclib pass runs.
628e514c57SPaschalis Mpeis     TargetLibraryInfoImpl TLII = TargetLibraryInfoImpl(Triple());
638e514c57SPaschalis Mpeis     TLII.addVectorizableFunctions({VD});
648e514c57SPaschalis Mpeis     FunctionAnalysisManager FAM;
658e514c57SPaschalis Mpeis     FAM.registerPass([&TLII]() { return TargetLibraryAnalysis(TLII); });
668e514c57SPaschalis Mpeis 
678e514c57SPaschalis Mpeis     // Register and run the pass on the 'foo' function from the input IR.
688e514c57SPaschalis Mpeis     FunctionPassManager FPM;
698e514c57SPaschalis Mpeis     FPM.addPass(ReplaceWithVeclib());
708e514c57SPaschalis Mpeis     std::unique_ptr<Module> M = parseIR(Ctx, IR);
718e514c57SPaschalis Mpeis     PassBuilder PB;
728e514c57SPaschalis Mpeis     PB.registerFunctionAnalyses(FAM);
738e514c57SPaschalis Mpeis 
748e514c57SPaschalis Mpeis     // Enable debugging and capture std error
756ad4ed5fSPaschalis Mpeis     bool DebugFlagPrev = llvm::DebugFlag;
768e514c57SPaschalis Mpeis     llvm::DebugFlag = true;
778e514c57SPaschalis Mpeis     testing::internal::CaptureStderr();
788e514c57SPaschalis Mpeis     FPM.run(*M->getFunction("foo"), FAM);
796ad4ed5fSPaschalis Mpeis     llvm::DebugFlag = DebugFlagPrev;
808e514c57SPaschalis Mpeis     return getLastLine(testing::internal::GetCapturedStderr());
818e514c57SPaschalis Mpeis   }
828e514c57SPaschalis Mpeis };
838e514c57SPaschalis Mpeis 
848e514c57SPaschalis Mpeis } // end anonymous namespace
858e514c57SPaschalis Mpeis 
868e514c57SPaschalis Mpeis static const char *IR = R"IR(
878e514c57SPaschalis Mpeis define <vscale x 4 x float> @foo(<vscale x 4 x float> %in){
888e514c57SPaschalis Mpeis   %call = call <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float> %in, i32 3)
898e514c57SPaschalis Mpeis   ret <vscale x 4 x float> %call
908e514c57SPaschalis Mpeis }
918e514c57SPaschalis Mpeis 
928e514c57SPaschalis Mpeis declare <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float>, i32) #0
938e514c57SPaschalis Mpeis )IR";
948e514c57SPaschalis Mpeis 
958e514c57SPaschalis Mpeis // The VFABI prefix in TLI describes signature which is matching the powi
968e514c57SPaschalis Mpeis // intrinsic declaration.
TEST_F(ReplaceWithVecLibTest,TestValidMapping)978e514c57SPaschalis Mpeis TEST_F(ReplaceWithVecLibTest, TestValidMapping) {
988e514c57SPaschalis Mpeis   VecDesc CorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvu_powi",
998e514c57SPaschalis Mpeis                        ElementCount::getScalable(4), /*Masked*/ true,
1008e514c57SPaschalis Mpeis                        "_ZGVsMxvu"};
1018e514c57SPaschalis Mpeis   EXPECT_EQ(run(CorrectVD, IR),
102*e4790ce2SPaschalis Mpeis             "Intrinsic calls replaced with vector libraries: 1");
1038e514c57SPaschalis Mpeis }
1048e514c57SPaschalis Mpeis 
1058e514c57SPaschalis Mpeis // The VFABI prefix in TLI describes signature which is not matching the powi
1068e514c57SPaschalis Mpeis // intrinsic declaration.
TEST_F(ReplaceWithVecLibTest,TestInvalidMapping)1078e514c57SPaschalis Mpeis TEST_F(ReplaceWithVecLibTest, TestInvalidMapping) {
1088e514c57SPaschalis Mpeis   VecDesc IncorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvv_powi",
1098e514c57SPaschalis Mpeis                          ElementCount::getScalable(4), /*Masked*/ true,
1108e514c57SPaschalis Mpeis                          "_ZGVsMxvv"};
1118e514c57SPaschalis Mpeis   EXPECT_EQ(run(IncorrectVD, IR),
1128e514c57SPaschalis Mpeis             "replace-with-veclib: Will not replace: llvm.powi.f32.i32. Wrong "
1138e514c57SPaschalis Mpeis             "type at index 1: i32");
1148e514c57SPaschalis Mpeis }
1158e514c57SPaschalis Mpeis #endif