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
18using namespace llvm;
19
20/// NOTE: Assertions must be enabled for these tests to run.
21#ifndef NDEBUG
22
23namespace {
24
25static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
26 SMDiagnostic Err;
27 std::unique_ptr<Module> Mod = parseAssemblyString(AsmString: IR, Err, Context&: C);
28 if (!Mod)
29 Err.print(ProgName: "ReplaceWithVecLibTest", S&: 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///
38class ReplaceWithVecLibTest : public ::testing::Test {
39
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(c: '\n');
46 return (LastNL == std::string::npos) ? Out : Out.substr(pos: LastNL + 1);
47 }
48
49protected:
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.
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(Fns: {VD});
64 FunctionAnalysisManager FAM;
65 FAM.registerPass(PassBuilder: [&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(Pass: ReplaceWithVeclib());
70 std::unique_ptr<Module> M = parseIR(C&: 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(IR&: *M->getFunction(Name: "foo"), AM&: FAM);
79 llvm::DebugFlag = DebugFlagPrev;
80 return getLastLine(Out: testing::internal::GetCapturedStderr());
81 }
82};
83
84} // end anonymous namespace
85
86static const char *IR = R"IR(
87define <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
92declare <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.
97TEST_F(ReplaceWithVecLibTest, TestValidMapping) {
98 VecDesc CorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvu_powi",
99 ElementCount::getScalable(MinVal: 4), /*Masked*/ true,
100 "_ZGVsMxvu"};
101 EXPECT_EQ(run(CorrectVD, IR),
102 "Instructions replaced with vector libraries: 1");
103}
104
105// The VFABI prefix in TLI describes signature which is not matching the powi
106// intrinsic declaration.
107TEST_F(ReplaceWithVecLibTest, TestInvalidMapping) {
108 VecDesc IncorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvv_powi",
109 ElementCount::getScalable(MinVal: 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

source code of llvm/unittests/Analysis/ReplaceWithVecLibTest.cpp