Implement support for -fwritable-strings and make the code generator
merge string literals when it is not provided.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44394 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/CodeGen/CGExpr.cpp b/CodeGen/CGExpr.cpp
index b996eca..f9a00eb 100644
--- a/CodeGen/CGExpr.cpp
+++ b/CodeGen/CGExpr.cpp
@@ -304,18 +304,8 @@
   assert(!E->isWide() && "FIXME: Wide strings not supported yet!");
   const char *StrData = E->getStrData();
   unsigned Len = E->getByteLength();
-  
-  // FIXME: Can cache/reuse these within the module.
-  llvm::Constant *C=llvm::ConstantArray::get(std::string(StrData, StrData+Len));
-  
-  // Create a global variable for this.
-  C = new llvm::GlobalVariable(C->getType(), true, 
-                               llvm::GlobalValue::InternalLinkage,
-                               C, ".str", CurFn->getParent());
-  llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
-  llvm::Constant *Zeros[] = { Zero, Zero };
-  C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
-  return LValue::MakeAddr(C);
+  std::string StringLiteral(StrData, StrData+Len);
+  return LValue::MakeAddr(CGM.GetAddrOfConstantString(StringLiteral));
 }
 
 LValue CodeGenFunction::EmitPreDefinedLValue(const PreDefinedExpr *E) {
diff --git a/CodeGen/CodeGenModule.cpp b/CodeGen/CodeGenModule.cpp
index bc9d68a..e4d0f47 100644
--- a/CodeGen/CodeGenModule.cpp
+++ b/CodeGen/CodeGenModule.cpp
@@ -15,6 +15,7 @@
 #include "CodeGenFunction.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/Constants.h"
 #include "llvm/DerivedTypes.h"
@@ -24,9 +25,9 @@
 using namespace CodeGen;
 
 
-CodeGenModule::CodeGenModule(ASTContext &C, llvm::Module &M,
-                             const llvm::TargetData &TD)
-  : Context(C), TheModule(M), TheTargetData(TD),
+CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO,
+                             llvm::Module &M, const llvm::TargetData &TD)
+  : Context(C), Features(LO), TheModule(M), TheTargetData(TD),
     Types(C, M, TD), MemCpyFn(0), CFConstantStringClassRef(0) {}
 
 llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const ValueDecl *D) {
@@ -155,27 +156,6 @@
   return 0;
 }
 
-/// GenerateStringLiteral -- returns a pointer to the first element of a 
-/// character array containing the literal.
-static llvm::Constant *GenerateStringLiteral(const StringLiteral* E, 
-                                            CodeGenModule& CGModule) {
-  assert(!E->isWide() && "FIXME: Wide strings not supported yet!");
-  const char *StrData = E->getStrData();
-  unsigned Len = E->getByteLength();
-
-  // FIXME: Can cache/reuse these within the module.
-  llvm::Constant *C=llvm::ConstantArray::get(std::string(StrData, StrData+Len));
-
-  // Create a global variable for this.
-  C = new llvm::GlobalVariable(C->getType(), true, 
-                               llvm::GlobalValue::InternalLinkage,
-                               C, ".str", &CGModule.getModule());
-  llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
-  llvm::Constant *Zeros[] = { Zero, Zero };
-  C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
-  return C;
-}
-
 /// GenerateAggregateInit - Generate a Constant initaliser for global array or
 /// struct typed variables.
 static llvm::Constant *GenerateAggregateInit(const InitListExpr *ILE, 
@@ -244,7 +224,10 @@
   // Generate constant for string literal values.
   case Stmt::StringLiteralClass: {
     const StringLiteral *SLiteral = cast<StringLiteral>(Expression);
-    return GenerateStringLiteral(SLiteral, CGModule);
+    const char *StrData = SLiteral->getStrData();
+    unsigned Len = SLiteral->getByteLength();
+    return CGModule.GetAddrOfConstantString(std::string(StrData, 
+                                                        StrData + Len));
   }
 
   // Elide parenthesis.
@@ -455,3 +438,39 @@
   Entry.setValue(GV);
   return GV;
 }
