From bbce49b9e5c6d7f05926b89f8e6fd235ae01c250 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 12 Aug 2008 00:12:39 +0000 Subject: [PATCH] Add ObjC constant string support for NeXT. Changed CGObjCRuntime::GenerateConstantString interface to take std::string instead of char* and size. Change ObjC functions which call on GenerateConstantString to bitcast result to appropriate type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@54659 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExprConstant.cpp | 6 +- lib/CodeGen/CGObjC.cpp | 7 +- lib/CodeGen/CGObjCGNU.cpp | 9 +- lib/CodeGen/CGObjCMac.cpp | 160 ++++++++++++++++++++++++++++++--- lib/CodeGen/CGObjCRuntime.h | 3 +- 5 files changed, 159 insertions(+), 26 deletions(-) diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 5865f21522..3d530e8210 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -61,8 +61,10 @@ public: return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } llvm::Constant *VisitObjCStringLiteral(const ObjCStringLiteral *E) { - return CGM.getObjCRuntime().GenerateConstantString( - E->getString()->getStrData(), E->getString()->getByteLength()); + std::string S(E->getString()->getStrData(), + E->getString()->getByteLength()); + llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(S); + return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); } llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index e152488bfa..6a8fe3c4f9 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -20,9 +20,10 @@ using namespace clang; using namespace CodeGen; /// Emits an instance of NSConstantString representing the object. -llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){ - return CGM.getObjCRuntime().GenerateConstantString( - E->getString()->getStrData(), E->getString()->getByteLength()); +llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E) { + std::string String(E->getString()->getStrData(), E->getString()->getByteLength()); + llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(String); + return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); } /// Emit a selector. diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index d77ae05939..ab896cc675 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -90,8 +90,7 @@ private: std::vector &V, const std::string &Name=""); public: CGObjCGNU(CodeGen::CodeGenModule &cgm); - virtual llvm::Constant *GenerateConstantString(const char *String, - const size_t length); + virtual llvm::Constant *GenerateConstantString(const std::string &String); virtual llvm::Value *GenerateMessageSend(llvm::IRBuilder<> &Builder, const llvm::Type *ReturnTy, llvm::Value *Sender, @@ -248,13 +247,11 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, //TODO: In case there are any crazy people still using the GNU runtime without //an OpenStep implementation, this should let them select their own class for //constant strings. -llvm::Constant *CGObjCGNU::GenerateConstantString(const char *String, const - size_t length) { - std::string Str(String, String +length); +llvm::Constant *CGObjCGNU::GenerateConstantString(const std::string &Str) { std::vector Ivars; Ivars.push_back(NULLPtr); Ivars.push_back(MakeConstantString(Str)); - Ivars.push_back(llvm::ConstantInt::get(IntTy, length)); + Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size())); llvm::Constant *ObjCStr = MakeGlobal( llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL), Ivars, ".objc_str"); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 205a8f55e9..ce53b5b231 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -14,17 +14,43 @@ #include "CGObjCRuntime.h" #include "CodeGenModule.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/LangOptions.h" +#include "llvm/Module.h" #include "llvm/Support/IRBuilder.h" using namespace clang; namespace { + +/// ObjCTypesHelper - Helper class that encapsulates lazy +/// construction of varies types used during ObjC generation. +class ObjCTypesHelper { +private: + CodeGen::CodeGenModule &CGM; + + const llvm::StructType *CFStringType; + llvm::Constant *CFConstantStringClassReference; + +public: + const llvm::Type *LongTy; + +public: + ObjCTypesHelper(CodeGen::CodeGenModule &cgm); + ~ObjCTypesHelper(); + + llvm::Constant *getCFConstantStringClassReference(); + const llvm::StructType *getCFStringType(); +}; + class CGObjCMac : public CodeGen::CGObjCRuntime { private: - CodeGen::CodeGenModule &CGM; + CodeGen::CodeGenModule &CGM; + ObjCTypesHelper ObjCTypes; + /// ObjCABI - FIXME: Not sure yet. + unsigned ObjCABI; /// UsedGlobals - list of globals to pack into the llvm.used metadata /// to prevent them from being clobbered. @@ -40,8 +66,7 @@ private: public: CGObjCMac(CodeGen::CodeGenModule &cgm); - virtual llvm::Constant *GenerateConstantString(const char *String, - const size_t length); + virtual llvm::Constant *GenerateConstantString(const std::string &String); virtual llvm::Value *GenerateMessageSend(llvm::IRBuilder<> &Builder, const llvm::Type *ReturnTy, @@ -108,9 +133,32 @@ public: virtual llvm::Function *ModuleInitFunction(); }; } // end anonymous namespace + +/* *** Helper Functions *** */ + +/// getConstantGEP() - Help routine to construct simple GEPs. +static llvm::Constant *getConstantGEP(llvm::Constant *C, + unsigned idx0, + unsigned idx1) { + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(llvm::Type::Int32Ty, idx0), + llvm::ConstantInt::get(llvm::Type::Int32Ty, idx1) + }; + return llvm::ConstantExpr::getGetElementPtr(C, Idxs, 2); +} + +/* *** CGObjCMac Public Interface *** */ -CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGM(cgm) { - EmitImageInfo(); +CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) + : CGM(cgm), + ObjCTypes(cgm), + ObjCABI(1) +{ + // FIXME: How does this get set in GCC? And what does it even mean? + if (ObjCTypes.LongTy != CGM.getTypes().ConvertType(CGM.getContext().IntTy)) + ObjCABI = 2; + + EmitImageInfo(); } // This has to perform the lookup every time, since posing and related @@ -127,11 +175,51 @@ llvm::Value *CGObjCMac::GetSelector(llvm::IRBuilder<> &Builder, Selector Sel) { return 0; } -/// Generate an NSConstantString object. -llvm::Constant *CGObjCMac::GenerateConstantString(const char *String, - const size_t length) { - assert(0 && "Cannot generate constant string for Mac runtime."); - return 0; +/// Generate a constant CFString object. +/* + struct __builtin_CFString { + const int *isa; // point to __CFConstantStringClassReference + int flags; + const char *str; + long length; + }; +*/ + +llvm::Constant *CGObjCMac::GenerateConstantString(const std::string &String) { + // FIXME: I have no idea what this constant is (it is a magic + // constant in GCC as well). Most likely the encoding of the string + // and at least one part of it relates to UTF-16. Is this just the + // code for UTF-8? Where is this handled for us? + // See: + unsigned flags = 0x07c8; + + // FIXME: Use some machinery to unique this. We can't reuse the CGM + // one since we put them in a different section. + llvm::Constant *StringC = llvm::ConstantArray::get(String); + llvm::Constant *StringGV = + new llvm::GlobalVariable(StringC->getType(), true, + llvm::GlobalValue::InternalLinkage, + StringC, ".str", &CGM.getModule()); + llvm::Constant *Values[4] = { + ObjCTypes.getCFConstantStringClassReference(), + llvm::ConstantInt::get(llvm::Type::Int32Ty, flags), + getConstantGEP(StringGV, 0, 0), // Decay array -> ptr + llvm::ConstantInt::get(ObjCTypes.LongTy, String.size()) + }; + + llvm::Constant *CFStringC = + llvm::ConstantStruct::get(ObjCTypes.getCFStringType(), + std::vector(Values, Values+4)); + + llvm::GlobalVariable *CFStringGV = + new llvm::GlobalVariable(CFStringC->getType(), true, + llvm::GlobalValue::InternalLinkage, + CFStringC, "", + &CGM.getModule()); + + CFStringGV->setSection("__DATA, __cfstring"); + + return CFStringGV; } /// Generates a message send where the super is the receiver. This is @@ -249,8 +337,6 @@ void CGObjCMac::EmitImageInfo() { if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) flags |= eImageInfo_GCOnly; - fprintf(stderr, "flags: %d (%d)\n", flags, CGM.getLangOptions().getGCMode()); - // Emitted as int[2]; llvm::Constant *values[2] = { llvm::ConstantInt::get(llvm::Type::Int32Ty, version), @@ -264,7 +350,11 @@ void CGObjCMac::EmitImageInfo() { "\01L_OBJC_IMAGE_INFO", &CGM.getModule()); - GV->setSection("__OBJC, __image_info,regular"); + if (ObjCABI == 1) { + GV->setSection("__OBJC, __image_info,regular"); + } else { + GV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip"); + } UsedGlobals.push_back(GV); } @@ -291,6 +381,50 @@ void CGObjCMac::FinishModule() { /* *** */ +ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) + : CGM(cgm), + CFStringType(0), + CFConstantStringClassReference(0), + LongTy(CGM.getTypes().ConvertType(CGM.getContext().LongTy)) +{ +} + +ObjCTypesHelper::~ObjCTypesHelper() { +} + +const llvm::StructType *ObjCTypesHelper::getCFStringType() { + if (!CFStringType) { + CFStringType = + llvm::StructType::get(llvm::PointerType::getUnqual(llvm::Type::Int32Ty), + llvm::Type::Int32Ty, + llvm::PointerType::getUnqual(llvm::Type::Int8Ty), + LongTy, + NULL); + + CGM.getModule().addTypeName("struct.__builtin_CFString", CFStringType); + } + + return CFStringType; +} + +llvm::Constant *ObjCTypesHelper::getCFConstantStringClassReference() { + if (!CFConstantStringClassReference) { + llvm::GlobalValue *GV = + new llvm::GlobalVariable(llvm::ArrayType::get(llvm::Type::Int32Ty, 0), + false, + llvm::GlobalValue::ExternalLinkage, + 0, "__CFConstantStringClassReference", + &CGM.getModule()); + + // Decay to pointer. + CFConstantStringClassReference = getConstantGEP(GV, 0, 0); + } + + return CFConstantStringClassReference; +} + +/* *** */ + CodeGen::CGObjCRuntime *CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM){ return new CGObjCMac(CGM); } diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 4610ef8b65..5e8172b665 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -59,8 +59,7 @@ public: virtual llvm::Value *GetSelector(BuilderType &Builder, Selector Sel) =0; /// Generate a constant string object - virtual llvm::Constant *GenerateConstantString(const char *String, - const size_t Length) = 0; + virtual llvm::Constant *GenerateConstantString(const std::string &String) = 0; /// Generate a category. A category contains a list of methods (and /// accompanying metadata) and a list of protocols. virtual void GenerateCategory(const char *ClassName, const char *CategoryName, -- 2.40.0