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