+
+/// GenerateWritableString -- Creates storage for a string literal
+static llvm::Constant *GenerateStringLiteral(const std::string &str, 
+                                             bool constant,
+                                             CodeGenModule& CGModule) {
+  // Create Constant for this string literal
+  llvm::Constant *C=llvm::ConstantArray::get(str);
+  
+  // Create a global variable for this string
+  C = new llvm::GlobalVariable(C->getType(), constant, 
+                               llvm::GlobalValue::InternalLinkage,
+                               C, ".str", &CGModule.getModule());
+  llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
+  llvm::Constant *Zeros[] = { Zero, Zero };
+  C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
+  return C;
+}
+
+/// CodeGenModule::GetAddrOfConstantString -- returns a pointer to the first 
+/// element of a character array containing the literal.
+llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str) {
+  // Don't share any string literals if writable-strings is turned on.
+  if (Features.WritableStrings)
+    return GenerateStringLiteral(str, false, *this);
+  
+  llvm::StringMapEntry<llvm::Constant *> &Entry = 
+  ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
+
+  if (Entry.getValue())
+      return Entry.getValue();
+
+  // Create a global variable for this.
+  llvm::Constant *C = GenerateStringLiteral(str, true, *this);
+  Entry.setValue(C);
+  return C;
+}
diff --git a/CodeGen/CodeGenModule.h b/CodeGen/CodeGenModule.h
index a044c0d..1d7c30e 100644
--- a/CodeGen/CodeGenModule.h
+++ b/CodeGen/CodeGenModule.h
@@ -32,6 +32,7 @@
   class Decl;
   class ValueDecl;
   class FileVarDecl;
+  struct LangOptions;
     
 namespace CodeGen {
 
@@ -39,21 +40,25 @@
 /// while generating LLVM code.
 class CodeGenModule {
   ASTContext &Context;
+  const LangOptions &Features;
   llvm::Module &TheModule;
   const llvm::TargetData &TheTargetData;
   CodeGenTypes Types;
 
   llvm::Function *MemCpyFn;
   llvm::DenseMap<const Decl*, llvm::Constant*> GlobalDeclMap;
-  
+    
   llvm::StringMap<llvm::Constant*> CFConstantStringMap;
+  llvm::StringMap<llvm::Constant*> ConstantStringMap;
   llvm::Constant *CFConstantStringClassRef;
   
   std::vector<llvm::Function *> BuiltinFunctions;
 public:
-  CodeGenModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD);
+  CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M, 
+                const llvm::TargetData &TD);
   
   ASTContext &getContext() const { return Context; }
+  const LangOptions &getLangOptions() const { return Features; }
   llvm::Module &getModule() const { return TheModule; }
   CodeGenTypes &getTypes() { return Types; }
   
@@ -64,6 +69,7 @@
   ///
   llvm::Function *getBuiltinLibFunction(unsigned BuiltinID);
   llvm::Constant *GetAddrOfConstantCFString(const std::string& str);
+  llvm::Constant *GetAddrOfConstantString(const std::string& str);
   llvm::Function *getMemCpyFn();
   
   
diff --git a/CodeGen/ModuleBuilder.cpp b/CodeGen/ModuleBuilder.cpp
index 83c74d0..adc1878 100644
--- a/CodeGen/ModuleBuilder.cpp
+++ b/CodeGen/ModuleBuilder.cpp
@@ -18,9 +18,9 @@
 
 /// Init - Create an ModuleBuilder with the specified ASTContext.
 clang::CodeGen::CodeGenModule *
-clang::CodeGen::Init(ASTContext &Context, llvm::Module &M,
-                     const llvm::TargetData &TD) {
-  return new CodeGenModule(Context, M, TD);
+clang::CodeGen::Init(ASTContext &Context, const LangOptions &Features, 
+                     llvm::Module &M, const llvm::TargetData &TD) {
+  return new CodeGenModule(Context, Features, M, TD);
 }
 
 void clang::CodeGen::Terminate(CodeGenModule *B) {