Implement protected visibility. This partly implements PR1363. Linker
should be taught to deal with protected symbols.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@36565 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/BytecodeFormat.html b/docs/BytecodeFormat.html
index f479ca5..1dc9c74 100644
--- a/docs/BytecodeFormat.html
+++ b/docs/BytecodeFormat.html
@@ -1044,7 +1044,7 @@
     </tr>
     <tr>
       <td><a href="#bit">bit(10-12)</a></td>
-      <td class="td_left">Visibility style: 0=Default, 1=Hidden.</td>
+      <td class="td_left">Visibility style: 0=Default, 1=Hidden, 2=Protected.</td>
     </tr>
     <tr>
       <td><a href="#bit">bit(13-31)</a></td>
@@ -1506,7 +1506,7 @@
     </tr>
     <tr>
       <td><a href="#bit">bit(16-18)</a></td>
-      <td class="td_left">Visibility style: 0=Default, 1=Hidden.</td>
+      <td class="td_left">Visibility style: 0=Default, 1=Hidden, 2=Protected.</td>
     </tr>
     <tr>
       <td><a href="#bit">bit(19-31)</a></td>
diff --git a/docs/LangRef.html b/docs/LangRef.html
index 67a2fc8..58e0e3c 100644
--- a/docs/LangRef.html
+++ b/docs/LangRef.html
@@ -591,6 +591,13 @@
     directly.
   </dd>
 
+  <dt><b>"<tt>protected</tt>" - Protected style</b>:</dt>
+
+  <dd>On ELF, protected visibility indicates that the symbol will be placed in
+  the dynamic symbol table, but that references within the defining module will
+  bind to the local symbol. That is, the symbol cannot be overridden by another
+  module.
+  </dd>
 </dl>
 
 </div>
diff --git a/include/llvm/GlobalValue.h b/include/llvm/GlobalValue.h
index 014cdbe..4f6b1e6 100644
--- a/include/llvm/GlobalValue.h
+++ b/include/llvm/GlobalValue.h
@@ -43,7 +43,8 @@
   /// @brief An enumeration for the kinds of visibility of global values.
   enum VisibilityTypes {
     DefaultVisibility = 0,  ///< The GV is visible
-    HiddenVisibility        ///< The GV is hidden
+    HiddenVisibility,       ///< The GV is hidden
+    ProtectedVisibility     ///< The GV is protected
   };
 
 protected:
@@ -58,7 +59,7 @@
   // Note: VC++ treats enums as signed, so an extra bit is required to prevent
   // Linkage and Visibility from turning into negative values.
   LinkageTypes Linkage : 5;   // The linkage of this global
-  unsigned Visibility : 1;    // The visibility style of this global
+  unsigned Visibility : 2;    // The visibility style of this global
   unsigned Alignment : 16;    // Alignment of this symbol, must be power of two
   std::string Section;        // Section to emit this into, empty mean default
 public:
@@ -74,6 +75,9 @@
 
   VisibilityTypes getVisibility() const { return (VisibilityTypes)Visibility; }
   bool hasHiddenVisibility() const { return Visibility == HiddenVisibility; }
+  bool hasProtectedVisibility() const {
+    return Visibility == ProtectedVisibility;
+  }
   void setVisibility(VisibilityTypes V) { Visibility = V; }
   
   bool hasSection() const { return !Section.empty(); }
diff --git a/include/llvm/Target/TargetAsmInfo.h b/include/llvm/Target/TargetAsmInfo.h
index 60de430..b13a3fb 100644
--- a/include/llvm/Target/TargetAsmInfo.h
+++ b/include/llvm/Target/TargetAsmInfo.h
@@ -256,7 +256,11 @@
     /// HiddenDirective - This directive, if non-null, is used to declare a
     /// global or function as having hidden visibility.
     const char *HiddenDirective;          // Defaults to "\t.hidden\t".
-    
+
+    /// ProtectedDirective - This directive, if non-null, is used to declare a
+    /// global or function as having protected visibility.
+    const char *ProtectedDirective;       // Defaults to "\t.protected\t".
+
     //===--- Dwarf Emission Directives -----------------------------------===//
 
     /// AbsoluteSectionOffsets - True if we should emit abolute section
@@ -523,6 +527,9 @@
     const char *getHiddenDirective() const {
       return HiddenDirective;
     }
+    const char *getProtectedDirective() const {
+      return ProtectedDirective;
+    }
     bool isAbsoluteSectionOffsets() const {
       return AbsoluteSectionOffsets;
     }
diff --git a/lib/AsmParser/Lexer.l b/lib/AsmParser/Lexer.l
index 382ce24..b67f6ff 100644
--- a/lib/AsmParser/Lexer.l
+++ b/lib/AsmParser/Lexer.l
@@ -206,6 +206,7 @@
 dllimport       { return DLLIMPORT; }
 dllexport       { return DLLEXPORT; }
 hidden          { return HIDDEN; }
