Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ModuleUtils] Add transformGlobal{C,D}tors #101757

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions llvm/include/llvm/Transforms/Utils/ModuleUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class FunctionCallee;
class GlobalIFunc;
class GlobalValue;
class Constant;
class ConstantStruct;
class Value;
class Type;

Expand All @@ -44,6 +45,14 @@ void appendToGlobalCtors(Module &M, Function *F, int Priority,
void appendToGlobalDtors(Module &M, Function *F, int Priority,
Constant *Data = nullptr);

/// Apply 'Fn' to the list of global ctors of module M and replace contructor
/// record with the one returned by `Fn`. If `nullptr` was returned, the
/// corresponding constructor will be removed from the array. For details see
/// https://llvm.org/docs/LangRef.html#the-llvm-global-ctors-global-variable
using GlobalCtorTransformFn = llvm::function_ref<Constant *(Constant *)>;
void transformGlobalCtors(Module &M, const GlobalCtorTransformFn &Fn);
void transformGlobalDtors(Module &M, const GlobalCtorTransformFn &Fn);

/// Sets the KCFI type for the function. Used for compiler-generated functions
/// that are indirectly called in instrumented code.
void setKCFIType(Module &M, Function &F, StringRef MangledType);
Expand Down
44 changes: 44 additions & 0 deletions llvm/lib/Transforms/Utils/ModuleUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,50 @@ void llvm::appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *D
appendToGlobalArray("llvm.global_dtors", M, F, Priority, Data);
}

static void transformGlobalArray(StringRef ArrayName, Module &M,
const GlobalCtorTransformFn &Fn) {
GlobalVariable *GVCtor = M.getNamedGlobal(ArrayName);
if (!GVCtor)
return;

IRBuilder<> IRB(M.getContext());
SmallVector<Constant *, 16> CurrentCtors;
bool Changed = false;
StructType *EltTy =
cast<StructType>(GVCtor->getValueType()->getArrayElementType());
if (Constant *Init = GVCtor->getInitializer()) {
CurrentCtors.reserve(Init->getNumOperands());
for (Value *OP : Init->operands()) {
Constant *C = cast<Constant>(OP);
Constant *NewC = Fn(C);
Changed |= (!NewC || NewC != C);
if (NewC)
CurrentCtors.push_back(NewC);
}
}
if (!Changed)
return;

GVCtor->eraseFromParent();

// Create a new initializer.
ArrayType *AT = ArrayType::get(EltTy, CurrentCtors.size());
Constant *NewInit = ConstantArray::get(AT, CurrentCtors);

// Create the new global variable and replace all uses of
// the old global variable with the new one.
(void)new GlobalVariable(M, NewInit->getType(), false,
GlobalValue::AppendingLinkage, NewInit, ArrayName);
}

void llvm::transformGlobalCtors(Module &M, const GlobalCtorTransformFn &Fn) {
transformGlobalArray("llvm.global_ctors", M, Fn);
}

void llvm::transformGlobalDtors(Module &M, const GlobalCtorTransformFn &Fn) {
transformGlobalArray("llvm.global_dtors", M, Fn);
}

static void collectUsedGlobals(GlobalVariable *GV,
SmallSetVector<Constant *, 16> &Init) {
if (!GV || !GV->hasInitializer())
Expand Down
48 changes: 45 additions & 3 deletions llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,23 @@ TEST(ModuleUtils, AppendToUsedList2) {
}

using AppendFnType = decltype(&appendToGlobalCtors);
using ParamType = std::tuple<StringRef, AppendFnType>;
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},
ParamType{"llvm.global_dtors", &appendToGlobalDtors}));
::testing::Values(ParamType{"llvm.global_ctors", &appendToGlobalCtors,
&transformGlobalCtors},
ParamType{"llvm.global_dtors", &appendToGlobalDtors,
&transformGlobalDtors}));

TEST_P(ModuleUtilsTest, AppendToMissingArray) {
LLVMContext C;
Expand Down Expand Up @@ -124,3 +130,39 @@ TEST_P(ModuleUtilsTest, AppendToArray) {
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());
}
Loading