summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/IPO/Internalize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/IPO/Internalize.cpp')
-rw-r--r--llvm/lib/Transforms/IPO/Internalize.cpp67
1 files changed, 47 insertions, 20 deletions
diff --git a/llvm/lib/Transforms/IPO/Internalize.cpp b/llvm/lib/Transforms/IPO/Internalize.cpp
index e1644819af61..db3b4384ce67 100644
--- a/llvm/lib/Transforms/IPO/Internalize.cpp
+++ b/llvm/lib/Transforms/IPO/Internalize.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
@@ -33,6 +34,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Utils/GlobalStatus.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
#define DEBUG_TYPE "internalize"
@@ -99,6 +101,12 @@ bool InternalizePass::shouldPreserveGV(const GlobalValue &GV) {
if (GV.hasDLLExportStorageClass())
return true;
+ // As the name suggests, externally initialized variables need preserving as
+ // they would be initialized elsewhere externally.
+ if (const auto *G = dyn_cast<GlobalVariable>(&GV))
+ if (G->isExternallyInitialized())
+ return true;
+
// Already local, has nothing to do.
if (GV.hasLocalLinkage())
return false;
@@ -111,14 +119,27 @@ bool InternalizePass::shouldPreserveGV(const GlobalValue &GV) {
}
bool InternalizePass::maybeInternalize(
- GlobalValue &GV, const DenseSet<const Comdat *> &ExternalComdats) {
+ GlobalValue &GV, DenseMap<const Comdat *, ComdatInfo> &ComdatMap) {
+ SmallString<0> ComdatName;
if (Comdat *C = GV.getComdat()) {
- if (ExternalComdats.count(C))
+ // For GlobalAlias, C is the aliasee object's comdat which may have been
+ // redirected. So ComdatMap may not contain C.
+ if (ComdatMap.lookup(C).External)
return false;
- // If a comdat is not externally visible we can drop it.
- if (auto GO = dyn_cast<GlobalObject>(&GV))
- GO->setComdat(nullptr);
+ if (auto *GO = dyn_cast<GlobalObject>(&GV)) {
+ // If a comdat with one member is not externally visible, we can drop it.
+ // Otherwise, the comdat can be used to establish dependencies among the
+ // group of sections. Thus we have to keep the comdat but switch it to
+ // nodeduplicate.
+ // Note: nodeduplicate is not necessary for COFF. wasm doesn't support
+ // nodeduplicate.
+ ComdatInfo &Info = ComdatMap.find(C)->second;
+ if (Info.Size == 1)
+ GO->setComdat(nullptr);
+ else if (!IsWasm)
+ C->setSelectionKind(Comdat::NoDeduplicate);
+ }
if (GV.hasLocalLinkage())
return false;
@@ -135,34 +156,36 @@ bool InternalizePass::maybeInternalize(
return true;
}
-// If GV is part of a comdat and is externally visible, keep track of its
-// comdat so that we don't internalize any of its members.
-void InternalizePass::checkComdatVisibility(
- GlobalValue &GV, DenseSet<const Comdat *> &ExternalComdats) {
+// If GV is part of a comdat and is externally visible, update the comdat size
+// and keep track of its comdat so that we don't internalize any of its members.
+void InternalizePass::checkComdat(
+ GlobalValue &GV, DenseMap<const Comdat *, ComdatInfo> &ComdatMap) {
Comdat *C = GV.getComdat();
if (!C)
return;
+ ComdatInfo &Info = ComdatMap.try_emplace(C).first->second;
+ ++Info.Size;
if (shouldPreserveGV(GV))
- ExternalComdats.insert(C);
+ Info.External = true;
}
bool InternalizePass::internalizeModule(Module &M, CallGraph *CG) {
bool Changed = false;
CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : nullptr;
- SmallPtrSet<GlobalValue *, 8> Used;
+ SmallVector<GlobalValue *, 4> Used;
collectUsedGlobalVariables(M, Used, false);
- // Collect comdat visiblity information for the module.
- DenseSet<const Comdat *> ExternalComdats;
+ // Collect comdat size and visiblity information for the module.
+ DenseMap<const Comdat *, ComdatInfo> ComdatMap;
if (!M.getComdatSymbolTable().empty()) {
for (Function &F : M)
- checkComdatVisibility(F, ExternalComdats);
+ checkComdat(F, ComdatMap);
for (GlobalVariable &GV : M.globals())
- checkComdatVisibility(GV, ExternalComdats);
+ checkComdat(GV, ComdatMap);
for (GlobalAlias &GA : M.aliases())
- checkComdatVisibility(GA, ExternalComdats);
+ checkComdat(GA, ComdatMap);
}
// We must assume that globals in llvm.used have a reference that not even
@@ -179,8 +202,9 @@ bool InternalizePass::internalizeModule(Module &M, CallGraph *CG) {
}
// Mark all functions not in the api as internal.
+ IsWasm = Triple(M.getTargetTriple()).isOSBinFormatWasm();
for (Function &I : M) {
- if (!maybeInternalize(I, ExternalComdats))
+ if (!maybeInternalize(I, ComdatMap))
continue;
Changed = true;
@@ -208,12 +232,15 @@ bool InternalizePass::internalizeModule(Module &M, CallGraph *CG) {
// FIXME: We should probably add this (and the __stack_chk_guard) via some
// type of call-back in CodeGen.
AlwaysPreserved.insert("__stack_chk_fail");
- AlwaysPreserved.insert("__stack_chk_guard");
+ if (Triple(M.getTargetTriple()).isOSAIX())
+ AlwaysPreserved.insert("__ssp_canary_word");
+ else
+ AlwaysPreserved.insert("__stack_chk_guard");
// Mark all global variables with initializers that are not in the api as
// internal as well.
for (auto &GV : M.globals()) {
- if (!maybeInternalize(GV, ExternalComdats))
+ if (!maybeInternalize(GV, ComdatMap))
continue;
Changed = true;
@@ -223,7 +250,7 @@ bool InternalizePass::internalizeModule(Module &M, CallGraph *CG) {
// Mark all aliases that are not in the api as internal as well.
for (auto &GA : M.aliases()) {
- if (!maybeInternalize(GA, ExternalComdats))
+ if (!maybeInternalize(GA, ComdatMap))
continue;
Changed = true;