2024-08-02 16:54:44 -07:00

169 lines
5.5 KiB
C++

//===- ModuleUtilsTest.cpp - Unit tests for Module utility ----===//
//
// 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/Transforms/Utils/ModuleUtils.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
using namespace llvm;
static std::unique_ptr<Module> parseIR(LLVMContext &C, StringRef IR) {
SMDiagnostic Err;
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
if (!Mod)
Err.print("ModuleUtilsTest", errs());
return Mod;
}
static int getListSize(Module &M, StringRef Name) {
auto *List = M.getGlobalVariable(Name);
if (!List)
return 0;
auto *T = cast<ArrayType>(List->getValueType());
return T->getNumElements();
}
TEST(ModuleUtils, AppendToUsedList1) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(
C, R"(@x = addrspace(4) global [2 x i32] zeroinitializer, align 4)");
SmallVector<GlobalValue *, 2> Globals;
for (auto &G : M->globals()) {
Globals.push_back(&G);
}
EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
appendToCompilerUsed(*M, Globals);
EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
EXPECT_EQ(0, getListSize(*M, "llvm.used"));
appendToUsed(*M, Globals);
EXPECT_EQ(1, getListSize(*M, "llvm.used"));
}
TEST(ModuleUtils, AppendToUsedList2) {
LLVMContext C;
std::unique_ptr<Module> M =
parseIR(C, R"(@x = global [2 x i32] zeroinitializer, align 4)");
SmallVector<GlobalValue *, 2> Globals;
for (auto &G : M->globals()) {
Globals.push_back(&G);
}
EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
appendToCompilerUsed(*M, Globals);
EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
EXPECT_EQ(0, getListSize(*M, "llvm.used"));
appendToUsed(*M, Globals);
EXPECT_EQ(1, getListSize(*M, "llvm.used"));
}
using AppendFnType = decltype(&appendToGlobalCtors);
using TransformFnType = decltype(&transformGlobalCtors);
using ParamType = std::tuple<StringRef, AppendFnType, TransformFnType>;
class ModuleUtilsTest : public testing::TestWithParam<ParamType> {
public:
StringRef arrayName() const { return std::get<0>(GetParam()); }
AppendFnType appendFn() const { return std::get<AppendFnType>(GetParam()); }
TransformFnType transformFn() const {
return std::get<TransformFnType>(GetParam());
}
};
INSTANTIATE_TEST_SUITE_P(
ModuleUtilsTestCtors, ModuleUtilsTest,
::testing::Values(ParamType{"llvm.global_ctors", &appendToGlobalCtors,
&transformGlobalCtors},
ParamType{"llvm.global_dtors", &appendToGlobalDtors,
&transformGlobalDtors}));
TEST_P(ModuleUtilsTest, AppendToMissingArray) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C, "");
EXPECT_EQ(0, getListSize(*M, arrayName()));
Function *F = cast<Function>(
M->getOrInsertFunction("ctor", Type::getVoidTy(C)).getCallee());
appendFn()(*M, F, 11, F);
ASSERT_EQ(1, getListSize(*M, arrayName()));
ConstantArray *CA = dyn_cast<ConstantArray>(
M->getGlobalVariable(arrayName())->getInitializer());
ASSERT_NE(nullptr, CA);
ConstantStruct *CS = dyn_cast<ConstantStruct>(CA->getOperand(0));
ASSERT_NE(nullptr, CS);
ConstantInt *Pri = dyn_cast<ConstantInt>(CS->getOperand(0));
ASSERT_NE(nullptr, Pri);
EXPECT_EQ(11u, Pri->getLimitedValue());
EXPECT_EQ(F, dyn_cast<Function>(CS->getOperand(1)));
EXPECT_EQ(F, CS->getOperand(2));
}
TEST_P(ModuleUtilsTest, AppendToArray) {
LLVMContext C;
std::unique_ptr<Module> M =
parseIR(C, (R"(@)" + arrayName() +
R"( = appending global [2 x { i32, ptr, ptr }] [
{ i32, ptr, ptr } { i32 65535, ptr null, ptr null },
{ i32, ptr, ptr } { i32 0, ptr null, ptr null }]
)")
.str());
EXPECT_EQ(2, getListSize(*M, arrayName()));
appendFn()(
*M,
cast<Function>(
M->getOrInsertFunction("ctor", Type::getVoidTy(C)).getCallee()),
11, nullptr);
EXPECT_EQ(3, getListSize(*M, arrayName()));
}
TEST_P(ModuleUtilsTest, UpdateArray) {
LLVMContext C;
std::unique_ptr<Module> M =
parseIR(C, (R"(@)" + arrayName() +
R"( = appending global [2 x { i32, ptr, ptr }] [
{ i32, ptr, ptr } { i32 65535, ptr null, ptr null },
{ i32, ptr, ptr } { i32 0, ptr null, ptr null }]
)")
.str());
EXPECT_EQ(2, getListSize(*M, arrayName()));
transformFn()(*M, [](Constant *C) -> Constant * {
ConstantStruct *CS = dyn_cast<ConstantStruct>(C);
if (!CS)
return nullptr;
StructType *EltTy = cast<StructType>(C->getType());
Constant *CSVals[3] = {
ConstantInt::getSigned(CS->getOperand(0)->getType(), 12),
CS->getOperand(1),
CS->getOperand(2),
};
return ConstantStruct::get(EltTy,
ArrayRef(CSVals, EltTy->getNumElements()));
});
EXPECT_EQ(1, getListSize(*M, arrayName()));
ConstantArray *CA = dyn_cast<ConstantArray>(
M->getGlobalVariable(arrayName())->getInitializer());
ASSERT_NE(nullptr, CA);
ConstantStruct *CS = dyn_cast<ConstantStruct>(CA->getOperand(0));
ASSERT_NE(nullptr, CS);
ConstantInt *Pri = dyn_cast<ConstantInt>(CS->getOperand(0));
ASSERT_NE(nullptr, Pri);
EXPECT_EQ(12u, Pri->getLimitedValue());
}