Newer
Older
// We still need to work out the details of handling UTF-16.
// See: <rdr://2996215>
Chris Lattner
committed
llvm::Constant *CodeGenModule::
GetAddrOfConstantCFString(const StringLiteral *Literal) {
bool isUTF16 = false;
if (Literal->containsNonAsciiOrNull()) {
// Convert from UTF-8 to UTF-16.
llvm::SmallVector<UTF16, 128> ToBuf(Literal->getByteLength());
const UTF8 *FromPtr = (UTF8 *)Literal->getStrData();
UTF16 *ToPtr = &ToBuf[0];
ConversionResult Result;
Result = ConvertUTF8toUTF16(&FromPtr, FromPtr+Literal->getByteLength(),
&ToPtr, ToPtr+Literal->getByteLength(),
strictConversion);
assert(Result == conversionOK && "UTF-8 to UTF-16 conversion failed");
isUTF16 = true;
// FIXME: Do something with the converted value!
}
std::string str(Literal->getStrData(), Literal->getByteLength());
llvm::StringMapEntry<llvm::Constant *> &Entry =
CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
if (llvm::Constant *C = Entry.getValue())
return C;
llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
llvm::Constant *Zeros[] = { Zero, Zero };
if (!CFConstantStringClassRef) {
const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
Ty = llvm::ArrayType::get(Ty, 0);
// FIXME: This is fairly broken if
// __CFConstantStringClassReference is already defined, in that it
// will get renamed and the user will most likely see an opaque
// error message. This is a general issue with relying on
// particular names.
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(Ty, false,
llvm::GlobalVariable::ExternalLinkage, 0,
"__CFConstantStringClassReference",
&getModule());
// Decay array -> ptr
CFConstantStringClassRef =
llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
QualType CFTy = getContext().getCFConstantStringType();
RecordDecl *CFRD = CFTy->getAsRecordType()->getDecl();
const llvm::StructType *STy =
cast<llvm::StructType>(getTypes().ConvertType(CFTy));
std::vector<llvm::Constant*> Fields;
RecordDecl::field_iterator Field = CFRD->field_begin();
FieldDecl *CurField = *Field++;
FieldDecl *NextField = *Field++;
appendFieldAndPadding(*this, Fields, CurField, NextField,
CFConstantStringClassRef, CFRD, STy);
CurField = NextField;
NextField = *Field++;
const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
appendFieldAndPadding(*this, Fields, CurField, NextField,
isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0)
: llvm::ConstantInt::get(Ty, 0x07C8),
CFRD, STy);
// String pointer.
CurField = NextField;
NextField = *Field++;
llvm::Constant *C = llvm::ConstantArray::get(str);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(C->getType(), true,
llvm::GlobalValue::InternalLinkage,
C, getContext().Target.getStringSymbolPrefix(true),
&getModule());
if (const char *Sect = getContext().Target.getCFStringDataSection())
GV->setSection(Sect);
appendFieldAndPadding(*this, Fields, CurField, NextField,
llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2),
CFRD, STy);
// String length.
CurField = NextField;
NextField = 0;
Ty = getTypes().ConvertType(getContext().LongTy);
appendFieldAndPadding(*this, Fields, CurField, NextField,
llvm::ConstantInt::get(Ty, str.length()), CFRD, STy);
// The struct.
C = llvm::ConstantStruct::get(STy, Fields);
GV = new llvm::GlobalVariable(C->getType(), true,
llvm::GlobalVariable::InternalLinkage, C,
getContext().Target.getCFStringSymbolPrefix(),
&getModule());
if (const char *Sect = getContext().Target.getCFStringSection())
GV->setSection(Sect);
Entry.setValue(GV);
/// GetStringForStringLiteral - Return the appropriate bytes for a
/// string literal, properly padded to match the literal type.
std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
const char *StrData = E->getStrData();
unsigned Len = E->getByteLength();
const ConstantArrayType *CAT =
getContext().getAsConstantArrayType(E->getType());
assert(CAT && "String isn't pointer or array!");
Chris Lattner
committed
// Resize the string to the right size.
std::string Str(StrData, StrData+Len);
uint64_t RealLen = CAT->getSize().getZExtValue();
Chris Lattner
committed
if (E->isWide())
RealLen *= getContext().Target.getWCharWidth()/8;
Str.resize(RealLen, '\0');
return Str;
}
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
/// constant array for the given string literal.
llvm::Constant *
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
// FIXME: This can be more efficient.
return GetAddrOfConstantString(GetStringForStringLiteral(S));
}
/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
/// array for the given ObjCEncodeExpr node.
llvm::Constant *
CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
std::string Str;
getContext().getObjCEncodingForType(E->getEncodedType(), Str);
return GetAddrOfConstantCString(Str);
}
/// GenerateWritableString -- Creates storage for a string literal.
static llvm::Constant *GenerateStringLiteral(const std::string &str,
bool constant,
CodeGenModule &CGM,
const char *GlobalName) {
// Create Constant for this string literal. Don't add a '\0'.
llvm::Constant *C = llvm::ConstantArray::get(str, false);
// Create a global variable for this string
return new llvm::GlobalVariable(C->getType(), constant,
llvm::GlobalValue::InternalLinkage,
C, GlobalName, &CGM.getModule());
}
/// GetAddrOfConstantString - Returns a pointer to a character array
/// containing the literal. This contents are exactly that of the
/// given string, i.e. it will not be null terminated automatically;
/// see GetAddrOfConstantCString. Note that whether the result is
/// actually a pointer to an LLVM constant depends on
/// Feature.WriteableStrings.
///
/// The result has pointer to array type.
llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str,
const char *GlobalName) {
bool IsConstant = !Features.WritableStrings;
// Get the default prefix if a name wasn't specified.
if (!GlobalName)
GlobalName = getContext().Target.getStringSymbolPrefix(IsConstant);
// Don't share any string literals if strings aren't constant.
if (!IsConstant)
return GenerateStringLiteral(str, false, *this, GlobalName);
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, GlobalName);
Entry.setValue(C);
return C;
}
/// GetAddrOfConstantCString - Returns a pointer to a character
/// array containing the literal and a terminating '\-'
/// character. The result has pointer to array type.
llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str,
const char *GlobalName){
return GetAddrOfConstantString(str + '\0', GlobalName);
/// EmitObjCPropertyImplementations - Emit information for synthesized
/// properties for an implementation.
void CodeGenModule::EmitObjCPropertyImplementations(const
ObjCImplementationDecl *D) {
for (ObjCImplementationDecl::propimpl_iterator i = D->propimpl_begin(),
e = D->propimpl_end(); i != e; ++i) {
ObjCPropertyImplDecl *PID = *i;
// Dynamic is just for type-checking.
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
ObjCPropertyDecl *PD = PID->getPropertyDecl();
// Determine which methods need to be implemented, some may have
// been overridden. Note that ::isSynthesized is not the method
// we want, that just indicates if the decl came from a
// property. What we want to know is if the method is defined in
// this implementation.
if (!D->getInstanceMethod(PD->getGetterName()))
CodeGenFunction(*this).GenerateObjCGetter(
const_cast<ObjCImplementationDecl *>(D), PID);
if (!PD->isReadOnly() &&
!D->getInstanceMethod(PD->getSetterName()))
CodeGenFunction(*this).GenerateObjCSetter(
const_cast<ObjCImplementationDecl *>(D), PID);
void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end();
I != E; ++I)
EmitTopLevelDecl(*I);
}
/// EmitTopLevelDecl - Emit code for a single top level declaration.
void CodeGenModule::EmitTopLevelDecl(Decl *D) {
// If an error has occurred, stop code generation, but continue
// parsing and semantic analysis (to ensure all warnings and errors
// are emitted).
if (Diags.hasErrorOccurred())
return;
switch (D->getKind()) {
case Decl::Function:
case Decl::Var:
EmitGlobal(cast<ValueDecl>(D));
break;
case Decl::Namespace:
EmitNamespace(cast<NamespaceDecl>(D));
break;
// Objective-C Decls
// Forward declarations, no (immediate) code generation.
case Decl::ObjCClass:
case Decl::ObjCForwardProtocol:
case Decl::ObjCCategory:
break;
case Decl::ObjCInterface:
// If we already laid out this interface due to an @class, and if we
// codegen'd a reference it, update the 'opaque' type to be a real type now.
Types.UpdateCompletedType(cast<ObjCInterfaceDecl>(D));
Runtime->GenerateProtocol(cast<ObjCProtocolDecl>(D));
break;
case Decl::ObjCCategoryImpl:
// Categories have properties but don't support synthesize so we
// can ignore them here.
Runtime->GenerateCategory(cast<ObjCCategoryImplDecl>(D));
break;
case Decl::ObjCImplementation: {
ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D);
EmitObjCPropertyImplementations(OMD);
Runtime->GenerateClass(OMD);
case Decl::ObjCMethod: {
ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(D);
// If this is not a prototype, emit the body.
if (OMD->getBody())
CodeGenFunction(*this).GenerateObjCMethod(OMD);
break;
}
case Decl::ObjCCompatibleAlias:
// compatibility-alias is a directive and has no code gen.
break;
case Decl::LinkageSpec: {
LinkageSpecDecl *LSD = cast<LinkageSpecDecl>(D);
if (LSD->getLanguage() == LinkageSpecDecl::lang_cxx)
ErrorUnsupported(LSD, "linkage spec");
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
// FIXME: implement C++ linkage, C linkage works mostly by C
// language reuse already.
break;
}
case Decl::FileScopeAsm: {
FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D);
std::string AsmString(AD->getAsmString()->getStrData(),
AD->getAsmString()->getByteLength());
const std::string &S = getModule().getModuleInlineAsm();
if (S.empty())
getModule().setModuleInlineAsm(AsmString);
else
getModule().setModuleInlineAsm(S + '\n' + AsmString);
break;
}
default:
// Make sure we handled everything we should, every other kind is
// a non-top-level decl. FIXME: Would be nice to have an
// isTopLevelDeclKind function. Need to recode Decl::Kind to do
// that easily.
assert(isa<TypeDecl>(D) && "Unsupported decl kind");
}
}