116 lines · cpp
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-exception6//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 NDEBUG22 23namespace {24 25static 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. This34/// allows checking that the pass won't crash when the function to replace (from35/// the input IR) does not match the replacement function (derived from the36/// 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('\n');46 return (LastNL == std::string::npos) ? Out : Out.substr(LastNL + 1);47 }48 49protected:50 LLVMContext Ctx;51 52 /// Creates TLII using the given \p VD, and then runs the ReplaceWithVeclib53 /// pass. The pass should not crash even when the replacement function54 /// (derived from the \p VD mapping) does not match the function to be55 /// replaced (from the input \p IR).56 ///57 /// \returns the last line of the standard error to be compared for58 /// correctness.59 std::string run(const VecDesc &VD, const char *IR) {60 // Create TLII and register it with FAM so it's preserved when61 // 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 error75 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 namespace85 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> %call90}91 92declare <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float>, i32) #093)IR";94 95// The VFABI prefix in TLI describes signature which is matching the powi96// intrinsic declaration.97TEST_F(ReplaceWithVecLibTest, TestValidMapping) {98 VecDesc CorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvu_powi",99 ElementCount::getScalable(4), /*Masked*/ true,100 "_ZGVsMxvu", /* CC = */ std::nullopt};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 powi106// intrinsic declaration.107TEST_F(ReplaceWithVecLibTest, TestInvalidMapping) {108 VecDesc IncorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvv_powi",109 ElementCount::getScalable(4), /*Masked*/ true,110 "_ZGVsMxvv", /* CC = */ std::nullopt};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#endif116