Re-did 60519. It turns out Darwin's handling of hidden visibility symbols are a bit...
authorEvan Cheng <evan.cheng@apple.com>
Fri, 5 Dec 2008 01:06:39 +0000 (01:06 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Fri, 5 Dec 2008 01:06:39 +0000 (01:06 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@60571 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
lib/Target/ARM/ARMISelLowering.cpp
lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp
lib/Target/PowerPC/PPCSubtarget.cpp
lib/Target/X86/AsmPrinter/X86ATTAsmPrinter.cpp
lib/Target/X86/AsmPrinter/X86ATTAsmPrinter.h
lib/Target/X86/X86Subtarget.cpp
test/CodeGen/PowerPC/hidden-vis-2.ll [new file with mode: 0644]
test/CodeGen/PowerPC/hidden-vis.ll [new file with mode: 0644]
test/CodeGen/X86/hidden-vis-2.ll
test/CodeGen/X86/hidden-vis-3.ll [new file with mode: 0644]
test/CodeGen/X86/hidden-vis-4.ll [new file with mode: 0644]

index 69452c13601f90c588fe5ea3be1e8ec19181207c..02a0ed624dca56dac9af9157551e169644b9d9ad 100644 (file)
@@ -830,9 +830,12 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
 /// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol
 /// even in non-static mode.
 static bool GVIsIndirectSymbol(GlobalValue *GV, Reloc::Model RelocM) {
-  return RelocM != Reloc::Static &&
-    (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
-     (GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode()));
+  // If symbol visibility is hidden, the extra load is not needed if
+  // the symbol is definitely defined in the current translation unit.
+  bool isDecl = GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode();
+  if (GV->hasHiddenVisibility() && (!isDecl && !GV->hasCommonLinkage()))
+    return false;
+  return RelocM != Reloc::Static && (isDecl || GV->mayBeOverridden());
 }
 
 SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op,
index ae6c3544bb9577fc047ca419520db1488f1ef56a..9d81acdb11702e48113dbee1876cc9b9a4777315 100644 (file)
@@ -32,6 +32,7 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Mangler.h"
 #include "llvm/Support/MathExtras.h"
@@ -73,11 +74,15 @@ namespace {
 
     /// GVNonLazyPtrs - Keeps the set of GlobalValues that require
     /// non-lazy-pointers for indirect access.
-    std::set<std::string> GVNonLazyPtrs;
+    StringSet<> GVNonLazyPtrs;
+
+    /// HiddenGVNonLazyPtrs - Keeps the set of GlobalValues with hidden
+    /// visibility that require non-lazy-pointers for indirect access.
+    StringSet<> HiddenGVNonLazyPtrs;
 
     /// FnStubs - Keeps the set of external function GlobalAddresses that the
     /// asm printer should generate stubs for.
-    std::set<std::string> FnStubs;
+    StringSet<> FnStubs;
 
     /// PCRelGVs - Keeps the set of GlobalValues used in pc relative
     /// constantpool.
@@ -141,7 +146,10 @@ namespace {
       if (!GV)
         Name += ACPV->getSymbol();
       if (ACPV->isNonLazyPointer()) {
-        GVNonLazyPtrs.insert(Name);
+        if (GV->hasHiddenVisibility())
+          HiddenGVNonLazyPtrs.insert(Name);
+        else
+          GVNonLazyPtrs.insert(Name);
         printSuffixedName(Name, "$non_lazy_ptr");
       } else if (ACPV->isStub()) {
         FnStubs.insert(Name);
@@ -927,9 +935,8 @@ bool ARMAsmPrinter::doFinalization(Module &M) {
     SwitchToDataSection("");
 
     // Output stubs for dynamically-linked functions
-    unsigned j = 1;
-    for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
-         i != e; ++i, ++j) {
+    for (StringSet<>::iterator i = FnStubs.begin(), e = FnStubs.end();
+         i != e; ++i) {
       if (TM.getRelocationModel() == Reloc::PIC_)
         SwitchToTextSection(".section __TEXT,__picsymbolstub4,symbol_stubs,"
                             "none,16", 0);
@@ -940,10 +947,10 @@ bool ARMAsmPrinter::doFinalization(Module &M) {
       EmitAlignment(2);
       O << "\t.code\t32\n";
 
-      std::string p = *i;
+      const char *p = i->getKeyData();
       printSuffixedName(p, "$stub");
       O << ":\n";
-      O << "\t.indirect_symbol " << *i << "\n";
+      O << "\t.indirect_symbol " << p << "\n";
       O << "\tldr ip, ";
       printSuffixedName(p, "$slp");
       O << "\n";
@@ -966,23 +973,37 @@ bool ARMAsmPrinter::doFinalization(Module &M) {
       SwitchToDataSection(".lazy_symbol_pointer", 0);
       printSuffixedName(p, "$lazy_ptr");
       O << ":\n";
-      O << "\t.indirect_symbol " << *i << "\n";
+      O << "\t.indirect_symbol " << p << "\n";
       O << "\t.long\tdyld_stub_binding_helper\n";
     }
     O << "\n";
 
     // Output non-lazy-pointers for external and common global variables.
-    if (!GVNonLazyPtrs.empty())
+    if (!GVNonLazyPtrs.empty()) {
       SwitchToDataSection(".non_lazy_symbol_pointer", 0);
-    for (std::set<std::string>::iterator i = GVNonLazyPtrs.begin(),
-           e = GVNonLazyPtrs.end(); i != e; ++i) {
-      std::string p = *i;
-      printSuffixedName(p, "$non_lazy_ptr");
-      O << ":\n";
-      O << "\t.indirect_symbol " << *i << "\n";
-      O << "\t.long\t0\n";
+      for (StringSet<>::iterator i =  GVNonLazyPtrs.begin(),
+             e = GVNonLazyPtrs.end(); i != e; ++i) {
+        const char *p = i->getKeyData();
+        printSuffixedName(p, "$non_lazy_ptr");
+        O << ":\n";
+        O << "\t.indirect_symbol " << p << "\n";
+        O << "\t.long\t0\n";
+      }
     }
 
+    if (!HiddenGVNonLazyPtrs.empty()) {
+      SwitchToSection(TAI->getDataSection());
+      for (StringSet<>::iterator i = HiddenGVNonLazyPtrs.begin(),
+             e = HiddenGVNonLazyPtrs.end(); i != e; ++i) {
+        const char *p = i->getKeyData();
+        EmitAlignment(2);
+        printSuffixedName(p, "$non_lazy_ptr");
+        O << ":\n";
+        O << "\t.long " << p << "\n";
+      }
+    }
+
+
     // Emit initial debug information.
     // FIXME: Dwarf support.
     //DW.EndModule();
index 3ed7265840147f263d12f1713b57d29458201843..8b37167f4ad3874a1adac59b7f6f274d939375b9 100644 (file)
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
-#include <set>
+#include "llvm/ADT/StringSet.h"
 using namespace llvm;
 
 STATISTIC(EmittedInsts, "Number of machine instrs printed");
 
 namespace {
   struct VISIBILITY_HIDDEN PPCAsmPrinter : public AsmPrinter {
-    std::set<std::string> FnStubs, GVStubs;
+    StringSet<> FnStubs, GVStubs, HiddenGVStubs;
     const PPCSubtarget &Subtarget;
 
     PPCAsmPrinter(raw_ostream &O, TargetMachine &TM, const TargetAsmInfo *T)
@@ -387,10 +387,18 @@ void PPCAsmPrinter::printOp(const MachineOperand &MO) {
 
     // External or weakly linked global variables need non-lazily-resolved stubs
     if (TM.getRelocationModel() != Reloc::Static) {
-      if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
-            GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
-        GVStubs.insert(Name);
-        printSuffixedName(Name, "$non_lazy_ptr");
+      if (GV->isDeclaration() || GV->mayBeOverridden()) {
+        if (GV->hasHiddenVisibility()) {
+          if (!GV->isDeclaration() && !GV->hasCommonLinkage())
+            O << Name;
+          else {
+            HiddenGVStubs.insert(Name);
+            printSuffixedName(Name, "$non_lazy_ptr");
+          }
+        } else {
+          GVStubs.insert(Name);
+          printSuffixedName(Name, "$non_lazy_ptr");
+        }
         if (GV->hasExternalWeakLinkage())
           ExtWeakSymbols.insert(GV);
         return;
@@ -416,7 +424,10 @@ void PPCAsmPrinter::printOp(const MachineOperand &MO) {
 void PPCAsmPrinter::EmitExternalGlobal(const GlobalVariable *GV) {
   std::string Name = getGlobalLinkName(GV);
   if (TM.getRelocationModel() != Reloc::Static) {
-    GVStubs.insert(Name);
+    if (GV->hasHiddenVisibility())
+      HiddenGVStubs.insert(Name);
+    else
+      GVStubs.insert(Name);
     printSuffixedName(Name, "$non_lazy_ptr");
     return;
   }
@@ -979,51 +990,70 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
 
   // Output stubs for dynamically-linked functions
   if (TM.getRelocationModel() == Reloc::PIC_) {
-    for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
+    for (StringSet<>::iterator i = FnStubs.begin(), e = FnStubs.end();
          i != e; ++i) {
       SwitchToTextSection("\t.section __TEXT,__picsymbolstub1,symbol_stubs,"
                           "pure_instructions,32");
       EmitAlignment(4);
-      std::string p = *i;
-      std::string L0p = (p[0]=='\"') ? "\"L0$" + p.substr(1) : "L0$" + p ;
+      const char *p = i->getKeyData();
+      bool hasQuote = p[0]=='\"';
       printSuffixedName(p, "$stub");
       O << ":\n";
-      O << "\t.indirect_symbol " << *i << '\n';
+      O << "\t.indirect_symbol " << p << '\n';
       O << "\tmflr r0\n";
-      O << "\tbcl 20,31," << L0p << '\n';
-      O << L0p << ":\n";
+      O << "\tbcl 20,31,";
+      if (hasQuote)
+        O << "\"L0$" << &p[1];
+      else
+        O << "L0$" << p;
+      O << '\n';
+      if (hasQuote)
+        O << "\"L0$" << &p[1];
+      else
+        O << "L0$" << p;
+      O << ":\n";
       O << "\tmflr r11\n";
       O << "\taddis r11,r11,ha16(";
       printSuffixedName(p, "$lazy_ptr");
-      O << "-" << L0p << ")\n";
+      O << "-";
+      if (hasQuote)
+        O << "\"L0$" << &p[1];
+      else
+        O << "L0$" << p;
+      O << ")\n";
       O << "\tmtlr r0\n";
       if (isPPC64)
         O << "\tldu r12,lo16(";
       else
         O << "\tlwzu r12,lo16(";
       printSuffixedName(p, "$lazy_ptr");
-      O << "-" << L0p << ")(r11)\n";
+      O << "-";
+      if (hasQuote)
+        O << "\"L0$" << &p[1];
+      else
+        O << "L0$" << p;
+      O << ")(r11)\n";
       O << "\tmtctr r12\n";
       O << "\tbctr\n";
       SwitchToDataSection(".lazy_symbol_pointer");
       printSuffixedName(p, "$lazy_ptr");
       O << ":\n";
-      O << "\t.indirect_symbol " << *i << '\n';
+      O << "\t.indirect_symbol " << p << '\n';
       if (isPPC64)
         O << "\t.quad dyld_stub_binding_helper\n";
       else
         O << "\t.long dyld_stub_binding_helper\n";
     }
   } else {
-    for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
+    for (StringSet<>::iterator i = FnStubs.begin(), e = FnStubs.end();
          i != e; ++i) {
       SwitchToTextSection("\t.section __TEXT,__symbol_stub1,symbol_stubs,"
                           "pure_instructions,16");
       EmitAlignment(4);
-      std::string p = *i;
+      const char *p = i->getKeyData();
       printSuffixedName(p, "$stub");
       O << ":\n";
-      O << "\t.indirect_symbol " << *i << '\n';
+      O << "\t.indirect_symbol " << p << '\n';
       O << "\tlis r11,ha16(";
       printSuffixedName(p, "$lazy_ptr");
       O << ")\n";
@@ -1038,7 +1068,7 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
       SwitchToDataSection(".lazy_symbol_pointer");
       printSuffixedName(p, "$lazy_ptr");
       O << ":\n";
-      O << "\t.indirect_symbol " << *i << '\n';
+      O << "\t.indirect_symbol " << p << '\n';
       if (isPPC64)
         O << "\t.quad dyld_stub_binding_helper\n";
       else
@@ -1061,12 +1091,12 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
   // Output stubs for external and common global variables.
   if (!GVStubs.empty()) {
     SwitchToDataSection(".non_lazy_symbol_pointer");
-    for (std::set<std::string>::iterator I = GVStubs.begin(),
-         E = GVStubs.end(); I != E; ++I) {
-      std::string p = *I;
+    for (StringSet<>::iterator i = GVStubs.begin(), e = GVStubs.end();
+         i != e; ++i) {
+      std::string p = i->getKeyData();
       printSuffixedName(p, "$non_lazy_ptr");
       O << ":\n";
-      O << "\t.indirect_symbol " << *I << '\n';
+      O << "\t.indirect_symbol " << p << '\n';
       if (isPPC64)
         O << "\t.quad\t0\n";
       else
@@ -1074,6 +1104,23 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
     }
   }
 
+  if (!HiddenGVStubs.empty()) {
+    SwitchToSection(TAI->getDataSection());
+    for (StringSet<>::iterator i = HiddenGVStubs.begin(), e = HiddenGVStubs.end();
+         i != e; ++i) {
+      std::string p = i->getKeyData();
+      EmitAlignment(isPPC64 ? 3 : 2);
+      printSuffixedName(p, "$non_lazy_ptr");
+      O << ":\n";
+      if (isPPC64)
+        O << "\t.quad\t";
+      else
+        O << "\t.long\t";
+      O << p << '\n';
+    }
+  }
+
+
   // Emit initial debug information.
   DW.EndModule();
 
index 14983fcf1de3c92fa38d964c85d8716bd3e01343..e63368bd6599253690a17568db486c941a1cdfc3 100644 (file)
@@ -141,8 +141,11 @@ bool PPCSubtarget::hasLazyResolverStub(const GlobalValue *GV) const {
   // We never hae stubs if HasLazyResolverStubs=false or if in static mode.
   if (!HasLazyResolverStubs || TM.getRelocationModel() == Reloc::Static)
     return false;
-  
+  // If symbol visibility is hidden, the extra load is not needed if
+  // the symbol is definitely defined in the current translation unit.
+  bool isDecl = GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode();
+  if (GV->hasHiddenVisibility() && !isDecl && !GV->hasCommonLinkage())
+    return false;
   return GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
-         GV->hasCommonLinkage() ||
-         (GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode());
+         GV->hasCommonLinkage() || isDecl;
 }
index 66319c398161ef286079d5213ff04ab8b7dc4cdd..76b1ddc2457a3042c500e2117d15050488781458 100644 (file)
@@ -391,6 +391,14 @@ void X86ATTAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
             FnStubs.insert(Name);
             printSuffixedName(Name, "$stub");
           }
+        } else if (GV->hasHiddenVisibility()) {
+          if (!GV->isDeclaration() && !GV->hasCommonLinkage())
+            // Definition is not definitely in the current translation unit.
+            O << Name;
+          else {
+            HiddenGVStubs.insert(Name);
+            printSuffixedName(Name, "$non_lazy_ptr");
+          }
         } else {
           GVStubs.insert(Name);
           printSuffixedName(Name, "$non_lazy_ptr");
@@ -875,6 +883,15 @@ void X86ATTAsmPrinter::printGVStub(const char *GV, const char *Prefix) {
   O << GV << "\n\t.long\t0\n";
 }
 
+/// printHiddenGVStub - Print stub for a hidden global value.
+///
+void X86ATTAsmPrinter::printHiddenGVStub(const char *GV, const char *Prefix) {
+  EmitAlignment(2);
+  printSuffixedName(GV, "$non_lazy_ptr", Prefix);
+  if (Prefix) O << Prefix;
+  O << ":\n" << TAI->getData32bitsDirective() << GV << '\n';
+}
+
 
 bool X86ATTAsmPrinter::doFinalization(Module &M) {
   // Print out module-level global variables here.
@@ -908,9 +925,8 @@ bool X86ATTAsmPrinter::doFinalization(Module &M) {
     SwitchToDataSection("");
 
     // Output stubs for dynamically-linked functions
-    unsigned j = 1;
     for (StringSet<>::iterator i = FnStubs.begin(), e = FnStubs.end();
-         i != e; ++i, ++j) {
+         i != e; ++i) {
       SwitchToDataSection("\t.section __IMPORT,__jump_table,symbol_stubs,"
                           "self_modifying_code+pure_instructions,5", 0);
       const char *p = i->getKeyData();
@@ -949,6 +965,13 @@ bool X86ATTAsmPrinter::doFinalization(Module &M) {
          i != e; ++i)
       printGVStub(i->getKeyData());
 
+    if (!HiddenGVStubs.empty()) {
+      SwitchToSection(TAI->getDataSection());
+      for (StringSet<>::iterator i = HiddenGVStubs.begin(), e = HiddenGVStubs.end();
+           i != e; ++i)
+        printHiddenGVStub(i->getKeyData());
+    }
+
     // Emit final debug information.
     DW.EndModule();
 
index 312c11d570ce5ed7463d3eada2853dc5b7586a7d..40a5b4fb1d7ec0e23e6e27340e669747b92eedc2 100644 (file)
@@ -121,13 +121,14 @@ struct VISIBILITY_HIDDEN X86ATTAsmPrinter : public AsmPrinter {
   void printModuleLevelGV(const GlobalVariable* GVar);
 
   void printGVStub(const char *GV, const char *Prefix = NULL);
+  void printHiddenGVStub(const char *GV, const char *Prefix = NULL);
 
   bool runOnMachineFunction(MachineFunction &F);
 
   void emitFunctionHeader(const MachineFunction &MF);
 
   // Necessary for Darwin to print out the apprioriate types of linker stubs
-  StringSet<> FnStubs, GVStubs, LinkOnceStubs;
+  StringSet<> FnStubs, GVStubs, HiddenGVStubs;
 
   // Necessary for dllexport support
   StringSet<> DLLExportedFns, DLLExportedGVs;
index c17f2dc68254ad444b2863158ea90285af7ea0de..b836471afc18f1537b85637a8b74b6bf278d7993 100644 (file)
@@ -40,10 +40,14 @@ bool X86Subtarget::GVRequiresExtraLoad(const GlobalValue* GV,
   if (TM.getRelocationModel() != Reloc::Static &&
       TM.getCodeModel() != CodeModel::Large) {
     if (isTargetDarwin()) {
-      return (!isDirectCall &&
-              (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
-               GV->hasCommonLinkage() ||
-               (GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode())));
+      bool isDecl = GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode();
+      if (GV->hasHiddenVisibility() &&
+          (Is64Bit || (!isDecl && !GV->hasCommonLinkage())))
+        // If symbol visibility is hidden, the extra load is not needed if
+        // target is x86-64 or the symbol is definitely defined in the current
+        // translation unit.
+        return false;
+      return !isDirectCall && (isDecl || GV->mayBeOverridden());
     } else if (isTargetELF()) {
       // Extra load is needed for all externally visible.
       if (isDirectCall)
diff --git a/test/CodeGen/PowerPC/hidden-vis-2.ll b/test/CodeGen/PowerPC/hidden-vis-2.ll
new file mode 100644 (file)
index 0000000..4c9ae55
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: llvm-as < %s | llc -mtriple=powerpc-apple-darwin9 | grep non_lazy_ptr | count 6
+
+@x = external hidden global i32                ; <i32*> [#uses=1]
+@y = extern_weak hidden global i32     ; <i32*> [#uses=1]
+
+define i32 @t() nounwind readonly {
+entry:
+       %0 = load i32* @x, align 4              ; <i32> [#uses=1]
+       %1 = load i32* @y, align 4              ; <i32> [#uses=1]
+       %2 = add i32 %1, %0             ; <i32> [#uses=1]
+       ret i32 %2
+}
diff --git a/test/CodeGen/PowerPC/hidden-vis.ll b/test/CodeGen/PowerPC/hidden-vis.ll
new file mode 100644 (file)
index 0000000..e04c89a
--- /dev/null
@@ -0,0 +1,9 @@
+; RUN: llvm-as < %s | llc -mtriple=powerpc-apple-darwin9 | not grep non_lazy_ptr
+
+@x = weak hidden global i32 0          ; <i32*> [#uses=1]
+
+define i32 @t() nounwind readonly {
+entry:
+       %0 = load i32* @x, align 4              ; <i32> [#uses=1]
+       ret i32 %0
+}
index 4df1c1c5b2140c4953c1f0b74d9ab748a3fce835..e000547f44f2ba2fb9339227d78d071a2a4b6650 100644 (file)
@@ -1,6 +1,5 @@
 ; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin9   | grep mov | count 1
 ; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 | not grep GOT
-; XFAIL: *
 
 @x = weak hidden global i32 0          ; <i32*> [#uses=1]
 
diff --git a/test/CodeGen/X86/hidden-vis-3.ll b/test/CodeGen/X86/hidden-vis-3.ll
new file mode 100644 (file)
index 0000000..81dc76e
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin9   | grep mov | count 3
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin9   | grep non_lazy_ptr
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin9   | grep long | count 2
+; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 | not grep GOT
+
+@x = external hidden global i32                ; <i32*> [#uses=1]
+@y = extern_weak hidden global i32     ; <i32*> [#uses=1]
+
+define i32 @t() nounwind readonly {
+entry:
+       %0 = load i32* @x, align 4              ; <i32> [#uses=1]
+       %1 = load i32* @y, align 4              ; <i32> [#uses=1]
+       %2 = add i32 %1, %0             ; <i32> [#uses=1]
+       ret i32 %2
+}
diff --git a/test/CodeGen/X86/hidden-vis-4.ll b/test/CodeGen/X86/hidden-vis-4.ll
new file mode 100644 (file)
index 0000000..e6936de
--- /dev/null
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin9 | grep non_lazy_ptr
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin9 | grep long
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin9 | grep comm
+
+@x = common hidden global i32 0                ; <i32*> [#uses=1]
+
+define i32 @t() nounwind readonly {
+entry:
+       %0 = load i32* @x, align 4              ; <i32> [#uses=1]
+       ret i32 %0
+}