Handle ELF mergeable sections

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53306 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/X86/X86TargetAsmInfo.cpp b/lib/Target/X86/X86TargetAsmInfo.cpp
index 5e328fb..1217291 100644
--- a/lib/Target/X86/X86TargetAsmInfo.cpp
+++ b/lib/Target/X86/X86TargetAsmInfo.cpp
@@ -341,10 +341,11 @@
         // ELF targets usually have BSS sections
         return getBSSSection();
        case SectionKind::ROData:
-       case SectionKind::RODataMergeStr:
-       case SectionKind::RODataMergeConst:
-        // FIXME: Temporary
         return getReadOnlySection();
+       case SectionKind::RODataMergeStr:
+        return MergeableStringSection(GVar);
+       case SectionKind::RODataMergeConst:
+        return MergeableConstSection(GVar);
        case SectionKind::ThreadData:
         // ELF targets usually support TLS stuff
         return getTLSDataSection();
@@ -358,6 +359,66 @@
     assert(0 && "Unsupported global");
 }
 
+std::string
+X86ELFTargetAsmInfo::MergeableConstSection(const GlobalVariable *GV) const {
+  unsigned Flags = SectionFlagsForGlobal(GV, GV->getSection().c_str());
+  unsigned Size = SectionFlags::getEntitySize(Flags);
+
+  // FIXME: string here is temporary, until stuff will fully land in.
+  if (Size)
+    return ".rodata.cst" + utostr(Size);
+  else
+    return getReadOnlySection();
+}
+
+std::string
+X86ELFTargetAsmInfo::MergeableStringSection(const GlobalVariable *GV) const {
+  unsigned Flags = SectionFlagsForGlobal(GV, GV->getSection().c_str());
+  unsigned Size = SectionFlags::getEntitySize(Flags);
+
+  if (Size) {
+    // We also need alignment here
+    const TargetData *TD = X86TM->getTargetData();
+    unsigned Align = TD->getPreferredAlignment(GV);
+    if (Align < Size)
+      Align = Size;
+
+    // FIXME: string here is temporary, until stuff will fully land in.
+    return ".rodata.str" + utostr(Size) + ',' + utostr(Align);
+  } else
+    return getReadOnlySection();
+}
+
+unsigned
+X86ELFTargetAsmInfo::SectionFlagsForGlobal(const GlobalValue *GV,
+                                           const char* name) const {
+  unsigned Flags =
+    TargetAsmInfo::SectionFlagsForGlobal(GV,
+                                         GV->getSection().c_str());
+
+  // If there was decision to put stuff into mergeable section - calculate
+  // entity size
+  if (Flags & SectionFlags::Mergeable) {
+    const TargetData *TD = X86TM->getTargetData();
+    Constant *C = cast<GlobalVariable>(GV)->getInitializer();
+    const Type *Type;
+
+    if (Flags & SectionFlags::Strings) {
+      const ConstantArray *CVA = cast<ConstantArray>(C);
+      Type = CVA->getType()->getElementType();
+    } else
+      Type = C->getType();
+
+    unsigned Size = TD->getABITypeSize(Type);
+    if (Size > 32)
+      Size = 0;
+    Flags = SectionFlags::setEntitySize(Flags, Size);
+  }
+
+  return Flags;
+}
+
+
 std::string X86ELFTargetAsmInfo::PrintSectionFlags(unsigned flags) const {
   std::string Flags = ",\"";
 
diff --git a/lib/Target/X86/X86TargetAsmInfo.h b/lib/Target/X86/X86TargetAsmInfo.h
index 483b774..dd8d3d1 100644
--- a/lib/Target/X86/X86TargetAsmInfo.h
+++ b/lib/Target/X86/X86TargetAsmInfo.h
@@ -20,6 +20,7 @@
 
   // Forward declaration.
   class X86TargetMachine;
+  class GlobalVariable;
 
   struct X86TargetAsmInfo : public TargetAsmInfo {
     explicit X86TargetAsmInfo(const X86TargetMachine &TM);
@@ -47,7 +48,11 @@
                                            bool Global) const;
 
     virtual std::string SelectSectionForGlobal(const GlobalValue *GV) const;
+    virtual unsigned SectionFlagsForGlobal(const GlobalValue *GV,
+                                           const char* name) const;
     virtual std::string PrintSectionFlags(unsigned flags) const;
+    std::string MergeableConstSection(const GlobalVariable *GV) const;
+    std::string MergeableStringSection(const GlobalVariable *GV) const;
   };
 
   struct X86COFFTargetAsmInfo : public X86TargetAsmInfo {