From 57dd66baa4ca084e99d9438d09c96c46716c7ebe Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 7 Feb 2013 01:53:15 +0000 Subject: [PATCH] objective-C modern translator. Fix up the translated metadata to handle ivar bitfields. This is wip. // rdar://13138459 llvm-svn: 174573 --- clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp | 293 ++++++++++++++++++++--- clang/test/Rewriter/modern-write-bf-abi.mm | 52 ++++ clang/test/Rewriter/unnamed-bf-modern-write.mm | 16 +- 3 files changed, 327 insertions(+), 34 deletions(-) create mode 100644 clang/test/Rewriter/modern-write-bf-abi.mm diff --git a/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp index 53b5591..bb98aab 100644 --- a/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp +++ b/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp @@ -133,6 +133,7 @@ namespace { SmallVector BlockDeclRefs; + // Block related declarations. SmallVector BlockByCopyDecls; llvm::SmallPtrSet BlockByCopyDeclsPtrSet; @@ -146,6 +147,13 @@ namespace { llvm::DenseMap > ReferencedIvars; + // ivar bitfield grouping containers + llvm::DenseSet ObjCInterefaceHasBitfieldGroups; + llvm::DenseMap IvarGroupNumber; + // This container maps an tuple to the type + // of the struct where the bitfield belongs. + llvm::DenseMap, 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 &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(IvarT) && IvarT->isRecordType()) { RecordDecl *RD = IvarT->getAs()->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(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 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 &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 tuple = std::make_pair(CDecl, GroupNo); + if (GroupRecordType.count(tuple)) + return GroupRecordType[tuple]; + + SmallVector IVars; + for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); + IVD; IVD = IVD->getNextIvar()) { + if (IVD->isBitField()) + IVars.push_back(const_cast(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 Ivars = ReferencedIvars[CDecl]; if (Ivars.empty()) return; + + llvm::DenseSet > GroupSymbolOutput; for (llvm::SmallPtrSet::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 Ivars, + ArrayRef 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 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(IvarT) && IvarT->isRecordType()) { RecordDecl *RD = IvarT->getAs()->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); diff --git a/clang/test/Rewriter/modern-write-bf-abi.mm b/clang/test/Rewriter/modern-write-bf-abi.mm new file mode 100644 index 0000000..9f44564 --- /dev/null +++ b/clang/test/Rewriter/modern-write-bf-abi.mm @@ -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 diff --git a/clang/test/Rewriter/unnamed-bf-modern-write.mm b/clang/test/Rewriter/unnamed-bf-modern-write.mm index 892382f..209cdd6 100644 --- a/clang/test/Rewriter/unnamed-bf-modern-write.mm +++ b/clang/test/Rewriter/unnamed-bf-modern-write.mm @@ -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: }; -- 2.7.4