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