From: Chris Lattner Date: Wed, 28 Nov 2007 05:34:05 +0000 (+0000) Subject: Implement support for -fwritable-strings and make the code generator X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=45e8cbdce25c2e16c7aac2036a591f6190097ae6;p=clang 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 b996ecacda..f9a00ebfee 100644 --- a/CodeGen/CGExpr.cpp +++ b/CodeGen/CGExpr.cpp @@ -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) { diff --git a/CodeGen/CodeGenModule.cpp b/CodeGen/CodeGenModule.cpp index bc9d68a4f5..e4d0f47b0c 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 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(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 &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 a044c0d02e..1d7c30e487 100644 --- a/CodeGen/CodeGenModule.h +++ b/CodeGen/CodeGenModule.h @@ -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 GlobalDeclMap; - + llvm::StringMap CFConstantStringMap; + llvm::StringMap ConstantStringMap; llvm::Constant *CFConstantStringClassRef; std::vector 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(); diff --git a/CodeGen/ModuleBuilder.cpp b/CodeGen/ModuleBuilder.cpp index 83c74d0cec..adc1878196 100644 --- a/CodeGen/ModuleBuilder.cpp +++ b/CodeGen/ModuleBuilder.cpp @@ -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) { diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp index bcc176e2c9..bcf54f95bf 100644 --- a/Driver/ASTConsumers.cpp +++ b/Driver/ASTConsumers.cpp @@ -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); } diff --git a/Driver/ASTConsumers.h b/Driver/ASTConsumers.h index 0591fdbef6..f7d2182f40 100644 --- a/Driver/ASTConsumers.h +++ b/Driver/ASTConsumers.h @@ -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(); diff --git a/Driver/clang.cpp b/Driver/clang.cpp index b31cee44d8..f85ab52cc7 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -278,6 +278,10 @@ static llvm::cl::opt PascalStrings("fpascal-strings", llvm::cl::desc("Recognize and construct Pascal-style " "string literals")); + +static llvm::cl::opt +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: diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 05e7189ea5..d88dc4b9f9 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -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; } }; diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h index 245dff43f0..9ca3648337 100644 --- a/include/clang/CodeGen/ModuleBuilder.h +++ b/include/clang/CodeGen/ModuleBuilder.h @@ -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. ///