| //===--- ReplaceWithVecLibTest.cpp - replace-with-veclib unit tests -------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/CodeGen/ReplaceWithVeclib.h" |
| #include "llvm/Analysis/TargetLibraryInfo.h" |
| #include "llvm/AsmParser/Parser.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Passes/PassBuilder.h" |
| #include "llvm/Support/SourceMgr.h" |
| #include "gtest/gtest.h" |
| |
| using namespace llvm; |
| |
| /// NOTE: Assertions must be enabled for these tests to run. |
| #ifndef NDEBUG |
| |
| namespace { |
| |
| static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { |
| SMDiagnostic Err; |
| std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); |
| if (!Mod) |
| Err.print("ReplaceWithVecLibTest", errs()); |
| return Mod; |
| } |
| |
| /// Runs ReplaceWithVecLib with different TLIIs that have custom VecDescs. This |
| /// allows checking that the pass won't crash when the function to replace (from |
| /// the input IR) does not match the replacement function (derived from the |
| /// VecDesc mapping). |
| /// |
| class ReplaceWithVecLibTest : public ::testing::Test { |
| |
| std::string getLastLine(std::string Out) { |
| // remove any trailing '\n' |
| if (!Out.empty() && *(Out.cend() - 1) == '\n') |
| Out.pop_back(); |
| |
| size_t LastNL = Out.find_last_of('\n'); |
| return (LastNL == std::string::npos) ? Out : Out.substr(LastNL + 1); |
| } |
| |
| protected: |
| LLVMContext Ctx; |
| |
| /// Creates TLII using the given \p VD, and then runs the ReplaceWithVeclib |
| /// pass. The pass should not crash even when the replacement function |
| /// (derived from the \p VD mapping) does not match the function to be |
| /// replaced (from the input \p IR). |
| /// |
| /// \returns the last line of the standard error to be compared for |
| /// correctness. |
| std::string run(const VecDesc &VD, const char *IR) { |
| // Create TLII and register it with FAM so it's preserved when |
| // ReplaceWithVeclib pass runs. |
| TargetLibraryInfoImpl TLII = TargetLibraryInfoImpl(Triple()); |
| TLII.addVectorizableFunctions({VD}); |
| FunctionAnalysisManager FAM; |
| FAM.registerPass([&TLII]() { return TargetLibraryAnalysis(TLII); }); |
| |
| // Register and run the pass on the 'foo' function from the input IR. |
| FunctionPassManager FPM; |
| FPM.addPass(ReplaceWithVeclib()); |
| std::unique_ptr<Module> M = parseIR(Ctx, IR); |
| PassBuilder PB; |
| PB.registerFunctionAnalyses(FAM); |
| |
| // Enable debugging and capture std error |
| bool DebugFlagPrev = llvm::DebugFlag; |
| llvm::DebugFlag = true; |
| testing::internal::CaptureStderr(); |
| FPM.run(*M->getFunction("foo"), FAM); |
| llvm::DebugFlag = DebugFlagPrev; |
| return getLastLine(testing::internal::GetCapturedStderr()); |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| static const char *IR = R"IR( |
| define <vscale x 4 x float> @foo(<vscale x 4 x float> %in){ |
| %call = call <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float> %in, i32 3) |
| ret <vscale x 4 x float> %call |
| } |
| |
| declare <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float>, i32) #0 |
| )IR"; |
| |
| // The VFABI prefix in TLI describes signature which is matching the powi |
| // intrinsic declaration. |
| TEST_F(ReplaceWithVecLibTest, TestValidMapping) { |
| VecDesc CorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvu_powi", |
| ElementCount::getScalable(4), /*Masked*/ true, |
| "_ZGVsMxvu"}; |
| EXPECT_EQ(run(CorrectVD, IR), |
| "Intrinsic calls replaced with vector libraries: 1"); |
| } |
| |
| // The VFABI prefix in TLI describes signature which is not matching the powi |
| // intrinsic declaration. |
| TEST_F(ReplaceWithVecLibTest, TestInvalidMapping) { |
| VecDesc IncorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvv_powi", |
| ElementCount::getScalable(4), /*Masked*/ true, |
| "_ZGVsMxvv"}; |
| EXPECT_EQ(run(IncorrectVD, IR), |
| "replace-with-veclib: Will not replace: llvm.powi.f32.i32. Wrong " |
| "type at index 1: i32"); |
| } |
| #endif |