xref: /llvm-project/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp (revision 048cf8857e081fb80d5ac8b24a79f999d632141b)
1ed511560SReshabh Sharma //===- ModuleUtilsTest.cpp - Unit tests for Module utility ----===//
2ed511560SReshabh Sharma //
3ed511560SReshabh Sharma // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ed511560SReshabh Sharma // See https://llvm.org/LICENSE.txt for license information.
5ed511560SReshabh Sharma // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ed511560SReshabh Sharma //
7ed511560SReshabh Sharma //===----------------------------------------------------------------------===//
8ed511560SReshabh Sharma 
9ed511560SReshabh Sharma #include "llvm/Transforms/Utils/ModuleUtils.h"
10ed511560SReshabh Sharma #include "llvm/ADT/StringRef.h"
11ed511560SReshabh Sharma #include "llvm/AsmParser/Parser.h"
12a0a9bf51SVitaly Buka #include "llvm/IR/Constants.h"
13ed511560SReshabh Sharma #include "llvm/IR/LLVMContext.h"
14ed511560SReshabh Sharma #include "llvm/IR/Module.h"
15ed511560SReshabh Sharma #include "llvm/Support/SourceMgr.h"
16ed511560SReshabh Sharma #include "gtest/gtest.h"
17ed511560SReshabh Sharma 
18ed511560SReshabh Sharma using namespace llvm;
19ed511560SReshabh Sharma 
20a0a9bf51SVitaly Buka static std::unique_ptr<Module> parseIR(LLVMContext &C, StringRef IR) {
21ed511560SReshabh Sharma   SMDiagnostic Err;
22ed511560SReshabh Sharma   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
23ed511560SReshabh Sharma   if (!Mod)
24ed511560SReshabh Sharma     Err.print("ModuleUtilsTest", errs());
25ed511560SReshabh Sharma   return Mod;
26ed511560SReshabh Sharma }
27ed511560SReshabh Sharma 
2888ef76c4SVitaly Buka static int getListSize(Module &M, StringRef Name) {
2988ef76c4SVitaly Buka   auto *List = M.getGlobalVariable(Name);
3088ef76c4SVitaly Buka   if (!List)
31ed511560SReshabh Sharma     return 0;
3288ef76c4SVitaly Buka   auto *T = cast<ArrayType>(List->getValueType());
3388ef76c4SVitaly Buka   return T->getNumElements();
34ed511560SReshabh Sharma }
35ed511560SReshabh Sharma 
36ed511560SReshabh Sharma TEST(ModuleUtils, AppendToUsedList1) {
37ed511560SReshabh Sharma   LLVMContext C;
38ed511560SReshabh Sharma 
39ed511560SReshabh Sharma   std::unique_ptr<Module> M = parseIR(
40ed511560SReshabh Sharma       C, R"(@x = addrspace(4) global [2 x i32] zeroinitializer, align 4)");
41ed511560SReshabh Sharma   SmallVector<GlobalValue *, 2> Globals;
42ed511560SReshabh Sharma   for (auto &G : M->globals()) {
43ed511560SReshabh Sharma     Globals.push_back(&G);
44ed511560SReshabh Sharma   }
4588ef76c4SVitaly Buka   EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
46ed511560SReshabh Sharma   appendToCompilerUsed(*M, Globals);
4788ef76c4SVitaly Buka   EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
48ed511560SReshabh Sharma 
4988ef76c4SVitaly Buka   EXPECT_EQ(0, getListSize(*M, "llvm.used"));
50ed511560SReshabh Sharma   appendToUsed(*M, Globals);
5188ef76c4SVitaly Buka   EXPECT_EQ(1, getListSize(*M, "llvm.used"));
52ed511560SReshabh Sharma }
53ed511560SReshabh Sharma 
54ed511560SReshabh Sharma TEST(ModuleUtils, AppendToUsedList2) {
55ed511560SReshabh Sharma   LLVMContext C;
56ed511560SReshabh Sharma 
57ed511560SReshabh Sharma   std::unique_ptr<Module> M =
58ed511560SReshabh Sharma       parseIR(C, R"(@x = global [2 x i32] zeroinitializer, align 4)");
59ed511560SReshabh Sharma   SmallVector<GlobalValue *, 2> Globals;
60ed511560SReshabh Sharma   for (auto &G : M->globals()) {
61ed511560SReshabh Sharma     Globals.push_back(&G);
62ed511560SReshabh Sharma   }
6388ef76c4SVitaly Buka   EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
64ed511560SReshabh Sharma   appendToCompilerUsed(*M, Globals);
6588ef76c4SVitaly Buka   EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
66ed511560SReshabh Sharma 
6788ef76c4SVitaly Buka   EXPECT_EQ(0, getListSize(*M, "llvm.used"));
68ed511560SReshabh Sharma   appendToUsed(*M, Globals);
6988ef76c4SVitaly Buka   EXPECT_EQ(1, getListSize(*M, "llvm.used"));
70ed511560SReshabh Sharma }
71a0a9bf51SVitaly Buka 
72a0a9bf51SVitaly Buka using AppendFnType = decltype(&appendToGlobalCtors);
73*048cf885SVitaly Buka using TransformFnType = decltype(&transformGlobalCtors);
74*048cf885SVitaly Buka using ParamType = std::tuple<StringRef, AppendFnType, TransformFnType>;
75a0a9bf51SVitaly Buka class ModuleUtilsTest : public testing::TestWithParam<ParamType> {
76a0a9bf51SVitaly Buka public:
77a0a9bf51SVitaly Buka   StringRef arrayName() const { return std::get<0>(GetParam()); }
78a0a9bf51SVitaly Buka   AppendFnType appendFn() const { return std::get<AppendFnType>(GetParam()); }
79*048cf885SVitaly Buka   TransformFnType transformFn() const {
80*048cf885SVitaly Buka     return std::get<TransformFnType>(GetParam());
81*048cf885SVitaly Buka   }
82a0a9bf51SVitaly Buka };
83a0a9bf51SVitaly Buka 
84a0a9bf51SVitaly Buka INSTANTIATE_TEST_SUITE_P(
85a0a9bf51SVitaly Buka     ModuleUtilsTestCtors, ModuleUtilsTest,
86*048cf885SVitaly Buka     ::testing::Values(ParamType{"llvm.global_ctors", &appendToGlobalCtors,
87*048cf885SVitaly Buka                                 &transformGlobalCtors},
88*048cf885SVitaly Buka                       ParamType{"llvm.global_dtors", &appendToGlobalDtors,
89*048cf885SVitaly Buka                                 &transformGlobalDtors}));
90a0a9bf51SVitaly Buka 
91a0a9bf51SVitaly Buka TEST_P(ModuleUtilsTest, AppendToMissingArray) {
92a0a9bf51SVitaly Buka   LLVMContext C;
93a0a9bf51SVitaly Buka 
94a0a9bf51SVitaly Buka   std::unique_ptr<Module> M = parseIR(C, "");
95a0a9bf51SVitaly Buka 
96a0a9bf51SVitaly Buka   EXPECT_EQ(0, getListSize(*M, arrayName()));
97a0a9bf51SVitaly Buka   Function *F = cast<Function>(
98a0a9bf51SVitaly Buka       M->getOrInsertFunction("ctor", Type::getVoidTy(C)).getCallee());
99a0a9bf51SVitaly Buka   appendFn()(*M, F, 11, F);
100a0a9bf51SVitaly Buka   ASSERT_EQ(1, getListSize(*M, arrayName()));
101a0a9bf51SVitaly Buka 
102a0a9bf51SVitaly Buka   ConstantArray *CA = dyn_cast<ConstantArray>(
103a0a9bf51SVitaly Buka       M->getGlobalVariable(arrayName())->getInitializer());
104a0a9bf51SVitaly Buka   ASSERT_NE(nullptr, CA);
105a0a9bf51SVitaly Buka   ConstantStruct *CS = dyn_cast<ConstantStruct>(CA->getOperand(0));
106a0a9bf51SVitaly Buka   ASSERT_NE(nullptr, CS);
107a0a9bf51SVitaly Buka   ConstantInt *Pri = dyn_cast<ConstantInt>(CS->getOperand(0));
108a0a9bf51SVitaly Buka   ASSERT_NE(nullptr, Pri);
109a0a9bf51SVitaly Buka   EXPECT_EQ(11u, Pri->getLimitedValue());
110a0a9bf51SVitaly Buka   EXPECT_EQ(F, dyn_cast<Function>(CS->getOperand(1)));
111a0a9bf51SVitaly Buka   EXPECT_EQ(F, CS->getOperand(2));
112a0a9bf51SVitaly Buka }
113a0a9bf51SVitaly Buka 
114a0a9bf51SVitaly Buka TEST_P(ModuleUtilsTest, AppendToArray) {
115a0a9bf51SVitaly Buka   LLVMContext C;
116a0a9bf51SVitaly Buka 
117a0a9bf51SVitaly Buka   std::unique_ptr<Module> M =
118a0a9bf51SVitaly Buka       parseIR(C, (R"(@)" + arrayName() +
119a0a9bf51SVitaly Buka                   R"( = appending global [2 x { i32, ptr, ptr }] [
120a0a9bf51SVitaly Buka             { i32, ptr, ptr } { i32 65535, ptr  null, ptr null },
121a0a9bf51SVitaly Buka             { i32, ptr, ptr } { i32 0, ptr  null, ptr null }]
122a0a9bf51SVitaly Buka       )")
123a0a9bf51SVitaly Buka                      .str());
124a0a9bf51SVitaly Buka 
125a0a9bf51SVitaly Buka   EXPECT_EQ(2, getListSize(*M, arrayName()));
126a0a9bf51SVitaly Buka   appendFn()(
127a0a9bf51SVitaly Buka       *M,
128a0a9bf51SVitaly Buka       cast<Function>(
129a0a9bf51SVitaly Buka           M->getOrInsertFunction("ctor", Type::getVoidTy(C)).getCallee()),
130a0a9bf51SVitaly Buka       11, nullptr);
131a0a9bf51SVitaly Buka   EXPECT_EQ(3, getListSize(*M, arrayName()));
132a0a9bf51SVitaly Buka }
133*048cf885SVitaly Buka 
134*048cf885SVitaly Buka TEST_P(ModuleUtilsTest, UpdateArray) {
135*048cf885SVitaly Buka   LLVMContext C;
136*048cf885SVitaly Buka 
137*048cf885SVitaly Buka   std::unique_ptr<Module> M =
138*048cf885SVitaly Buka       parseIR(C, (R"(@)" + arrayName() +
139*048cf885SVitaly Buka                   R"( = appending global [2 x { i32, ptr, ptr }] [
140*048cf885SVitaly Buka             { i32, ptr, ptr } { i32 65535, ptr  null, ptr null },
141*048cf885SVitaly Buka             { i32, ptr, ptr } { i32 0, ptr  null, ptr null }]
142*048cf885SVitaly Buka       )")
143*048cf885SVitaly Buka                      .str());
144*048cf885SVitaly Buka 
145*048cf885SVitaly Buka   EXPECT_EQ(2, getListSize(*M, arrayName()));
146*048cf885SVitaly Buka   transformFn()(*M, [](Constant *C) -> Constant * {
147*048cf885SVitaly Buka     ConstantStruct *CS = dyn_cast<ConstantStruct>(C);
148*048cf885SVitaly Buka     if (!CS)
149*048cf885SVitaly Buka       return nullptr;
150*048cf885SVitaly Buka     StructType *EltTy = cast<StructType>(C->getType());
151*048cf885SVitaly Buka     Constant *CSVals[3] = {
152*048cf885SVitaly Buka         ConstantInt::getSigned(CS->getOperand(0)->getType(), 12),
153*048cf885SVitaly Buka         CS->getOperand(1),
154*048cf885SVitaly Buka         CS->getOperand(2),
155*048cf885SVitaly Buka     };
156*048cf885SVitaly Buka     return ConstantStruct::get(EltTy,
157*048cf885SVitaly Buka                                ArrayRef(CSVals, EltTy->getNumElements()));
158*048cf885SVitaly Buka   });
159*048cf885SVitaly Buka   EXPECT_EQ(1, getListSize(*M, arrayName()));
160*048cf885SVitaly Buka   ConstantArray *CA = dyn_cast<ConstantArray>(
161*048cf885SVitaly Buka       M->getGlobalVariable(arrayName())->getInitializer());
162*048cf885SVitaly Buka   ASSERT_NE(nullptr, CA);
163*048cf885SVitaly Buka   ConstantStruct *CS = dyn_cast<ConstantStruct>(CA->getOperand(0));
164*048cf885SVitaly Buka   ASSERT_NE(nullptr, CS);
165*048cf885SVitaly Buka   ConstantInt *Pri = dyn_cast<ConstantInt>(CS->getOperand(0));
166*048cf885SVitaly Buka   ASSERT_NE(nullptr, Pri);
167*048cf885SVitaly Buka   EXPECT_EQ(12u, Pri->getLimitedValue());
168*048cf885SVitaly Buka }
169