]> granicus.if.org Git - clang/commitdiff
Implement support for -fwritable-strings and make the code generator
authorChris Lattner <sabre@nondot.org>
Wed, 28 Nov 2007 05:34:05 +0000 (05:34 +0000)
committerChris Lattner <sabre@nondot.org>
Wed, 28 Nov 2007 05:34:05 +0000 (05:34 +0000)
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

CodeGen/CGExpr.cpp
CodeGen/CodeGenModule.cpp
CodeGen/CodeGenModule.h
CodeGen/ModuleBuilder.cpp
Driver/ASTConsumers.cpp
Driver/ASTConsumers.h
Driver/clang.cpp
include/clang/Basic/LangOptions.h
include/clang/CodeGen/ModuleBuilder.h

index b996ecacda5030e96c702bd261265e10f3e23dc4..f9a00ebfee3d73ad69eb99f409683e5e451abf8b 100644 (file)
@@ -304,18 +304,8 @@ LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
   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) {
index bc9d68a4f518bd8f587e858beeb69ea157c0dfce..e4d0f47b0c3fa8c17f980450bc4506472f05ed0b 100644 (file)
@@ -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 clang;
 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 @@ static llvm::Constant *GenerateConstantCast(const Expr *Expression,
   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 @@ static llvm::Constant *GenerateConstantExpr(const Expr* Expression,
   // 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 @@ GetAddrOfConstantCFString(const std::string &str) {
   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;
+}
index a044c0d02eef680418862dce1e6282015a2f1387..1d7c30e487293ed2aa5762dcd22afa09873698e7 100644 (file)
@@ -32,6 +32,7 @@ namespace clang {
   class Decl;
   class ValueDecl;
   class FileVarDecl;
+  struct LangOptions;
     
 namespace CodeGen {
 
@@ -39,21 +40,25 @@ namespace CodeGen {
 /// 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 @@ public:
   ///
   llvm::Function *getBuiltinLibFunction(unsigned BuiltinID);
   llvm::Constant *GetAddrOfConstantCFString(const std::string& str);
+  llvm::Constant *GetAddrOfConstantString(const std::string& str);
   llvm::Function *getMemCpyFn();
   
   
index 83c74d0cecaf5559cabad99bab0ff63b918cac80..adc187819617fd2b14861c0bfd69e9c1543d295f 100644 (file)
@@ -18,9 +18,9 @@ using namespace clang;
 
 /// 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) {
index bcc176e2c9ba07aff8f1624b097dbc53dbef04bc..bcf54f95bf850ff072eb82cab18bd2dd753e4a52 100644 (file)
@@ -550,15 +550,18 @@ namespace {
     llvm::Module *M;
     const llvm::TargetData *TD;
     ASTContext *Ctx;
+    const LangOptions &Features;
     CodeGen::CodeGenModule *Builder;
   public:
-    LLVMEmitter(Diagnostic &diags) : Diags(diags) {}
+    LLVMEmitter(Diagnostic &diags, const LangOptions &LO) 
+      : Diags(diags)
+      , Features(LO) {}
     virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
       Ctx = &Context;
       M = new llvm::Module("foo");
       M->setTargetTriple(Ctx->Target.getTargetTriple());
       TD = new llvm::TargetData(Ctx->Target.getTargetDescription());
-      Builder = CodeGen::Init(Context, *M, *TD);
+      Builder = CodeGen::Init(Context, Features, *M, *TD);
     }
     
     virtual void HandleTopLevelDecl(Decl *D) {
@@ -588,7 +591,7 @@ namespace {
   }; 
 } // end anonymous namespace
 
-ASTConsumer *clang::CreateLLVMEmitter(Diagnostic &Diags) {
-  return new LLVMEmitter(Diags);
+ASTConsumer *clang::CreateLLVMEmitter(Diagnostic &Diags, const LangOptions &Features) {
+  return new LLVMEmitter(Diags, Features);
 }
 
index 0591fdbef6783b11b63d8ac8f2ec829ee90d41c4..f7d2182f4049908279607efd70464e82d01e8982 100644 (file)
@@ -20,6 +20,7 @@ namespace clang {
 
 class ASTConsumer;
 class Diagnostic;
+struct LangOptions;
 
 ASTConsumer *CreateASTPrinter(FILE* FP = NULL);
 ASTConsumer *CreateASTDumper();
@@ -28,7 +29,7 @@ ASTConsumer *CreateCFGDumper(bool ViewGraphs = false);
 ASTConsumer *CreateLiveVarAnalyzer();
 ASTConsumer *CreateDeadStoreChecker(Diagnostic &Diags);
 ASTConsumer *CreateUnitValsChecker(Diagnostic &Diags);
-ASTConsumer *CreateLLVMEmitter(Diagnostic &Diags);
+ASTConsumer *CreateLLVMEmitter(Diagnostic &Diags, const LangOptions &Features);
 ASTConsumer *CreateCodeRewriterTest();
 ASTConsumer *CreateSerializationTest();
 
index b31cee44d84a75f9b4b0e7c84a59a02b44f0da1f..f85ab52cc77c3ca144932236e5dfba2a1d4926a5 100644 (file)
@@ -278,6 +278,10 @@ static llvm::cl::opt<bool>
 PascalStrings("fpascal-strings",
               llvm::cl::desc("Recognize and construct Pascal-style "
                              "string literals"));
+
+static llvm::cl::opt<bool>
+WritableStrings("fwritable-strings",
+              llvm::cl::desc("Store string literals as writable data."));
 // FIXME: add:
 //   -ansi
 //   -trigraphs
@@ -335,6 +339,7 @@ static void InitializeLanguageStandard(LangOptions &Options) {
   Options.Trigraphs = 1; // -trigraphs or -ansi
   Options.DollarIdents = 1;  // FIXME: Really a target property.
   Options.PascalStrings = PascalStrings;
+  Options.WritableStrings = WritableStrings;
 }
 
 //===----------------------------------------------------------------------===//
@@ -820,7 +825,7 @@ static void ProcessInputFile(Preprocessor &PP, unsigned MainFileID,
     break;
       
   case EmitLLVM:
-    Consumer = CreateLLVMEmitter(PP.getDiagnostics());
+    Consumer = CreateLLVMEmitter(PP.getDiagnostics(), PP.getLangOptions());
     break;
     
   case RewriteTest:
index 05e7189ea514d911ee63dc0d67af442422484296..d88dc4b9f9f93a4093be317f4009789f0d29ed79 100644 (file)
@@ -36,12 +36,13 @@ struct LangOptions {
   
   unsigned PascalStrings     : 1;  // Allow Pascal strings
   unsigned Boolean           : 1;  // Allow bool/true/false
+  unsigned WritableStrings   : 1;  // Allow writable strings
   
   LangOptions() {
     Trigraphs = BCPLComment = DollarIdents = Digraphs = HexFloats = 0;
     ObjC1 = ObjC2 = 0;
     C99 = Microsoft = CPlusPlus = CPlusPlus0x = NoExtensions = 0;
-    CXXOperatorNames = PascalStrings = Boolean = 0;
+    CXXOperatorNames = PascalStrings = Boolean = WritableStrings = 0;
   }
 };
 
index 245dff43f0d96f4eeb8bb538aa3c0ff6048db4f6..9ca364833704d00d4c2b581238dcff79b15f611c 100644 (file)
@@ -23,13 +23,14 @@ namespace clang {
   class ASTContext;
   class FunctionDecl;
   class FileVarDecl;
+  struct LangOptions;
 
 namespace CodeGen {
   class CodeGenModule;
   
   /// Init - Create an ModuleBuilder with the specified ASTContext.
-  CodeGenModule *Init(ASTContext &Context, llvm::Module &M,
-                  const llvm::TargetData &TD);
+  CodeGenModule *Init(ASTContext &Context, const LangOptions &Features,
+                      llvm::Module &M, const llvm::TargetData &TD);
   
   /// CodeGenFunction - Convert the AST node for a FunctionDecl into LLVM.
   ///