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