+protected       { return PROTECTED; }
 extern_weak     { return EXTERN_WEAK; }
 external        { return EXTERNAL; }
 thread_local    { return THREAD_LOCAL; }
diff --git a/lib/AsmParser/Lexer.l.cvs b/lib/AsmParser/Lexer.l.cvs
index 382ce24..b67f6ff 100644
--- a/lib/AsmParser/Lexer.l.cvs
+++ b/lib/AsmParser/Lexer.l.cvs
@@ -206,6 +206,7 @@
 dllimport       { return DLLIMPORT; }
 dllexport       { return DLLEXPORT; }
 hidden          { return HIDDEN; }
+protected       { return PROTECTED; }
 extern_weak     { return EXTERN_WEAK; }
 external        { return EXTERNAL; }
 thread_local    { return THREAD_LOCAL; }
diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y
index c47b6fc..63f2261 100644
--- a/lib/AsmParser/llvmAsmParser.y
+++ b/lib/AsmParser/llvmAsmParser.y
@@ -1099,7 +1099,7 @@
 %token NORETURN INREG SRET NOUNWIND
 
 // Visibility Styles
-%token DEFAULT HIDDEN
+%token DEFAULT HIDDEN PROTECTED
 
 %start Module
 %%
@@ -1180,9 +1180,10 @@
   ;
 
 GVVisibilityStyle
-  : /*empty*/ { $$ = GlobalValue::DefaultVisibility; }
-  | DEFAULT   { $$ = GlobalValue::DefaultVisibility; }
-  | HIDDEN    { $$ = GlobalValue::HiddenVisibility;  }
+  : /*empty*/ { $$ = GlobalValue::DefaultVisibility;   }
+  | DEFAULT   { $$ = GlobalValue::DefaultVisibility;   }
+  | HIDDEN    { $$ = GlobalValue::HiddenVisibility;    }
+  | PROTECTED { $$ = GlobalValue::ProtectedVisibility; }
   ;
 
 FunctionDeclareLinkage
diff --git a/lib/AsmParser/llvmAsmParser.y.cvs b/lib/AsmParser/llvmAsmParser.y.cvs
index c47b6fc..63f2261 100644
--- a/lib/AsmParser/llvmAsmParser.y.cvs
+++ b/lib/AsmParser/llvmAsmParser.y.cvs
@@ -1099,7 +1099,7 @@
 %token NORETURN INREG SRET NOUNWIND
 
 // Visibility Styles
-%token DEFAULT HIDDEN
+%token DEFAULT HIDDEN PROTECTED
 
 %start Module
 %%
@@ -1180,9 +1180,10 @@
   ;
 
 GVVisibilityStyle
-  : /*empty*/ { $$ = GlobalValue::DefaultVisibility; }
-  | DEFAULT   { $$ = GlobalValue::DefaultVisibility; }
-  | HIDDEN    { $$ = GlobalValue::HiddenVisibility;  }
+  : /*empty*/ { $$ = GlobalValue::DefaultVisibility;   }
+  | DEFAULT   { $$ = GlobalValue::DefaultVisibility;   }
+  | HIDDEN    { $$ = GlobalValue::HiddenVisibility;    }
+  | PROTECTED { $$ = GlobalValue::ProtectedVisibility; }
   ;
 
 FunctionDeclareLinkage
