diff --git a/lib/Transforms/Utils/CtorUtils.cpp b/lib/Transforms/Utils/CtorUtils.cpp index a3594248de0..26875e837b8 100644 --- a/lib/Transforms/Utils/CtorUtils.cpp +++ b/lib/Transforms/Utils/CtorUtils.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/BitVector.h" #include "llvm/Transforms/Utils/CtorUtils.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" @@ -24,41 +25,22 @@ namespace llvm { namespace { -/// Given a specified llvm.global_ctors list, install the -/// specified array. -void installGlobalCtors(GlobalVariable *GCL, - const std::vector &Ctors) { - // If we made a change, reassemble the initializer list. - Constant *CSVals[3]; +/// Given a specified llvm.global_ctors list, remove the listed elements. +void removeGlobalCtors(GlobalVariable *GCL, const BitVector &CtorsToRemove) { + // Filter out the initializer elements to remove. + ConstantArray *OldCA = cast(GCL->getInitializer()); + SmallVector CAList; + for (unsigned I = 0, E = OldCA->getNumOperands(); I < E; ++I) + if (!CtorsToRemove.test(I)) + CAList.push_back(OldCA->getOperand(I)); - StructType *StructTy = - cast(GCL->getType()->getElementType()->getArrayElementType()); - - // Create the new init list. - std::vector CAList; - for (Function *F : Ctors) { - Type *Int32Ty = Type::getInt32Ty(GCL->getContext()); - if (F) { - CSVals[0] = ConstantInt::get(Int32Ty, 65535); - CSVals[1] = F; - } else { - CSVals[0] = ConstantInt::get(Int32Ty, 0x7fffffff); - CSVals[1] = Constant::getNullValue(StructTy->getElementType(1)); - } - // FIXME: Only allow the 3-field form in LLVM 4.0. - size_t NumElts = StructTy->getNumElements(); - if (NumElts > 2) - CSVals[2] = Constant::getNullValue(StructTy->getElementType(2)); - CAList.push_back( - ConstantStruct::get(StructTy, makeArrayRef(CSVals, NumElts))); - } - - // Create the array initializer. - Constant *CA = - ConstantArray::get(ArrayType::get(StructTy, CAList.size()), CAList); + // Create the new array initializer. + ArrayType *ATy = + ArrayType::get(OldCA->getType()->getElementType(), CAList.size()); + Constant *CA = ConstantArray::get(ATy, CAList); // If we didn't change the number of elements, don't create a new GV. - if (CA->getType() == GCL->getInitializer()->getType()) { + if (CA->getType() == OldCA->getType()) { GCL->setInitializer(CA); return; } @@ -82,7 +64,7 @@ void installGlobalCtors(GlobalVariable *GCL, /// Given a llvm.global_ctors list that we can understand, /// return a list of the functions and null terminator as a vector. -std::vector parseGlobalCtors(GlobalVariable *GV) { +std::vector parseGlobalCtors(GlobalVariable *GV) { if (GV->getInitializer()->isNullValue()) return std::vector(); ConstantArray *CA = cast(GV->getInitializer()); @@ -147,17 +129,15 @@ bool optimizeGlobalCtorsList(Module &M, bool MadeChange = false; // Loop over global ctors, optimizing them when we can. - for (unsigned i = 0; i != Ctors.size(); ++i) { + unsigned NumCtors = Ctors.size(); + BitVector CtorsToRemove(NumCtors); + for (unsigned i = 0; i != Ctors.size() && NumCtors > 0; ++i) { Function *F = Ctors[i]; // Found a null terminator in the middle of the list, prune off the rest of // the list. - if (!F) { - if (i != Ctors.size() - 1) { - Ctors.resize(i + 1); - MadeChange = true; - } - break; - } + if (!F) + continue; + DEBUG(dbgs() << "Optimizing Global Constructor: " << *F << "\n"); // We cannot simplify external ctor functions. @@ -166,9 +146,10 @@ bool optimizeGlobalCtorsList(Module &M, // If we can evaluate the ctor at compile time, do. if (ShouldRemove(F)) { - Ctors.erase(Ctors.begin() + i); + Ctors[i] = nullptr; + CtorsToRemove.set(i); + NumCtors--; MadeChange = true; - --i; continue; } } @@ -176,7 +157,7 @@ bool optimizeGlobalCtorsList(Module &M, if (!MadeChange) return false; - installGlobalCtors(GlobalCtors, Ctors); + removeGlobalCtors(GlobalCtors, CtorsToRemove); return true; } diff --git a/test/Transforms/GlobalOpt/preserve-comdats.ll b/test/Transforms/GlobalOpt/preserve-comdats.ll new file mode 100644 index 00000000000..08188b9d427 --- /dev/null +++ b/test/Transforms/GlobalOpt/preserve-comdats.ll @@ -0,0 +1,37 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s + +$comdat_global = comdat any + +@comdat_global = weak_odr global i8 0, comdat $comdat_global +@simple_global = internal global i8 0 +; CHECK: @comdat_global = weak_odr global i8 0, comdat $comdat_global +; CHECK: @simple_global = internal global i8 42 + +@llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 65535, void ()* @init_comdat_global, i8* @comdat_global }, + { i32, void ()*, i8* } { i32 65535, void ()* @init_simple_global, i8* null } +] +; CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] +; CHECK: [{ i32, void ()*, i8* } { i32 65535, void ()* @init_comdat_global, i8* @comdat_global }] + +define void @init_comdat_global() { + store i8 42, i8* @comdat_global + ret void +} +; CHECK: define void @init_comdat_global() + +define internal void @init_simple_global() comdat $comdat_global { + store i8 42, i8* @simple_global + ret void +} +; CHECK-NOT: @init_simple_global() + +define i8* @use_simple() { + ret i8* @simple_global +} +; CHECK: define i8* @use_simple() + +define i8* @use_comdat() { + ret i8* @comdat_global +} +; CHECK: define i8* @use_comdat()