objective-C modern translator. Fix up the translated

metadata to handle ivar bitfields. This is wip.
// rdar://13138459

llvm-svn: 174573
This commit is contained in:
Fariborz Jahanian 2013-02-07 01:53:15 +00:00
parent 8ea63242a4
commit 57dd66baa4
3 changed files with 327 additions and 34 deletions

View File

@ -133,6 +133,7 @@ namespace {
SmallVector<DeclRefExpr *, 32> BlockDeclRefs;
// Block related declarations.
SmallVector<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
@ -146,6 +147,13 @@ namespace {
llvm::DenseMap<ObjCInterfaceDecl *,
llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars;
// ivar bitfield grouping containers
llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups;
llvm::DenseMap<const ObjCIvarDecl* , unsigned> IvarGroupNumber;
// This container maps an <class, group number for ivar> tuple to the type
// of the struct where the bitfield belongs.
llvm::DenseMap<std::pair<const ObjCInterfaceDecl*, unsigned>, QualType> GroupRecordType;
// This maps an original source AST to it's rewritten form. This allows
// us to avoid rewriting the same node twice (which is very uncommon).
// This is needed to support some of the exotic property rewriting.
@ -340,6 +348,20 @@ namespace {
void RewriteImplicitCastObjCExpr(CastExpr *IE);
void RewriteLinkageSpec(LinkageSpecDecl *LSD);
// Computes ivar bitfield group no.
unsigned ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV);
// Names field decl. for ivar bitfield group.
void ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV, std::string &Result);
// Names struct type for ivar bitfield group.
void ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV, std::string &Result);
// Names symbol for ivar bitfield group field offset.
void ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV, std::string &Result);
// Given an ivar bitfield, it builds (or finds) its group record type.
QualType GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV);
QualType SynthesizeBitfieldGroupStructType(
ObjCIvarDecl *IV,
SmallVectorImpl<ObjCIvarDecl *> &IVars);
// Block rewriting.
void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
@ -800,11 +822,16 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
// Build name of symbol holding ivar offset.
std::string IvarOffsetName;
WriteInternalIvarName(ClassDecl, D, IvarOffsetName);
if (D->isBitField())
ObjCIvarBitfieldGroupOffset(D, IvarOffsetName);
else
WriteInternalIvarName(ClassDecl, D, IvarOffsetName);
std::string S = "(*(";
QualType IvarT = D->getType();
if (D->isBitField())
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
@ -852,6 +879,10 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
S += "((char *)self + ";
S += IvarOffsetName;
S += "))";
if (D->isBitField()) {
S += ".";
S += D->getNameAsString();
}
ReferencedIvars[const_cast<ObjCInterfaceDecl *>(ClassDecl)].insert(D);
return S;
}
@ -3882,6 +3913,126 @@ void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDec
}
unsigned RewriteModernObjC::ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV) {
const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
if (ObjCInterefaceHasBitfieldGroups.count(CDecl)) {
return IvarGroupNumber[IV];
}
unsigned GroupNo = 0;
SmallVector<const ObjCIvarDecl *, 8> IVars;
for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar())
IVars.push_back(IVD);
for (unsigned i = 0, e = IVars.size(); i < e; i++)
if (IVars[i]->isBitField()) {
IvarGroupNumber[IVars[i++]] = ++GroupNo;
while (i < e && IVars[i]->isBitField())
IvarGroupNumber[IVars[i++]] = GroupNo;
if (i < e)
--i;
}
ObjCInterefaceHasBitfieldGroups.insert(CDecl);
return IvarGroupNumber[IV];
}
QualType RewriteModernObjC::SynthesizeBitfieldGroupStructType(
ObjCIvarDecl *IV,
SmallVectorImpl<ObjCIvarDecl *> &IVars) {
std::string StructTagName;
ObjCIvarBitfieldGroupType(IV, StructTagName);
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct,
Context->getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Context->Idents.get(StructTagName));
for (unsigned i=0, e = IVars.size(); i < e; i++) {
ObjCIvarDecl *Ivar = IVars[i];
RD->addDecl(FieldDecl::Create(*Context, RD, SourceLocation(), SourceLocation(),
&Context->Idents.get(Ivar->getName()),
Ivar->getType(),
0, /*Expr *BW */Ivar->getBitWidth(), false,
ICIS_NoInit));
}
RD->completeDefinition();
return Context->getTagDeclType(RD);
}
QualType RewriteModernObjC::GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV) {
const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
std::pair<const ObjCInterfaceDecl*, unsigned> tuple = std::make_pair(CDecl, GroupNo);
if (GroupRecordType.count(tuple))
return GroupRecordType[tuple];
SmallVector<ObjCIvarDecl *, 8> IVars;
for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar()) {
if (IVD->isBitField())
IVars.push_back(const_cast<ObjCIvarDecl *>(IVD));
else {
if (!IVars.empty()) {
unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]);
// Generate the struct type for this group of bitfield ivars.
GroupRecordType[std::make_pair(CDecl, GroupNo)] =
SynthesizeBitfieldGroupStructType(IVars[0], IVars);
IVars.clear();
}
}
}
if (!IVars.empty()) {
// Do the last one.
unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]);
GroupRecordType[std::make_pair(CDecl, GroupNo)] =
SynthesizeBitfieldGroupStructType(IVars[0], IVars);
}
QualType RetQT = GroupRecordType[tuple];
assert(!RetQT.isNull() && "GetGroupRecordTypeForObjCIvarBitfield struct type is NULL");
return RetQT;
}
/// ObjCIvarBitfieldGroupDecl - Names field decl. for ivar bitfield group.
/// Name would be: classname__GRBF_n where n is the group number for this ivar.
void RewriteModernObjC::ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV,
std::string &Result) {
const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
Result += CDecl->getName();
Result += "__GRBF_";
unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
Result += utostr(GroupNo);
return;
}
/// ObjCIvarBitfieldGroupType - Names struct type for ivar bitfield group.
/// Name of the struct would be: classname__T_n where n is the group number for
/// this ivar.
void RewriteModernObjC::ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV,
std::string &Result) {
const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
Result += CDecl->getName();
Result += "__T_";
unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
Result += utostr(GroupNo);
return;
}
/// ObjCIvarBitfieldGroupOffset - Names symbol for ivar bitfield group field offset.
/// Name would be: OBJC_IVAR_$_classname__GRBF_n where n is the group number for
/// this ivar.
void RewriteModernObjC::ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV,
std::string &Result) {
Result += "OBJC_IVAR_$_";
ObjCIvarBitfieldGroupDecl(IV, Result);
}
#define SKIP_BITFIELDS(IX, ENDIX, VEC) { \
while ((IX < ENDIX) && VEC[IX]->isBitField()) \
++IX; \
if (IX < ENDIX) \
--IX; \
}
/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to
/// an objective-c class with ivars.
void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
@ -3915,7 +4066,19 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// struct/unions in objective-c classes.
for (unsigned i = 0, e = IVars.size(); i < e; i++)
RewriteLocallyDefinedNamedAggregates(IVars[i], Result);
// Insert named structs which are syntheized to group ivar bitfields
// to outer scope as well.
for (unsigned i = 0, e = IVars.size(); i < e; i++)
if (IVars[i]->isBitField()) {
ObjCIvarDecl *IV = IVars[i];
QualType QT = GetGroupRecordTypeForObjCIvarBitfield(IV);
RewriteObjCFieldDeclType(QT, Result);
Result += ";";
// skip over ivar bitfields in this group.
SKIP_BITFIELDS(i , e, IVars);
}
Result += "\nstruct ";
Result += CDecl->getNameAsString();
Result += "_IMPL {\n";
@ -3926,8 +4089,18 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Result += "_IVARS;\n";
}
for (unsigned i = 0, e = IVars.size(); i < e; i++)
RewriteObjCFieldDecl(IVars[i], Result);
for (unsigned i = 0, e = IVars.size(); i < e; i++) {
if (IVars[i]->isBitField()) {
ObjCIvarDecl *IV = IVars[i];
Result += "\tstruct ";
ObjCIvarBitfieldGroupType(IV, Result); Result += " ";
ObjCIvarBitfieldGroupDecl(IV, Result); Result += ";\n";
// skip over ivar bitfields in this group.
SKIP_BITFIELDS(i , e, IVars);
}
else
RewriteObjCFieldDecl(IVars[i], Result);
}
Result += "};\n";
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
@ -3946,9 +4119,18 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
if (Ivars.empty())
return;
llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput;
for (llvm::SmallPtrSet<ObjCIvarDecl *, 8>::iterator i = Ivars.begin(),
e = Ivars.end(); i != e; i++) {
ObjCIvarDecl *IvarDecl = (*i);
const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface();
unsigned GroupNo = 0;
if (IvarDecl->isBitField()) {
GroupNo = ObjCIvarBitfieldGroupNo(IvarDecl);
if (GroupSymbolOutput.count(std::make_pair(IDecl, GroupNo)))
continue;
}
Result += "\n";
if (LangOpts.MicrosoftExt)
Result += "__declspec(allocate(\".objc_ivar$B\")) ";
@ -3959,7 +4141,12 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
Result += "__declspec(dllimport) ";
Result += "unsigned long ";
WriteInternalIvarName(CDecl, IvarDecl, Result);
if (IvarDecl->isBitField()) {
ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
GroupSymbolOutput.insert(std::make_pair(IDecl, GroupNo));
}
else
WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += ";";
}
}
@ -6052,19 +6239,16 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
/// ivar offset.
void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
if (ivar->isBitField()) {
// FIXME: The hack below doesn't work for bitfields. For now, we simply
// place all bitfields at offset 0.
Result += "0";
} else {
Result += "__OFFSETOFIVAR__(struct ";
Result += ivar->getContainingInterface()->getNameAsString();
if (LangOpts.MicrosoftExt)
Result += "_IMPL";
Result += ", ";
Result += "__OFFSETOFIVAR__(struct ";
Result += ivar->getContainingInterface()->getNameAsString();
if (LangOpts.MicrosoftExt)
Result += "_IMPL";
Result += ", ";
if (ivar->isBitField())
ObjCIvarBitfieldGroupDecl(ivar, Result);
else
Result += ivar->getNameAsString();
Result += ")";
}
Result += ")";
}
/// WriteModernMetadataDeclarations - Writes out metadata declarations for modern ABI.
@ -6741,21 +6925,41 @@ static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj,
Result += "extern \"C\" unsigned long int ";
else
Result += "extern \"C\" __declspec(dllexport) unsigned long int ";
WriteInternalIvarName(CDecl, IvarDecl, Result);
if (Ivars[i]->isBitField())
RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
else
WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += " __attribute__ ((used, section (\"__DATA,__objc_ivar\")))";
Result += " = ";
RewriteObj.RewriteIvarOffsetComputation(IvarDecl, Result);
Result += ";\n";
if (Ivars[i]->isBitField()) {
// skip over rest of the ivar bitfields.
SKIP_BITFIELDS(i , e, Ivars);
}
}
}
static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj,
ASTContext *Context, std::string &Result,
ArrayRef<ObjCIvarDecl *> Ivars,
ArrayRef<ObjCIvarDecl *> OriginalIvars,
StringRef VarName,
ObjCInterfaceDecl *CDecl) {
if (Ivars.size() > 0) {
Write_IvarOffsetVar(RewriteObj, Context, Result, Ivars, CDecl);
if (OriginalIvars.size() > 0) {
Write_IvarOffsetVar(RewriteObj, Context, Result, OriginalIvars, CDecl);
SmallVector<ObjCIvarDecl *, 8> Ivars;
// strip off all but the first ivar bitfield from each group of ivars.
// Such ivars in the ivar list table will be replaced by their grouping struct
// 'ivar'.
for (unsigned i = 0, e = OriginalIvars.size(); i < e; i++) {
if (OriginalIvars[i]->isBitField()) {
Ivars.push_back(OriginalIvars[i]);
// skip over rest of the ivar bitfields.
SKIP_BITFIELDS(i , e, OriginalIvars);
}
else
Ivars.push_back(OriginalIvars[i]);
}
Result += "\nstatic ";
Write__ivar_list_t_TypeDecl(Result, Ivars.size());
@ -6771,22 +6975,35 @@ static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj,
else
Result += "\t {";
Result += "(unsigned long int *)&";
WriteInternalIvarName(CDecl, IvarDecl, Result);
if (Ivars[i]->isBitField())
RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
else
WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += ", ";
Result += "\""; Result += IvarDecl->getName(); Result += "\", ";
Result += "\"";
if (Ivars[i]->isBitField())
RewriteObj.ObjCIvarBitfieldGroupDecl(Ivars[i], Result);
else
Result += IvarDecl->getName();
Result += "\", ";
QualType IVQT = IvarDecl->getType();
if (IvarDecl->isBitField())
IVQT = RewriteObj.GetGroupRecordTypeForObjCIvarBitfield(IvarDecl);
std::string IvarTypeString, QuoteIvarTypeString;
Context->getObjCEncodingForType(IvarDecl->getType(), IvarTypeString,
Context->getObjCEncodingForType(IVQT, IvarTypeString,
IvarDecl);
RewriteObj.QuoteDoublequotes(IvarTypeString, QuoteIvarTypeString);
Result += "\""; Result += QuoteIvarTypeString; Result += "\", ";
// FIXME. this alignment represents the host alignment and need be changed to
// represent the target alignment.
unsigned Align = Context->getTypeAlign(IvarDecl->getType())/8;
unsigned Align = Context->getTypeAlign(IVQT)/8;
Align = llvm::Log2_32(Align);
Result += llvm::utostr(Align); Result += ", ";
CharUnits Size = Context->getTypeSizeInChars(IvarDecl->getType());
CharUnits Size = Context->getTypeSizeInChars(IVQT);
Result += llvm::utostr(Size.getQuantity());
if (i == e-1)
Result += "}}\n";
@ -7511,7 +7728,10 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
// Build name of symbol holding ivar offset.
std::string IvarOffsetName;
WriteInternalIvarName(clsDeclared, D, IvarOffsetName);
if (D->isBitField())
ObjCIvarBitfieldGroupOffset(D, IvarOffsetName);
else
WriteInternalIvarName(clsDeclared, D, IvarOffsetName);
ReferencedIvars[clsDeclared].insert(D);
@ -7535,6 +7755,8 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
SourceLocation(),
addExpr);
QualType IvarT = D->getType();
if (D->isBitField())
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
@ -7587,8 +7809,23 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
PE = new (Context) ParenExpr(OldRange.getBegin(),
OldRange.getEnd(),
Exp);
if (D->isBitField()) {
FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
D->getType(), 0,
/*BitWidth=*/D->getBitWidth(),
/*Mutable=*/true,
ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(),
FD->getType(), VK_LValue,
OK_Ordinary);
Replacement = ME;
Replacement = PE;
}
else
Replacement = PE;
}
ReplaceStmtWithRange(IV, Replacement, OldRange);

View File

@ -0,0 +1,52 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp
// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp
// rdar://13138459
// -Did="void*" -DSEL="void *" -DClass="void*"
@interface NSMutableArray {
id isa;
}
@end
typedef unsigned char BOOL;
typedef unsigned long NSUInteger;
__attribute__((visibility("hidden")))
@interface __NSArrayM : NSMutableArray {
NSUInteger _used;
NSUInteger _doHardRetain:1;
NSUInteger _doWeakAccess:1;
#if __LP64__
NSUInteger _size:62;
#else
NSUInteger _size:30;
#endif
NSUInteger _hasObjects:1;
NSUInteger _hasStrongReferences:1;
#if __LP64__
NSUInteger _offset:62;
#else
NSUInteger _offset:30;
#endif
unsigned long _mutations;
id *_list;
}
@end
id __CFAllocateObject2();
BOOL objc_collectingEnabled();
@implementation __NSArrayM
+ (id)__new:(const id [])objects :(NSUInteger)count :(BOOL)hasObjects :(BOOL)hasStrong :(BOOL)transferRetain {
__NSArrayM *newArray = (__NSArrayM *)__CFAllocateObject2();
newArray->_size = count;
newArray->_mutations = 1;
newArray->_doHardRetain = (hasObjects && hasStrong);
newArray->_doWeakAccess = (objc_collectingEnabled() && !hasStrong);
newArray->_hasObjects = hasObjects;
newArray->_hasStrongReferences = hasStrong;
newArray->_list = 0;
return *newArray->_list;
}
@end

View File

@ -1,5 +1,6 @@
// RUN: %clang_cc1 -E %s -o %t.mm
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s
// rdar://13138459
@interface Foo {
@private
@ -13,11 +14,14 @@
@implementation Foo
@end
// CHECK: struct Foo__T_1 {
// CHECK-NEXT: int : 1;
// CHECK-NEXT: int third : 1;
// CHECK-NEXT: int : 1;
// CHECK-NEXT: int fifth : 1;
// CHECK-NEXT: char : 0;
// CHECK-NEXT: } ;
// CHECK: struct Foo_IMPL {
// CHECK-NEXT: int first;
// CHECK-NEXT: int : 1;
// CHECK-NEXT: int third : 1;
// CHECK-NEXT: int : 1;
// CHECK-NEXT: int fifth : 1;
// CHECK-NEXT: char : 0;
// CHECK-NEXT: int first;
// CHECK-NEXT: struct Foo__T_1 Foo__GRBF_1;
// CHECK-NEXT: };