|
| 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 | + |
| 18 | +using namespace llvm; |
| 19 | + |
| 20 | +namespace { |
| 21 | + |
| 22 | +static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { |
| 23 | + SMDiagnostic Err; |
| 24 | + std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); |
| 25 | + if (!Mod) |
| 26 | + Err.print("ReplaceWithVecLibTest", errs()); |
| 27 | + return Mod; |
| 28 | +} |
| 29 | + |
| 30 | +/// Runs ReplaceWithVecLib with different TLIIs that have custom VecDescs. This |
| 31 | +/// allows checking that the pass won't crash when the function to replace (from |
| 32 | +/// the input IR) does not match the replacement function (derived from the |
| 33 | +/// VecDesc mapping). |
| 34 | +class ReplaceWithVecLibTest : public ::testing::Test { |
| 35 | +protected: |
| 36 | + LLVMContext Ctx; |
| 37 | + |
| 38 | + /// Creates TLII using the given \p VD, and then runs the ReplaceWithVeclib |
| 39 | + /// pass. The pass should not crash even when the replacement function |
| 40 | + /// (derived from the \p VD mapping) does not match the function to be |
| 41 | + /// replaced (from the input \p IR). |
| 42 | + bool run(const VecDesc &VD, const char *IR) { |
| 43 | + // Create TLII and register it with FAM so it's preserved when |
| 44 | + // ReplaceWithVeclib pass runs. |
| 45 | + TargetLibraryInfoImpl TLII = TargetLibraryInfoImpl(Triple()); |
| 46 | + TLII.addVectorizableFunctions({VD}); |
| 47 | + FunctionAnalysisManager FAM; |
| 48 | + FAM.registerPass([&TLII]() { return TargetLibraryAnalysis(TLII); }); |
| 49 | + |
| 50 | + // Register and run the pass on the 'foo' function from the input IR. |
| 51 | + FunctionPassManager FPM; |
| 52 | + FPM.addPass(ReplaceWithVeclib()); |
| 53 | + std::unique_ptr<Module> M = parseIR(Ctx, IR); |
| 54 | + PassBuilder PB; |
| 55 | + PB.registerFunctionAnalyses(FAM); |
| 56 | + FPM.run(*M->getFunction("foo"), FAM); |
| 57 | + |
| 58 | + return true; |
| 59 | + } |
| 60 | +}; |
| 61 | + |
| 62 | +} // end anonymous namespace |
| 63 | + |
| 64 | +static const char *IR = R"IR( |
| 65 | +define <vscale x 4 x float> @foo(<vscale x 4 x float> %in){ |
| 66 | + %call = call <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float> %in, i32 3) |
| 67 | + ret <vscale x 4 x float> %call |
| 68 | +} |
| 69 | +
|
| 70 | +declare <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float>, i32) #0 |
| 71 | +)IR"; |
| 72 | + |
| 73 | +// LLVM intrinsic 'powi' (in IR) has the same signature with the VecDesc. |
| 74 | +TEST_F(ReplaceWithVecLibTest, TestValidMapping) { |
| 75 | + VecDesc CorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvu_powi", |
| 76 | + ElementCount::getScalable(4), true, "_ZGVsMxvu"}; |
| 77 | + EXPECT_TRUE(run(CorrectVD, IR)); |
| 78 | +} |
| 79 | + |
| 80 | +// LLVM intrinsic 'powi' (in IR) has different signature with the VecDesc. |
| 81 | +TEST_F(ReplaceWithVecLibTest, TestInvalidMapping) { |
| 82 | + VecDesc IncorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvv_powi", |
| 83 | + ElementCount::getScalable(4), true, "_ZGVsMxvv"}; |
| 84 | + /// TODO: test should avoid and not crash. |
| 85 | + EXPECT_DEATH(run(IncorrectVD, IR), ""); |
| 86 | +} |
0 commit comments