r247209 - ARC: Fix the precise-lifetime suppression of returns_inner_pointer

John McCall via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 9 16:37:17 PDT 2015


Author: rjmccall
Date: Wed Sep  9 18:37:17 2015
New Revision: 247209

URL: http://llvm.org/viewvc/llvm-project?rev=247209&view=rev
Log:
ARC: Fix the precise-lifetime suppression of returns_inner_pointer
receiver extension for message sends via property syntax.

rdar://22172983

Modified:
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=247209&r1=247208&r2=247209&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Wed Sep  9 18:37:17 2015
@@ -273,10 +273,23 @@ shouldExtendReceiverForInnerPointerMessa
   // receiver is loaded from a variable with precise lifetime.
   case ObjCMessageExpr::Instance: {
     const Expr *receiver = message->getInstanceReceiver();
+
+    // Look through OVEs.
+    if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
+      if (opaque->getSourceExpr())
+        receiver = opaque->getSourceExpr()->IgnoreParens();
+    }
+
     const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver);
     if (!ice || ice->getCastKind() != CK_LValueToRValue) return true;
     receiver = ice->getSubExpr()->IgnoreParens();
 
+    // Look through OVEs.
+    if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
+      if (opaque->getSourceExpr())
+        receiver = opaque->getSourceExpr()->IgnoreParens();
+    }
+
     // Only __strong variables.
     if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
       return true;

Modified: cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m?rev=247209&r1=247208&r2=247209&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m Wed Sep  9 18:37:17 2015
@@ -26,7 +26,8 @@ void test0() {
   // CHECK-NEXT: ret void
 }
 
-// rdar://problem/9821110
+// rdar://problem/9821110 - precise lifetime should suppress extension
+// rdar://problem/22172983 - should work for calls via property syntax, too
 @interface Test1
 - (char*) interior __attribute__((objc_returns_inner_pointer));
 // Should we allow this on properties? Yes! see // rdar://14990439
@@ -34,8 +35,8 @@ void test0() {
 @end
 extern Test1 *test1_helper(void);
 
-// CHECK-LABEL: define void @test1a()
-void test1a(void) {
+// CHECK-LABEL: define void @test1a_message()
+void test1a_message(void) {
   // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
   // CHECK:      [[C:%.*]] = alloca i8*, align 8
   // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
@@ -67,8 +68,43 @@ void test1a(void) {
   char *c = [(ptr) interior];
 }
 
-// CHECK-LABEL: define void @test1b()
-void test1b(void) {
+
+// CHECK-LABEL: define void @test1a_property()
+void test1a_property(void) {
+  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
+  // CHECK:      [[C:%.*]] = alloca i8*, align 8
+  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: store [[TEST1]]* [[T3]]
+  // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
+  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
+  // CHECK-NEXT: store i8* [[T6]], i8**
+  // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
+  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+  // CHECK-NEXT: ret void
+  Test1 *ptr = test1_helper();
+  char *c = ptr.interior;
+}
+
+
+// CHECK-LABEL: define void @test1b_message()
+void test1b_message(void) {
   // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
   // CHECK:      [[C:%.*]] = alloca i8*, align 8
   // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
@@ -94,11 +130,76 @@ void test1b(void) {
   // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
   // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
   // CHECK-NEXT: ret void
-  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
+  PRECISE_LIFETIME Test1 *ptr = test1_helper();
   char *c = [ptr interior];
 }
 
-void test1c(void) {
+// CHECK-LABEL: define void @test1b_property()
+void test1b_property(void) {
+  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
+  // CHECK:      [[C:%.*]] = alloca i8*, align 8
+  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: store [[TEST1]]* [[T3]]
+  // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
+  // CHECK-NEXT: store i8* [[T3]], i8**
+  // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
+  // CHECK-NOT:  clang.imprecise_release
+  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+  // CHECK-NEXT: ret void
+  PRECISE_LIFETIME Test1 *ptr = test1_helper();
+  char *c = ptr.interior;
+}
+
+// CHECK-LABEL: define void @test1c_message()
+void test1c_message(void) {
+  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
+  // CHECK:      [[PC:%.*]] = alloca i8*, align 8
+  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: store [[TEST1]]* [[T3]]
+  // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
+  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
+  // CHECK-NEXT: store i8* [[T6]], i8**
+  // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
+  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+  // CHECK-NEXT: ret void
+  Test1 *ptr = test1_helper();
+  char *pc = [ptr PropertyReturnsInnerPointer];
+}
+
+// CHECK-LABEL: define void @test1c_property()
+void test1c_property(void) {
   // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
   // CHECK:      [[PC:%.*]] = alloca i8*, align 8
   // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
@@ -130,7 +231,38 @@ void test1c(void) {
   char *pc = ptr.PropertyReturnsInnerPointer;
 }
 
-void test1d(void) {
+// CHECK-LABEL: define void @test1d_message()
+void test1d_message(void) {
+  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
+  // CHECK:      [[PC:%.*]] = alloca i8*, align 8
+  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: store [[TEST1]]* [[T3]]
+  // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
+  // CHECK-NEXT: store i8* [[CALL1]], i8**
+  // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
+  // CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]*, [[TEST1]]**
+  // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[TEN]])
+  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+  // CHECK-NEXT: ret void
+  PRECISE_LIFETIME Test1 *ptr = test1_helper();
+  char *pc = [ptr PropertyReturnsInnerPointer];
+}
+
+// CHECK-LABEL: define void @test1d_property()
+void test1d_property(void) {
   // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
   // CHECK:      [[PC:%.*]] = alloca i8*, align 8
   // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
@@ -143,11 +275,8 @@ void test1d(void) {
   // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
   // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
   // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
-  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
-  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease
-  // CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]*
   // CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
-  // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] to i8*
+  // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
   // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
   // CHECK-NEXT: store i8* [[CALL1]], i8**
   // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
@@ -158,7 +287,7 @@ void test1d(void) {
   // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
   // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
   // CHECK-NEXT: ret void
-  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
+  PRECISE_LIFETIME Test1 *ptr = test1_helper();
   char *pc = ptr.PropertyReturnsInnerPointer;
 }
 




More information about the cfe-commits mailing list