Add support emiting for 2/4 byte mergable strings to the ".rodata.str*"
section on ELF targets.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78066 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/TargetLoweringObjectFile.cpp b/lib/Target/TargetLoweringObjectFile.cpp
index f2c7988..7d8f529 100644
--- a/lib/Target/TargetLoweringObjectFile.cpp
+++ b/lib/Target/TargetLoweringObjectFile.cpp
@@ -79,18 +79,33 @@
   return true;
 }
 
-static bool isConstantString(const Constant *C) {
+/// IsNullTerminatedString - Return true if the specified constant (which is
+/// known to have a type that is an array of 1/2/4 byte elements) ends with a
+/// nul value and contains no other nuls in it.
+static bool IsNullTerminatedString(const Constant *C) {
+  const ArrayType *ATy = cast<ArrayType>(C->getType());
+  
   // First check: is we have constant array of i8 terminated with zero
-  const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
-  // Check, if initializer is a null-terminated string
-  if (CVA && CVA->isCString())
+  if (const ConstantArray *CVA = dyn_cast<ConstantArray>(C)) {
+    if (ATy->getNumElements() == 0) return false;
+
+    ConstantInt *Null =
+      dyn_cast<ConstantInt>(CVA->getOperand(ATy->getNumElements()-1));
+    if (Null == 0 || Null->getZExtValue() != 0)
+      return false; // Not null terminated.
+    
+    // Verify that the null doesn't occur anywhere else in the string.
+    for (unsigned i = 0, e = ATy->getNumElements()-1; i != e; ++i)
+      // Reject constantexpr elements etc.
+      if (!isa<ConstantInt>(CVA->getOperand(i)) ||
+          CVA->getOperand(i) == Null)
+        return false;
     return true;
+  }
 
   // Another possibility: [1 x i8] zeroinitializer
   if (isa<ConstantAggregateZero>(C))
-    if (const ArrayType *Ty = dyn_cast<ArrayType>(C->getType()))
-      return (Ty->getElementType() == Type::Int8Ty &&
-              Ty->getNumElements() == 1);
+    return ATy->getNumElements() == 1;
 
   return false;
 }
@@ -133,11 +148,23 @@
     default: llvm_unreachable("unknown relocation info kind");
     case Constant::NoRelocation:
       // If initializer is a null-terminated string, put it in a "cstring"
-      // section if the target has it.
-      if (isConstantString(C))
-        return SectionKind::getMergeable1ByteCString();
-      
-      // FIXME: Detect 2/4 byte strings.
+      // section of the right width.
+      if (const ArrayType *ATy = dyn_cast<ArrayType>(C->getType())) {
+        if (const IntegerType *ITy = 
+              dyn_cast<IntegerType>(ATy->getElementType())) {
+          if ((ITy->getBitWidth() == 8 || ITy->getBitWidth() == 16 ||
+               ITy->getBitWidth() == 32) &&
+              IsNullTerminatedString(C)) {
+            if (ITy->getBitWidth() == 8)
+              return SectionKind::getMergeable1ByteCString();
+            if (ITy->getBitWidth() == 16)
+              return SectionKind::getMergeable2ByteCString();
+                                         
+            assert(ITy->getBitWidth() == 32 && "Unknown width");
+            return SectionKind::getMergeable4ByteCString();
+          }
+        }
+      }
         
       // Otherwise, just drop it into a mergable constant section.  If we have
       // a section for this size, use it, otherwise use the arbitrary sized