169 lines
5.5 KiB
C++
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());
|
|
}
|