If the target of an alias has internal linkage, then the
authorDuncan Sands <baldrick@free.fr>
Sun, 15 Feb 2009 09:56:08 +0000 (09:56 +0000)
committerDuncan Sands <baldrick@free.fr>
Sun, 15 Feb 2009 09:56:08 +0000 (09:56 +0000)
alias can be morphed into the target.  Implement this
transform, and fix a crash in the existing transform at
the same time.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@64583 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/IPO/GlobalOpt.cpp
test/Transforms/GlobalOpt/2009-02-15-BitcastAlias.ll [new file with mode: 0644]
test/Transforms/GlobalOpt/2009-02-15-ResolveAlias.ll [new file with mode: 0644]

index 7f636c9270154cde574539b220d39e2092722479..4208e9044e869c740e2637ab8b793401e99f2159 100644 (file)
@@ -50,6 +50,8 @@ STATISTIC(NumShrunkToBool  , "Number of global vars shrunk to booleans");
 STATISTIC(NumFastCallFns   , "Number of functions converted to fastcc");
 STATISTIC(NumCtorsEvaluated, "Number of static ctors evaluated");
 STATISTIC(NumNestRemoved   , "Number of nest attributes removed");
+STATISTIC(NumAliasesResolved, "Number of global aliases resolved");
+STATISTIC(NumAliasesRemoved, "Number of global aliases eliminated");
 
 namespace {
   struct VISIBILITY_HIDDEN GlobalOpt : public ModulePass {
@@ -2373,15 +2375,61 @@ bool GlobalOpt::ResolveAliases(Module &M) {
   bool Changed = false;
 
   for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
-       I != E; ++I) {
-    if (I->use_empty())
+       I != E;) {
+    Module::alias_iterator J = I++;
+    // If the aliasee may change at link time, nothing can be done - bail out.
+    if (J->mayBeOverridden())
       continue;
 
-    if (const GlobalValue *GV = I->resolveAliasedGlobal())
-      if (GV != I) {
-        I->replaceAllUsesWith(const_cast<GlobalValue*>(GV));
-        Changed = true;
-      }
+    Constant *Aliasee = J->getAliasee();
+    GlobalValue *Target = cast<GlobalValue>(Aliasee->stripPointerCasts());
+    bool hasOneUse = Target->hasOneUse() && Aliasee->hasOneUse();
+
+    // Make all users of the alias use the aliasee instead.
+    if (!J->use_empty()) {
+      J->replaceAllUsesWith(Aliasee);
+      ++NumAliasesResolved;
+      Changed = true;
+    }
+
+    // If the aliasee has internal linkage, give it the name and linkage
+    // of the alias, and delete the alias.  This turns:
+    //   define internal ... @f(...)
+    //   @a = alias ... @f
+    // into:
+    //   define ... @a(...)
+    if (!Target->hasInternalLinkage())
+      continue;
+
+    // The transform is only useful if the alias does not have internal linkage.
+    if (J->hasInternalLinkage())
+      continue;
+
+    // Be conservative and do not perform the transform if multiple aliases
+    // potentially target the aliasee.  TODO: Make this more aggressive.
+    if (!hasOneUse)
+      continue;
+
+    // Do not perform the transform if it would change the visibility.
+    if (J->getVisibility() != Target->getVisibility())
+      continue;
+
+    // Do not perform the transform if it would change the section.
+    if (J->hasSection() != Target->hasSection() ||
+        (J->hasSection() && J->getSection() != Target->getSection()))
+      continue;
+
+    // Give the aliasee the name and linkage of the alias.
+    Target->takeName(J);
+    Target->setLinkage(J->getLinkage());
+
+    // The alignment is the only remaining attribute that may not match.
+    Target->setAlignment(std::max(J->getAlignment(), Target->getAlignment()));
+
+    // Delete the alias.
+    M.getAliasList().erase(J);
+    ++NumAliasesRemoved;
+    Changed = true;
   }
 
   return Changed;
diff --git a/test/Transforms/GlobalOpt/2009-02-15-BitcastAlias.ll b/test/Transforms/GlobalOpt/2009-02-15-BitcastAlias.ll
new file mode 100644 (file)
index 0000000..e59c8df
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | opt -globalopt
+
+@g = external global i32
+
+@a = alias bitcast (i32* @g to i8*)
+
+define void @f() {
+       %tmp = load i8* @a
+       ret void
+}
diff --git a/test/Transforms/GlobalOpt/2009-02-15-ResolveAlias.ll b/test/Transforms/GlobalOpt/2009-02-15-ResolveAlias.ll
new file mode 100644 (file)
index 0000000..f042e59
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: llvm-as < %s | opt -globalopt | llvm-dis | grep {define void @a}
+
+define internal void @f() {
+       ret void
+}
+
+@a = alias void ()* @f
+
+define void @g() {
+       call void()* @a()
+       ret void
+}