[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm added a comment. In https://reviews.llvm.org/D41050#954668, @rjmccall wrote: > In https://reviews.llvm.org/D41050#953917, @danzimm wrote: > > > Change tests to use non-O2 generated IR. It looks like the combined > > objc_retainAutoreleasedReturnValue/objc_autoreleaseReturnValue calls > > annihilate each other and we just get a call/ret. > > > Is that really happening at -O0? Maybe you need to add -disable-llvm-optzns > to the test line if so. Unfortunately it looks like adding `-disable-llvm-optzns` and/or `-disable-llvm-passes` (I also manually added `-O0` since I don't know what clang defaults to) doesn't generate the explicit call to `objc_retainAutoreleasedReturnValue`. Should we add a flag to disable that merging? Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm added a comment. I just dug into how the ARC optimization pass is invoked... it really shouldn't be invoked if `-disable-llvm-passes` is passed (or `-disable-llvm-optzns` which appears to just alias the first). Can you verify that my command is sane: /Users/danzimm/oss/build/bin/clang -cc1 -internal-isystem /Users/danzimm/oss/build/lib/clang/6.0.0/include -nostdsysteminc -triple x86_64-apple-macosx10.12.0 -disable-llvm-passes -emit-llvm -fblocks -fobjc-arc -std=c++11 -O0 -o - /Users/danzimm/oss/llvm/tools/clang/test/CodeGenObjCXX/arc-forwarded-lambda-call.mm Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm updated this revision to Diff 126892. danzimm added a comment. Pass -disable-llvm-passes with -O3 so that we can test that the IR we generate actually is generated Repository: rC Clang https://reviews.llvm.org/D41050 Files: lib/CodeGen/CGClass.cpp test/CodeGenObjCXX/arc-forwarded-lambda-call.mm Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -disable-llvm-passes -O3 -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test0P11objc_objectENK3$_0clEv"({{%.*}}* {{%.*}}) + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) [[A0:#[0-9]+]] + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) [[A0]] + // CHECK-NEXT: ret i8* [[T2]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test1vENK3$_1clEv"({{%.*}}* undef) + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) [[A0]] + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) [[A0]] + // CHECK-NEXT: ret i8* [[T2]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -disable-llvm-passes -O3 -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test0P11objc_objectENK3$_0clEv"({{%.*}}* {{%.*}}) + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) [[A0:#[0-9]+]] + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) [[A0]] + // CHECK-NEXT: ret i8* [[T2]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test1vENK3$_1clEv"({{%.*}}* undef) + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) [[A0]] + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) [[A0]] + // CHECK-NEXT: ret i8* [[T2]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm updated this revision to Diff 126893. danzimm added a comment. Remove unnecessary checks from tests (sorry for unbatched updates) Repository: rC Clang https://reviews.llvm.org/D41050 Files: lib/CodeGen/CGClass.cpp test/CodeGenObjCXX/arc-forwarded-lambda-call.mm Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -disable-llvm-passes -O3 -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test0P11objc_objectENK3$_0clEv" + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) + // CHECK-NEXT: ret i8* [[T2]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test1vENK3$_1clEv" + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) + // CHECK-NEXT: ret i8* [[T2]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -disable-llvm-passes -O3 -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test0P11objc_objectENK3$_0clEv" + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) + // CHECK-NEXT: ret i8* [[T2]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test1vENK3$_1clEv" + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) + // CHECK-NEXT: ret i8* [[T2]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm added a comment. @dexonsmith Here are my results after passing those extra flags with `-O3` (/Users/danzimm/oss/build/bin/clang -cc1 -internal-isystem /Users/danzimm/oss/build/lib/clang/6.0.0/include -nostdsysteminc -triple x86_64-apple-macosx10.12.0 -emit-llvm -disable-llvm-passes -O3 -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -mllvm -debug-pass=Executions -o ~/foo.ll /Users/danzimm/oss/llvm/tools/clang/test/CodeGenObjCXX/arc-forwarded-lambda-call.mm): Pass Arguments: -tti Target Transform Information FunctionPass Manager Pass Arguments: -tti Target Transform Information ModulePass Manager Print Module IR [2017-12-14 09:47:12.252472000] 0x7f87b90016f0 Executing Pass 'Print Module IR' on Module '/Users/danzimm/oss/llvm/tools/clang/test/CodeGenObjCXX/arc-forwarded-lambda-call.mm'... [2017-12-14 09:47:12.254702000] 0x7f87b90016f0Freeing Pass 'Print Module IR' on Module '/Users/danzimm/oss/llvm/tools/clang/test/CodeGenObjCXX/arc-forwarded-lambda-call.mm'... Pass Arguments: -tti Target Transform Information ModulePass Manager and with `-O0` (/Users/danzimm/oss/build/bin/clang -cc1 -internal-isystem /Users/danzimm/oss/build/lib/clang/6.0.0/include -nostdsysteminc -triple x86_64-apple-macosx10.12.0 -emit-llvm -disable-llvm-passes -O0 -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -mllvm -debug-pass=Executions -o ~/foo.ll /Users/danzimm/oss/llvm/tools/clang/test/CodeGenObjCXX/arc-forwarded-lambda-call.mm): Pass Arguments: -tti Target Transform Information FunctionPass Manager Pass Arguments: -tti Target Transform Information ModulePass Manager Print Module IR [2017-12-14 09:47:20.884147000] 0x7ff71ed097d0 Executing Pass 'Print Module IR' on Module '/Users/danzimm/oss/llvm/tools/clang/test/CodeGenObjCXX/arc-forwarded-lambda-call.mm'... [2017-12-14 09:47:20.886182000] 0x7ff71ed097d0Freeing Pass 'Print Module IR' on Module '/Users/danzimm/oss/llvm/tools/clang/test/CodeGenObjCXX/arc-forwarded-lambda-call.mm'... Pass Arguments: -tti Target Transform Information ModulePass Manager Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm added a comment. Also, I don't have commit access. Could someone else commit this for me? Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59873: Add additional mangling for struct members of non trivial structs
danzimm created this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. In https://bugs.llvm.org/show_bug.cgi?id=41206 we observe bad codegen when embedding a non-trivial C struct within a C struct. This is due to the fact that name mangling for non-trivial structs marks the two structs as identical. This diff contains a potential fix for this issue. I've included a test that exercises this for two scenarios. Please comment if there're any other scenarios I should consider. Test Plan: I've included a unit test Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D59873 Files: clang/lib/CodeGen/CGNonTrivialStruct.cpp Index: clang/lib/CodeGen/CGNonTrivialStruct.cpp === --- clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -139,8 +139,8 @@ // ::= ["_" ] // ::= + // ::= | -// ::= | | -// +// ::= "_S" | +//| // ::= "_AB" "s" "n" // "_AE" // ::= @@ -175,6 +175,7 @@ void visitStruct(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset) { CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); +appendStr("_S"); asDerived().visitStructFields(QT, FieldOffset); } Index: clang/lib/CodeGen/CGNonTrivialStruct.cpp === --- clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -139,8 +139,8 @@ // ::= ["_" ] // ::= + // ::= | -// ::= | | -// +// ::= "_S" | +//| // ::= "_AB" "s" "n" // "_AE" // ::= @@ -175,6 +175,7 @@ void visitStruct(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset) { CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); +appendStr("_S"); asDerived().visitStructFields(QT, FieldOffset); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59873: Add additional mangling for struct members of non trivial structs
danzimm added a comment. @lebedev.ri right, sorry about that- I prematurely diff'd (got a few terminals crossed and thought I was finished with the test already). I will be amending with a test and a few other test fixes shortly. Sorry about the miscommunication :/ Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59873/new/ https://reviews.llvm.org/D59873 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59873: Add additional mangling for struct members of non trivial structs
danzimm updated this revision to Diff 192436. danzimm added a comment. I forgot to add the test originally, this update contains a test and updates to old tests to make them pass Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59873/new/ https://reviews.llvm.org/D59873 Files: clang/lib/CodeGen/CGNonTrivialStruct.cpp clang/test/CodeGenObjC/nontrivial-c-struct-within-struct-name.m clang/test/CodeGenObjC/strong-in-c-struct.m Index: clang/test/CodeGenObjC/strong-in-c-struct.m === --- clang/test/CodeGenObjC/strong-in-c-struct.m +++ clang/test/CodeGenObjC/strong-in-c-struct.m @@ -89,12 +89,12 @@ // CHECK: define void @test_constructor_destructor_StrongOuter() // CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGOUTER:.*]], align 8 // CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V0]]) +// CHECK: call void @__default_constructor_8_S_s16_s24(i8** %[[V0]]) // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V1]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V1]]) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__default_constructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: define linkonce_odr hidden void @__default_constructor_8_S_s16_s24(i8** %[[DST:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 // CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 @@ -117,7 +117,7 @@ // CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 %[[V4]], i8 0, i64 8, i1 false) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__destructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: define linkonce_odr hidden void @__destructor_8_S_s16_s24(i8** %[[DST:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 // CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 @@ -149,12 +149,12 @@ // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGOUTER]]*, %[[STRUCT_STRONGOUTER]]** %[[S_ADDR]], align 8 // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** // CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[V0]] to i8** -// CHECK: call void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: call void @__copy_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]]) // CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V3]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V3]]) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -208,7 +208,7 @@ StrongOuter t = *s; } -/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -231,15 +231,15 @@ // CHECK: define void @test_move_constructor_StrongOuter() // CHECK: %[[T1:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T:.*]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T1]] to i8** -// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V1]]) +// CHECK: call void @__default_constructor_8_S_s16_s24(i8** %[[V1]]) // CHECK: %[[T2:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 // CHECK: %[[V9:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T2]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V9]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V9]]) // CHECK: define internal void @__Block_byref_object_copy_(i8*, i8*) -// CHECK: call void @__move_constructor_8_8_t0w16_s16_s24_t32w8( +// CHECK: call void @__move_constructor_8_8_S_t0w16_s16_s24_t32w8( -// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_AD
[PATCH] D59873: Add additional mangling for struct members of non trivial structs
danzimm added a comment. @smeenai please feel free add any reviewers that I might've missed Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59873/new/ https://reviews.llvm.org/D59873 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59873: Add additional mangling for struct members of non trivial structs
danzimm updated this revision to Diff 192652. danzimm added a comment. Add a third level to ensure nontrivial structs within structs within structs works (this suggests that N embeddings works too). Also change the invocation of the test Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59873/new/ https://reviews.llvm.org/D59873 Files: clang/lib/CodeGen/CGNonTrivialStruct.cpp clang/test/CodeGenObjC/nontrivial-c-struct-within-struct-name.m clang/test/CodeGenObjC/strong-in-c-struct.m Index: clang/test/CodeGenObjC/strong-in-c-struct.m === --- clang/test/CodeGenObjC/strong-in-c-struct.m +++ clang/test/CodeGenObjC/strong-in-c-struct.m @@ -89,12 +89,12 @@ // CHECK: define void @test_constructor_destructor_StrongOuter() // CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGOUTER:.*]], align 8 // CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V0]]) +// CHECK: call void @__default_constructor_8_S_s16_s24(i8** %[[V0]]) // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V1]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V1]]) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__default_constructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: define linkonce_odr hidden void @__default_constructor_8_S_s16_s24(i8** %[[DST:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 // CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 @@ -117,7 +117,7 @@ // CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 %[[V4]], i8 0, i64 8, i1 false) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__destructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: define linkonce_odr hidden void @__destructor_8_S_s16_s24(i8** %[[DST:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 // CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 @@ -149,12 +149,12 @@ // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGOUTER]]*, %[[STRUCT_STRONGOUTER]]** %[[S_ADDR]], align 8 // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** // CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[V0]] to i8** -// CHECK: call void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: call void @__copy_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]]) // CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V3]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V3]]) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -208,7 +208,7 @@ StrongOuter t = *s; } -/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -231,15 +231,15 @@ // CHECK: define void @test_move_constructor_StrongOuter() // CHECK: %[[T1:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T:.*]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T1]] to i8** -// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V1]]) +// CHECK: call void @__default_constructor_8_S_s16_s24(i8** %[[V1]]) // CHECK: %[[T2:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 // CHECK: %[[V9:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T2]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V9]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V9]]) // CHECK: define internal void @__Block_byref_object_copy_(i8*, i8*) -// CHECK: call void @__move_constructor_8_8_t0w16_s16_s24_t32w8( +// CHECK: call void @__move_constructor_8_8_S_t0w16_s16_s24_t32w8( -// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i
[PATCH] D59873: Add additional mangling for struct members of non trivial structs
danzimm added a comment. @smeenai good idea on the third level! Yep, I'll need somebody to commit this for me, thanks! Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59873/new/ https://reviews.llvm.org/D59873 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D52664: Update CMakeLists.txt snippet so that example compiles
danzimm created this revision. danzimm added a reviewer: modocache. Herald added a subscriber: cfe-commits. Previous to this the example didn't work out of the box, it seems some cmake config changed between when this was written and now. Repository: rC Clang https://reviews.llvm.org/D52664 Files: docs/LibASTMatchersTutorial.rst Index: docs/LibASTMatchersTutorial.rst === --- docs/LibASTMatchersTutorial.rst +++ docs/LibASTMatchersTutorial.rst @@ -113,6 +113,7 @@ LoopConvert.cpp ) target_link_libraries(loop-convert +PRIVATE clangTooling clangBasic clangASTMatchers Index: docs/LibASTMatchersTutorial.rst === --- docs/LibASTMatchersTutorial.rst +++ docs/LibASTMatchersTutorial.rst @@ -113,6 +113,7 @@ LoopConvert.cpp ) target_link_libraries(loop-convert +PRIVATE clangTooling clangBasic clangASTMatchers ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D52664: Update CMakeLists.txt snippet so that example compiles
danzimm added a comment. @steveire can you land this for me? I don't have commit access Repository: rC Clang https://reviews.llvm.org/D52664 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block
danzimm created this revision. Herald added subscribers: cfe-commits, kosarev. Clang has a pretty cool feature right now that will allow you to use a lambda as a block. Unfortunately there's a bug in this conversion if the return value of the block is an ObjC object and arc is enabled -- the return value gets over-released. An example of this causing a crash that shouldn't occur can be seen below: typedef id (^Go)(); int main() { Go g = []() -> id { return [NSObject new]; }; id sss = nil; @autoreleasepool { id ss = g(); sss = ss; } NSLog(@"%@", sss); return 0; } It looks like when a lambda is auto-converted to a block it generates a block that just wraps the lambda and forwards all args to it and the return value of the lambda back to be the return value of the block. Currently if the block returns an ObjC object both the lambda that's generated and the block that wraps it autorelease the return value, which effectively over-releases the return value. There are a few options that I considered and one that stuck out to me: 1. Add a retain call on the return value after invoking the enclosed lambda -- this way we maintain proper retain count 2. Stop autoreleasing the return value of the lambda 3. Stop autoreleasing the return value of the block I opted against the first case since it would mean unnecessary extra reference count churn. I didn't see an easy way to implement the second option as the enclosing lambda is generated as a global function definition, without the metadata that a block encloses it (and thus there's no easy way that I could see to differentiate the lambda-converted-to-block function definition from other global function definitions). Thus I came to the third option which is easily implementable since the codegen for blocks must recognize whether or not it encloses a lambda (as it changes what it generates if it does). The test I wrote relies on the optimizer inlining the lambda invocation -- I'm not sure if that's an ok assumption to make. The IR generated previous to this patch is kind of fun: define internal i8* @___Z5test0P11objc_object_block_invoke(i8* nocapture readonly %.block_descriptor) #0 { entry: %block.capture.addr = getelementptr inbounds i8, i8* %.block_descriptor, i64 32 %0 = bitcast i8* %block.capture.addr to i8** %1 = load i8*, i8** %0, align 8, !tbaa !7 %2 = tail call i8* @objc_retain(i8* %1) #2 %3 = tail call i8* @objc_autoreleaseReturnValue(i8* %1) #2 %4 = tail call i8* @objc_autoreleaseReturnValue(i8* %1) #2 ret i8* %1 } Repository: rC Clang https://reviews.llvm.org/D41050 Files: lib/CodeGen/CGBlocks.cpp test/CodeGenObjCXX/arc-block-lambda-conversion.mm Index: test/CodeGenObjCXX/arc-block-lambda-conversion.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-block-lambda-conversion.mm @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -O2 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGBlocks.cpp === --- lib/CodeGen/CGBlocks.cpp +++ lib/CodeGen/CGBlocks.cpp @@ -1450,9 +1450,12 @@ llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); --entry_ptr; - if (IsLambdaConversionToBlock) + if (IsLambdaConversionToBlock) { +// The lambda that's generated will emit a call to +// objc_autoreleaseReturnValue for us if necessary +AutoreleaseResult = false; EmitLambdaBlockInvokeBody(); - else { + } else { PGO.assignRegionCounters(GlobalDecl(blockDecl), fn); incrementProfileCounter(blockDecl->getBody()); EmitStmt(blockDecl->getBody()); Index: test/CodeGenObjCXX/arc-block-lambda-conversion.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-block-lambda-conversion.mm @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -O2 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGBlocks.cpp =
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block
danzimm added a comment. @rjmccall ah right, good point -- I think it's ok to elide that objc_retainAutoreleasedReturnValue/objc_autoreleaseReturnValue pair in this case though, since all of this is generated within clang itself (and thus we can make the guarentee that the object will properly live until the return of the enclosing block) -- it reduces retain count churn this way too Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block
danzimm added a comment. Or do we need to abide by those semantics strictly here? Could you expand on why that is, if that's the case? Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block
danzimm updated this revision to Diff 126628. danzimm added a comment. Call objc_retainAutoreleasedReturnValue after invoking a wrapped lambda Repository: rC Clang https://reviews.llvm.org/D41050 Files: lib/CodeGen/CGBlocks.cpp lib/CodeGen/CGClass.cpp test/CodeGenObjCXX/arc-forwarded-lambda-call.mm Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -O2 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } Index: lib/CodeGen/CGBlocks.cpp === --- lib/CodeGen/CGBlocks.cpp +++ lib/CodeGen/CGBlocks.cpp @@ -1450,9 +1450,9 @@ llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); --entry_ptr; - if (IsLambdaConversionToBlock) + if (IsLambdaConversionToBlock) { EmitLambdaBlockInvokeBody(); - else { + } else { PGO.assignRegionCounters(GlobalDecl(blockDecl), fn); incrementProfileCounter(blockDecl->getBody()); EmitStmt(blockDecl->getBody()); Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -O2 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } Index: lib/CodeGen/CGBlocks.cpp === --- lib/CodeGen/CGBlocks.cpp +++ lib/CodeGen/CGBlocks.cpp @@ -1450,9 +1450,9 @@ llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); --entry_ptr; - if (IsLambdaConversionToBlock) + if (IsLambdaConversionToBlock) { EmitLambdaBlockInvokeBody(); - else { + } else { PGO.assignRegionCounters(GlobalDecl(blockDecl), fn); incrementProfileCounter(blockDecl->getBody()); EmitStmt(blockDecl->getBody()); __
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block
danzimm added a comment. @rjmccall aha, right - thanks for explaining that to me (sorry for the bad logic I had earlier). It turns out this was also broken for a lambda that was auto-converted to a function pointer who returned an ObjC object. I changed the test case to reflect the more general situation, but I'm still unsure about the quality of the tests. Is it ok to rely on optimization passes to inline certain calls? Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block
danzimm updated this revision to Diff 126633. danzimm added a comment. Remove unnecessary change of braces Repository: rC Clang https://reviews.llvm.org/D41050 Files: lib/CodeGen/CGClass.cpp test/CodeGenObjCXX/arc-forwarded-lambda-call.mm Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -O2 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -O2 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: {{%.*}} = tail call i8* @objc_retain(i8* [[T0:%.*]]) + // CHECK-NEXT: {{%.*}} = tail call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm updated this revision to Diff 126763. danzimm added a comment. Change tests to use non-O2 generated IR. It looks like the combined objc_retainAutoreleasedReturnValue/objc_autoreleaseReturnValue calls annihilate each other and we just get a call/ret. Repository: rC Clang https://reviews.llvm.org/D41050 Files: lib/CodeGen/CGClass.cpp test/CodeGenObjCXX/arc-forwarded-lambda-call.mm Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test0P11objc_objectENK3$_0clEv"({{%.*}}* {{%.*}}) + // CHECK-NEXT: ret i8* [[T0]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test1vENK3$_1clEv"({{%.*}}* undef) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } Index: test/CodeGenObjCXX/arc-forwarded-lambda-call.mm === --- /dev/null +++ test/CodeGenObjCXX/arc-forwarded-lambda-call.mm @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s + +void test0(id x) { + extern void test0_helper(id (^)(void)); + test0_helper([=]() { return x; }); + // CHECK-LABEL: define internal i8* @___Z5test0P11objc_object_block_invoke + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test0P11objc_objectENK3$_0clEv"({{%.*}}* {{%.*}}) + // CHECK-NEXT: ret i8* [[T0]] +} + +id test1_rv; + +void test1() { + extern void test1_helper(id (*)(void)); + test1_helper([](){ return test1_rv; }); + // CHECK-LABEL: define internal i8* @"_ZZ5test1vEN3$_18__invokeEv" + // CHECK: [[T0:%.*]] = call i8* @"_ZZ5test1vENK3$_1clEv"({{%.*}}* undef) + // CHECK-NEXT: ret i8* [[T0]] +} Index: lib/CodeGen/CGClass.cpp === --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2776,9 +2776,12 @@ RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { +if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); +} EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D41050: Fix over-release of return value of lambda implicitly converted to block/function pointer
danzimm added a comment. Ah, just found test/Transforms/ObjCARC/rv.ll test3: ; Delete a redundant retainRV,autoreleaseRV when forwaring a call result ; directly to a return value. ; CHECK-LABEL: define i8* @test3( ; CHECK: call i8* @returner() ; CHECK-NEXT: ret i8* %call define i8* @test3() { entry: %call = call i8* @returner() %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind ret i8* %1 } Repository: rC Clang https://reviews.llvm.org/D41050 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits