Implement support for -fwritable-strings and make the code generator

merge string literals when it is not provided.

llvm-svn: 44394
This commit is contained in:
Chris Lattner
2007-11-28 05:34:05 +00:00
parent e04dc1fa4d
commit fb30009465
9 changed files with 77 additions and 51 deletions

View 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) {

View 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;
}

View 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();

View 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) {

View 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);
}

View 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();

View 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:

View 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;
}
};

View 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.
///