Add a new "available_externally" linkage type. This is intended
authorChris Lattner <sabre@nondot.org>
Mon, 13 Apr 2009 05:44:34 +0000 (05:44 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 13 Apr 2009 05:44:34 +0000 (05:44 +0000)
to support C99 inline, GNU extern inline, etc.  Related bugzilla's
include PR3517, PR3100, & PR2933.  Nothing uses this yet, but it
appears to work.

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

19 files changed:
docs/LangRef.html
include/llvm/CodeGen/MachineFunctionPass.h
include/llvm/GlobalValue.h
lib/AsmParser/LLLexer.cpp
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLToken.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/CodeGen/AsmPrinter/DwarfWriter.cpp
lib/CodeGen/MachineFunction.cpp
lib/Linker/LinkModules.cpp
lib/Target/CppBackend/CPPBackend.cpp
lib/VMCore/AsmWriter.cpp
test/CodeGen/Generic/externally_available.ll [new file with mode: 0644]
test/Transforms/GlobalDCE/externally_available.ll [new file with mode: 0644]
test/Transforms/Inline/externally_available.ll [new file with mode: 0644]
test/Transforms/InstCombine/odr-linkage.ll [new file with mode: 0644]
tools/llvm-nm/llvm-nm.cpp

index 457a56ab0cba6e3321c5e1b266508ef6c1ee7186..8ec11235dc2067495e23630833c63655d26a4893 100644 (file)
@@ -509,6 +509,17 @@ All Global Variables and Functions have one of the following types of linkage:
   '<tt>static</tt>' keyword in C.
   </dd>
 
+  <dt><tt><b><a name="available_externally">available_externally</a></b></tt>:
+  </dt>
+
+  <dd>Globals with "<tt>available_externally</tt>" linkage are never emitted
+  into the object file corresponding to the LLVM module.  They exist to
+  allow inlining and other optimizations to take place given knowledge of the
+  definition of the global, which is known to be somewhere outside the module.
+  Globals with <tt>available_externally</tt> linkage are allowed to be discarded
+  at will, and are otherwise the same as <tt>linkonce_odr</tt>.  This linkage
+  type is only allowed on definitions, not declarations.</dd>
+
   <dt><tt><b><a name="linkage_linkonce">linkonce</a></b></tt>: </dt>
 
   <dd>Globals with "<tt>linkonce</tt>" linkage are merged with other globals of
@@ -554,10 +565,10 @@ All Global Variables and Functions have one of the following types of linkage:
 
   <dt><tt><b><a name="linkage_linkonce">linkonce_odr</a></b></tt>: </dt>
   <dt><tt><b><a name="linkage_weak">weak_odr</a></b></tt>: </dt>
-  <dd>Some languages allow inequivalent globals to be merged, such as two
+  <dd>Some languages allow differing globals to be merged, such as two
     functions with different semantics.  Other languages, such as <tt>C++</tt>,
     ensure that only equivalent globals are ever merged (the "one definition
-    rule" - <tt>odr</tt>).  Such languages can use the <tt>linkonce_odr</tt>
+    rule" - "ODR").  Such languages can use the <tt>linkonce_odr</tt>
     and <tt>weak_odr</tt> linkage types to indicate that the global will only
     be merged with equivalent globals.  These linkage types are otherwise the
     same as their non-<tt>odr</tt> versions.
index 95bb2bf510d52c0cfae8e8c9418b8dea285d1be7..6b5e64abc46c92a7d4a876bb9b62b5175af5129c 100644 (file)
@@ -24,8 +24,9 @@
 
 namespace llvm {
 
+  // FIXME: This pass should declare that the pass does not invalidate any LLVM
+  // passes.
 struct MachineFunctionPass : public FunctionPass {
-
   explicit MachineFunctionPass(intptr_t ID) : FunctionPass(ID) {}
   explicit MachineFunctionPass(void *ID) : FunctionPass(ID) {}
 
@@ -36,14 +37,7 @@ protected:
   virtual bool runOnMachineFunction(MachineFunction &MF) = 0;
 
 public:
-  // FIXME: This pass should declare that the pass does not invalidate any LLVM
-  // passes.
-  bool runOnFunction(Function &F) {
-    return runOnMachineFunction(MachineFunction::get(&F));
-  }
-  
-private:
-  virtual void virtfn();  // out of line virtual fn to give class a home.
+  bool runOnFunction(Function &F);
 };
 
 } // End llvm namespace
index e6a82ef22e9735426e7aff4cc57a498b8c6804c9..50c613ef6a20a2f808dd0eca49140b501d52c601 100644 (file)
@@ -31,6 +31,7 @@ public:
   /// @brief An enumeration for the kinds of linkage for global values.
   enum LinkageTypes {
     ExternalLinkage = 0,///< Externally visible function
+    AvailableExternallyLinkage, ///< Available for inspection, not emission.
     LinkOnceAnyLinkage, ///< Keep one copy of function when linking (inline)
     LinkOnceODRLinkage, ///< Same, but only replaced by something equivalent.
     WeakAnyLinkage,     ///< Keep one copy of named function when linking (weak)
@@ -109,6 +110,9 @@ public:
   }
 
   bool hasExternalLinkage() const { return Linkage == ExternalLinkage; }
+  bool hasAvailableExternallyLinkage() const {
+    return Linkage == AvailableExternallyLinkage;
+  }
   bool hasLinkOnceLinkage() const {
     return Linkage == LinkOnceAnyLinkage || Linkage == LinkOnceODRLinkage;
   }
@@ -119,7 +123,8 @@ public:
   bool hasInternalLinkage() const { return Linkage == InternalLinkage; }
   bool hasPrivateLinkage() const { return Linkage == PrivateLinkage; }
   bool hasLocalLinkage() const {
-    return Linkage == InternalLinkage || Linkage == PrivateLinkage;
+    return Linkage == InternalLinkage || Linkage == PrivateLinkage ||
+           Linkage == AvailableExternallyLinkage;
   }
   bool hasDLLImportLinkage() const { return Linkage == DLLImportLinkage; }
   bool hasDLLExportLinkage() const { return Linkage == DLLExportLinkage; }
@@ -141,9 +146,10 @@ public:
   }
 
   /// isWeakForLinker - Whether the definition of this global may be replaced at
-  /// link time, whether the replacement is equivalent to the original or not.
+  /// link time.
   bool isWeakForLinker() const {
-    return (Linkage == WeakAnyLinkage ||
+    return (Linkage == AvailableExternallyLinkage ||
+            Linkage == WeakAnyLinkage ||
             Linkage == WeakODRLinkage ||
             Linkage == LinkOnceAnyLinkage ||
             Linkage == LinkOnceODRLinkage ||
index d4815d83d68f5392b282f2a9f058cc830c4e0e2a..b227af259f05f9faa8face651fedce57da30e6e5 100644 (file)
@@ -487,6 +487,7 @@ lltok::Kind LLLexer::LexIdentifier() {
 
   KEYWORD(private);
   KEYWORD(internal);
+  KEYWORD(available_externally);
   KEYWORD(linkonce);
   KEYWORD(linkonce_odr);
   KEYWORD(weak);
index 177161e3a613d3ab7c542b8187c0dca661282b89..d92957a6eff4cd58d90b4f764742a267431fe1e7 100644 (file)
@@ -764,6 +764,9 @@ bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage) {
   case lltok::kw_weak_odr:     Res = GlobalValue::WeakODRLinkage; break;
   case lltok::kw_linkonce:     Res = GlobalValue::LinkOnceAnyLinkage; break;
   case lltok::kw_linkonce_odr: Res = GlobalValue::LinkOnceODRLinkage; break;
+  case lltok::kw_available_externally:
+    Res = GlobalValue::AvailableExternallyLinkage;
+    break;
   case lltok::kw_appending:    Res = GlobalValue::AppendingLinkage; break;
   case lltok::kw_dllexport:    Res = GlobalValue::DLLExportLinkage; break;
   case lltok::kw_common:       Res = GlobalValue::CommonLinkage; break;
index 35cb4dbaa7473289c8cc9aafb2828f51b864c523..d8bd38a4a61d8786c70c1ff183171dcd878b4ef7 100644 (file)
@@ -37,7 +37,7 @@ namespace lltok {
     kw_global,  kw_constant,
 
     kw_private, kw_internal, kw_linkonce, kw_linkonce_odr, kw_weak, kw_weak_odr,
-    kw_appending, kw_dllimport, kw_dllexport, kw_common,
+    kw_appending, kw_dllimport, kw_dllexport, kw_common,kw_available_externally,
     kw_default, kw_hidden, kw_protected,
     kw_extern_weak,
     kw_external, kw_thread_local,
index 6f91dda50128407751a0a88937b51c1fd7150d65..8079acddb06a00507ec7ce6c716fbdfeef5f2562 100644 (file)
@@ -70,6 +70,7 @@ static GlobalValue::LinkageTypes GetDecodedLinkage(unsigned Val) {
   case 9: return GlobalValue::PrivateLinkage;
   case 10: return GlobalValue::WeakODRLinkage;
   case 11: return GlobalValue::LinkOnceODRLinkage;
+  case 12: return GlobalValue::AvailableExternallyLinkage;
   }
 }
 
index c836d39d259f7320a325d1c4bfae5a2f97bcd994..1937c7e26f151040ea54a20041cba9faecee9cb5 100644 (file)
@@ -287,6 +287,7 @@ static unsigned getEncodedLinkage(const GlobalValue *GV) {
   case GlobalValue::PrivateLinkage:      return 9;
   case GlobalValue::WeakODRLinkage:      return 10;
   case GlobalValue::LinkOnceODRLinkage:  return 11;
+  case GlobalValue::AvailableExternallyLinkage:  return 12;
   }
 }
 
index d19e9afaf028235504d3e1781f178662a8c4db0c..0979ced89a38ea6548ae90a019d9c030edd7052f 100644 (file)
@@ -443,7 +443,9 @@ bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) {
   }
 
   // Ignore debug and non-emitted data.
-  if (GV->getSection() == "llvm.metadata") return true;
+  if (GV->getSection() == "llvm.metadata" ||
+      GV->hasAvailableExternallyLinkage())
+    return true;
   
   if (!GV->hasAppendingLinkage()) return false;
 
index d59609b371ef67ea1ad4ef4a4d1d86a8479a12b2..4582f4a447f9bcd860146dd59f41da3c59783cd7 100644 (file)
@@ -3519,6 +3519,9 @@ class DwarfException : public Dwarf  {
   ///
   void EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo) {
     Function::LinkageTypes linkage = EHFrameInfo.function->getLinkage();
+    
+    assert(!EHFrameInfo.function->hasAvailableExternallyLinkage() && 
+           "Should not emit 'available externally' functions at all");
 
     Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection());
 
index bd7105fd28591c7ddd76a33eef1fc19f191c33ef..18a040e5540942b91a19ab3f43c09ab2b9b0b4c3 100644 (file)
@@ -38,8 +38,14 @@ using namespace llvm;
 static AnnotationID MF_AID(
   AnnotationManager::getID("CodeGen::MachineCodeForFunction"));
 
-// Out of line virtual function to home classes.
-void MachineFunctionPass::virtfn() {}
+bool MachineFunctionPass::runOnFunction(Function &F) {
+  // Do not codegen any 'available_externally' functions at all, they have
+  // definitions outside the translation unit.
+  if (F.hasAvailableExternallyLinkage())
+    return false;
+  
+  return runOnMachineFunction(MachineFunction::get(&F));
+}
 
 namespace {
   struct VISIBILITY_HIDDEN Printer : public MachineFunctionPass {
index 0ca4e10f5bf015e2374a5d005ec03b807f61eaff..4a15d88d8f369649df64db2d640a77cf3976ce1e 100644 (file)
@@ -480,9 +480,10 @@ static bool GetLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
   } else if (Src->isWeakForLinker()) {
     // At this point we know that Dest has LinkOnce, External*, Weak, Common,
     // or DLL* linkage.
-    if ((Dest->hasLinkOnceLinkage() &&
-          (Src->hasWeakLinkage() || Src->hasCommonLinkage())) ||
-        Dest->hasExternalWeakLinkage()) {
+    if (Dest->hasExternalWeakLinkage() ||
+        Dest->hasAvailableExternallyLinkage() ||
+        (Dest->hasLinkOnceLinkage() &&
+         (Src->hasWeakLinkage() || Src->hasCommonLinkage()))) {
       LinkFromSrc = true;
       LT = Src->getLinkage();
     } else {
index 8262408d15cdea3ce1ec16d38bc709198f5466ae..e89d5f9ddd1f14cb87f7cac9723b784b88dfe59c 100644 (file)
@@ -294,6 +294,8 @@ namespace {
       Out << "GlobalValue::InternalLinkage"; break;
     case GlobalValue::PrivateLinkage:
       Out << "GlobalValue::PrivateLinkage"; break;
+    case GlobalValue::AvailableExternallyLinkage:
+      Out << "GlobalValue::AvailableExternallyLinkage "; break;
     case GlobalValue::LinkOnceAnyLinkage:
       Out << "GlobalValue::LinkOnceAnyLinkage "; break;
     case GlobalValue::LinkOnceODRLinkage:
index b1bf42ea835069c874f0c2001c8095923e2de20a..e4dd9d6b83e17906a871b1be099f0e5cc6169213 100644 (file)
@@ -1225,6 +1225,9 @@ static void PrintLinkage(GlobalValue::LinkageTypes LT, raw_ostream &Out) {
   switch (LT) {
   case GlobalValue::PrivateLinkage:     Out << "private "; break;
   case GlobalValue::InternalLinkage:    Out << "internal "; break;
+  case GlobalValue::AvailableExternallyLinkage:
+    Out << "available_externally ";
+    break;
   case GlobalValue::LinkOnceAnyLinkage: Out << "linkonce "; break;
   case GlobalValue::LinkOnceODRLinkage: Out << "linkonce_odr "; break;
   case GlobalValue::WeakAnyLinkage:     Out << "weak "; break;
diff --git a/test/CodeGen/Generic/externally_available.ll b/test/CodeGen/Generic/externally_available.ll
new file mode 100644 (file)
index 0000000..73b6b98
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | llc | not grep test_
+
+; test_function should not be emitted to the .s file.
+define available_externally i32 @test_function() {
+  ret i32 4
+}
+
+; test_global should not be emitted to the .s file.
+@test_global = available_externally global i32 4
+
diff --git a/test/Transforms/GlobalDCE/externally_available.ll b/test/Transforms/GlobalDCE/externally_available.ll
new file mode 100644 (file)
index 0000000..ccdf7e1
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | opt -globaldce | llvm-dis | not grep test_
+
+; test_function should not be emitted to the .s file.
+define available_externally i32 @test_function() {
+  ret i32 4
+}
+
+; test_global should not be emitted to the .s file.
+@test_global = available_externally global i32 4
+
diff --git a/test/Transforms/Inline/externally_available.ll b/test/Transforms/Inline/externally_available.ll
new file mode 100644 (file)
index 0000000..68f7d65
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llvm-as < %s | opt -inline -constprop | llvm-dis > %t
+; RUN: not grep test_function %t
+; RUN: grep {ret i32 5} %t
+
+
+; test_function should not be emitted to the .s file.
+define available_externally i32 @test_function() {
+  ret i32 4
+}
+
+
+define i32 @result() {
+  %A = call i32 @test_function()
+  %B = add i32 %A, 1
+  ret i32 %B
+}
\ No newline at end of file
diff --git a/test/Transforms/InstCombine/odr-linkage.ll b/test/Transforms/InstCombine/odr-linkage.ll
new file mode 100644 (file)
index 0000000..96f8833
--- /dev/null
@@ -0,0 +1,19 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep {ret i32 10}
+
+@g1 = available_externally constant i32 1
+@g2 = linkonce_odr constant i32 2
+@g3 = weak_odr constant i32 3
+@g4 = internal constant i32 4
+
+define i32 @test() {
+  %A = load i32* @g1
+  %B = load i32* @g2
+  %C = load i32* @g3
+  %D = load i32* @g4
+  
+  %a = add i32 %A, %B
+  %b = add i32 %a, %C
+  %c = add i32 %b, %D
+  ret i32 %c
+}
+   
\ No newline at end of file
index 344951051e83767f6fa207553b1c5f681cc4aefd..324e0f67035c7021686ae7425a6746d6b9e52802 100644 (file)
@@ -69,7 +69,6 @@ namespace {
 }
 
 static char TypeCharForSymbol(GlobalValue &GV) {
-  /* FIXME: what to do with private linkage? */
   if (GV.isDeclaration())                                  return 'U';
   if (GV.hasLinkOnceLinkage())                             return 'C';
   if (GV.hasCommonLinkage())                               return 'C';
@@ -87,8 +86,11 @@ static char TypeCharForSymbol(GlobalValue &GV) {
 }
 
 static void DumpSymbolNameForGlobalValue(GlobalValue &GV) {
+  // Private linkage and available_externally linkage don't exist in symtab.
+  if (GV.hasPrivateLinkage() || GV.hasAvailableExternallyLinkage()) return;
+  
   const std::string SymbolAddrStr = "        "; // Not used yet...
-  char TypeChar = TypeCharForSymbol (GV);
+  char TypeChar = TypeCharForSymbol(GV);
   if ((TypeChar != 'U') && UndefinedOnly)
     return;
   if ((TypeChar == 'U') && DefinedOnly)
@@ -96,17 +98,17 @@ static void DumpSymbolNameForGlobalValue(GlobalValue &GV) {
   if (GV.hasLocalLinkage () && ExternalOnly)
     return;
   if (OutputFormat == posix) {
-    std::cout << GV.getName () << " " << TypeCharForSymbol (GV) << " "
+    std::cout << GV.getName () << " " << TypeCharForSymbol(GV) << " "
               << SymbolAddrStr << "\n";
   } else if (OutputFormat == bsd) {
-    std::cout << SymbolAddrStr << " " << TypeCharForSymbol (GV) << " "
+    std::cout << SymbolAddrStr << " " << TypeCharForSymbol(GV) << " "
               << GV.getName () << "\n";
   } else if (OutputFormat == sysv) {
     std::string PaddedName (GV.getName ());
     while (PaddedName.length () < 20)
       PaddedName += " ";
     std::cout << PaddedName << "|" << SymbolAddrStr << "|   "
-              << TypeCharForSymbol (GV)
+              << TypeCharForSymbol(GV)
               << "  |                  |      |     |\n";
   }
 }
@@ -122,10 +124,10 @@ static void DumpSymbolNamesFromModule(Module *M) {
               << "Name                  Value   Class        Type"
               << "         Size   Line  Section\n";
   }
-  std::for_each (M->begin (), M->end (), DumpSymbolNameForGlobalValue);
-  std::for_each (M->global_begin (), M->global_end (),
+  std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue);
+  std::for_each (M->global_begin(), M->global_end(),
                  DumpSymbolNameForGlobalValue);
-  std::for_each (M->alias_begin (), M->alias_end (),
+  std::for_each (M->alias_begin(), M->alias_end(),
                  DumpSymbolNameForGlobalValue);
 }