From ff685c562c8fd5dfc6effec17377fde9dad6f271 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 4 Dec 2012 17:20:57 +0000 Subject: [PATCH] objective-c blocks: Consider padding due to alignment after the fixed size block header when generating captured block variable info. // rdar://12773256 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@169285 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/DeclPrinter.cpp | 11 ++++ lib/CodeGen/CGBlocks.cpp | 18 ++++-- lib/CodeGen/CGBlocks.h | 8 +++ lib/CodeGen/CGObjCMac.cpp | 5 +- .../arc-captured-32bit-block-var-layout-2.m | 60 +++++++++++++++++++ 5 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 35bff1035e..493e46be47 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -970,6 +970,17 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n"; + if (PID->ivar_size() > 0) { + Out << "{\n"; + Indentation += Policy.Indentation; + for (ObjCCategoryDecl::ivar_iterator I = PID->ivar_begin(), + E = PID->ivar_end(); I != E; ++I) { + Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + } + Indentation -= Policy.Indentation; + Out << "}\n"; + } + VisitDeclContext(PID, false); Out << "@end"; diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 1d8b326d20..d181da2de6 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -428,7 +428,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, // to get reproducible results. There should probably be an // llvm::array_pod_stable_sort. std::stable_sort(layout.begin(), layout.end()); - + + // Needed for blocks layout info. + info.BlockHeaderForcedGapOffset = info.BlockSize; + info.BlockHeaderForcedGapSize = CharUnits::Zero(); + CharUnits &blockSize = info.BlockSize; info.BlockAlign = std::max(maxFieldAlign, info.BlockAlign); @@ -469,17 +473,22 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, endAlign = getLowBit(blockSize); // ...until we get to the alignment of the maximum field. - if (endAlign >= maxFieldAlign) + if (endAlign >= maxFieldAlign) { + if (li == first) { + // No user field was appended. So, a gap was added. + // Save total gap size for use in block layout bit map. + info.BlockHeaderForcedGapSize = li->Size; + } break; + } } - // Don't re-append everything we just appended. layout.erase(first, li); } } assert(endAlign == getLowBit(blockSize)); - + // At this point, we just have to add padding if the end align still // isn't aligned right. if (endAlign < maxFieldAlign) { @@ -494,7 +503,6 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, assert(endAlign >= maxFieldAlign); assert(endAlign == getLowBit(blockSize)); - // Slam everything else on now. This works because they have // strictly decreasing alignment and we expect that size is always a // multiple of alignment. diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index e63d4b6b1f..0e40478fad 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -211,6 +211,14 @@ public: const BlockExpr *BlockExpression; CharUnits BlockSize; CharUnits BlockAlign; + + // Offset of the gap caused by block header having a smaller + // alignment than the alignment of the block descriptor. This + // is the gap offset before the first capturued field. + CharUnits BlockHeaderForcedGapOffset; + // Gap size caused by aligning first field after block header. + // This could be zero if no forced alignment is required. + CharUnits BlockHeaderForcedGapSize; /// An instruction which dominates the full-expression that the /// block is inside. diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index f4b42bb9b7..d84875bfd5 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -2424,7 +2424,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, // Ignore the optional 'this' capture: C++ objects are not assumed // to be GC'ed. - + if (blockInfo.BlockHeaderForcedGapSize != CharUnits::Zero()) + UpdateRunSkipBlockVars(false, Qualifiers::OCL_None, + blockInfo.BlockHeaderForcedGapOffset, + blockInfo.BlockHeaderForcedGapSize); // Walk the captured variables. for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), ce = blockDecl->capture_end(); ci != ce; ++ci) { diff --git a/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m b/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m new file mode 100644 index 0000000000..909d413138 --- /dev/null +++ b/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -emit-llvm %s -o %t-64.s +// RUN: FileCheck --input-file=%t-64.s %s +// rdar://12773256 + +@class NSString; +extern void NSLog(NSString *format, ...); +extern int printf(const char *, ...); + +int main() { + NSString *strong; + unsigned long long eightByte = 0x8001800181818181ull; + // Test1 +// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"\220\00" + void (^block1)() = ^{ printf("%#llx", eightByte); NSLog(@"%@", strong); }; +// %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0*, i64, %0* }>, align 8 +// block variable layout: BL_NON_OBJECT_WORD:3, BL_STRONG:1, BL_OPERATOR:0 + + // Test2 + int i = 1; +// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"#0\00" + void (^block2)() = ^{ printf("%#llx, %d", eightByte, i); NSLog(@"%@", strong); }; +// %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32, i64, i32, %0* }>, align 8 +// block variable layout: BL_NON_OBJECT_WORD:4, BL_STRONG:1, BL_OPERATOR:0 + + // Test3 + char ch = 'a'; +// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"\220\00" + void (^block3)() = ^{ printf("%c %#llx", ch, eightByte); NSLog(@"%@", strong); }; +// %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0*, i64, %0*, i8 }>, align 8 +// block variable layout: BL_NON_OBJECT_WORD:3, BL_STRONG:1, BL_OPERATOR:0 + + // Test4 + unsigned long fourByte = 0x8001ul; +// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c" 0\00" + void (^block4)() = ^{ printf("%c %#lx", ch, fourByte); NSLog(@"%@", strong); }; +// block variable layout: BL_NON_OBJECT_WORD:1, BL_STRONG:1, BL_OPERATOR:0 +// %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32, %0*, i8 }>, align 4 + + // Test5 +// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"\220\00" + void (^block5)() = ^{ NSLog(@"%@", strong); printf("%c %#llx", ch, eightByte); }; +// %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0*, i64, %0*, i8 }>, align 8 +// block variable layout: BL_NON_OBJECT_WORD:3, BL_STRONG:1, BL_OPERATOR:0 + + // Test6 +// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer + void (^block6)() = ^{ printf("%#llx", eightByte); }; +// %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [4 x i8], i64 }>, align 8 +// block variable layout: BL_OPERATOR:0 +} + +/** +struct __block_literal_generic { // 32bytes (64bit) and 20 bytes (32bit). +0 void *__isa; +4 int __flags; +8 int __reserved; +12 void (*__invoke)(void *); +16 struct __block_descriptor *__descriptor; +}; +*/ -- 2.40.0