diff --git a/lib/Bytecode/Reader/Reader.cpp b/lib/Bytecode/Reader/Reader.cpp
index 99aac05..e75f0fc 100644
--- a/lib/Bytecode/Reader/Reader.cpp
+++ b/lib/Bytecode/Reader/Reader.cpp
@@ -1532,6 +1532,7 @@
   switch (VisibilityID) {
   case 0: Visibility = GlobalValue::DefaultVisibility; break;
   case 1: Visibility = GlobalValue::HiddenVisibility; break;
+  case 2: Visibility = GlobalValue::ProtectedVisibility; break;
   default:
    error("Unknown visibility type: " + utostr(VisibilityID));
    Visibility = GlobalValue::DefaultVisibility;
@@ -1767,6 +1768,7 @@
     switch (VisibilityID) {
     case 0: Visibility = GlobalValue::DefaultVisibility; break;
     case 1: Visibility = GlobalValue::HiddenVisibility; break;
+    case 2: Visibility = GlobalValue::ProtectedVisibility; break;
     default:
       error("Unknown visibility type: " + utostr(VisibilityID));
       Visibility = GlobalValue::DefaultVisibility;
diff --git a/lib/Bytecode/Writer/Writer.cpp b/lib/Bytecode/Writer/Writer.cpp
index f1c6f6c..b4a2691 100644
--- a/lib/Bytecode/Writer/Writer.cpp
+++ b/lib/Bytecode/Writer/Writer.cpp
@@ -957,8 +957,9 @@
 static unsigned getEncodedVisibility(const GlobalValue *GV) {
   switch (GV->getVisibility()) {
   default: assert(0 && "Invalid visibility!");
-  case GlobalValue::DefaultVisibility: return 0;
-  case GlobalValue::HiddenVisibility:  return 1;
+  case GlobalValue::DefaultVisibility:   return 0;
+  case GlobalValue::HiddenVisibility:    return 1;
+  case GlobalValue::ProtectedVisibility: return 2;
   }
 }
 
diff --git a/lib/Target/TargetAsmInfo.cpp b/lib/Target/TargetAsmInfo.cpp
index 8deda9f..37ab073 100644
--- a/lib/Target/TargetAsmInfo.cpp
+++ b/lib/Target/TargetAsmInfo.cpp
@@ -74,6 +74,7 @@
   UsedDirective(0),
   WeakRefDirective(0),
   HiddenDirective("\t.hidden\t"),
+  ProtectedDirective("\t.protected\t"),
   AbsoluteSectionOffsets(false),
   HasLEB128(false),
   HasDotLoc(false),
diff --git a/lib/Target/X86/X86ATTAsmPrinter.cpp b/lib/Target/X86/X86ATTAsmPrinter.cpp
index 03a2286..634f41b 100755
--- a/lib/Target/X86/X86ATTAsmPrinter.cpp
+++ b/lib/Target/X86/X86ATTAsmPrinter.cpp
@@ -125,9 +125,13 @@
     }
     break;
   }
-  if (F->hasHiddenVisibility())
+  if (F->hasHiddenVisibility()) {
     if (const char *Directive = TAI->getHiddenDirective())
       O << Directive << CurrentFnName << "\n";
+  } else if (F->hasProtectedVisibility()) {
+    if (const char *Directive = TAI->getProtectedDirective())
+      O << Directive << CurrentFnName << "\n";
+  }
 
   if (Subtarget->isTargetELF())
     O << "\t.type " << CurrentFnName << ",@function\n";
@@ -322,7 +326,8 @@
       if (isCallOp && isa<Function>(GV)) {
         if (printGOT(TM, Subtarget)) {
           // Assemble call via PLT for non-local symbols
-          if (!GV->hasHiddenVisibility() || GV->isDeclaration())
+          if (!(GV->hasHiddenVisibility() || GV->hasProtectedVisibility()) ||
+              GV->isDeclaration())
             O << "@PLT";
         }
         if (Subtarget->isTargetCygMing() && GV->isDeclaration())
diff --git a/lib/Target/X86/X86AsmPrinter.cpp b/lib/Target/X86/X86AsmPrinter.cpp
index 76037f1..7e7dc88 100644
--- a/lib/Target/X86/X86AsmPrinter.cpp
+++ b/lib/Target/X86/X86AsmPrinter.cpp
@@ -155,9 +155,14 @@
     unsigned Size = TD->getTypeSize(Type);
     unsigned Align = TD->getPreferredAlignmentLog(I);
 
-    if (I->hasHiddenVisibility())
+    if (I->hasHiddenVisibility()) {
       if (const char *Directive = TAI->getHiddenDirective())
         O << Directive << name << "\n";
+    } else if (I->hasProtectedVisibility()) {
+      if (const char *Directive = TAI->getProtectedDirective())
+        O << Directive << name << "\n";
+    }
+    
     if (Subtarget->isTargetELF())
       O << "\t.type " << name << ",@object\n";
     
diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp
index ac68e8d..3a065b0 100644
--- a/lib/VMCore/AsmWriter.cpp
+++ b/lib/VMCore/AsmWriter.cpp
@@ -886,6 +886,7 @@
     default: assert(0 && "Invalid visibility style!");
     case GlobalValue::DefaultVisibility: break;
     case GlobalValue::HiddenVisibility: Out << "hidden "; break;
+    case GlobalValue::ProtectedVisibility: Out << "protected "; break;
     }
   }
 
@@ -914,6 +915,7 @@
   default: assert(0 && "Invalid visibility style!");
   case GlobalValue::DefaultVisibility: break;
   case GlobalValue::HiddenVisibility: Out << "hidden "; break;
+  case GlobalValue::ProtectedVisibility: Out << "protected "; break;
   }
 
   Out << "alias ";
@@ -998,6 +1000,7 @@
     default: assert(0 && "Invalid visibility style!");
     case GlobalValue::DefaultVisibility: break;
     case GlobalValue::HiddenVisibility: Out << "hidden "; break;
+    case GlobalValue::ProtectedVisibility: Out << "protected "; break;
     }
   }