ahatanak created this revision.
ahatanak added reviewers: pete, rjmccall, erik.pilkington.
ahatanak added a project: clang.
Herald added subscribers: dexonsmith, jkorous.

This patch makes IRGen emit ObjC runtime functions 
(`objc_autoreleaseReturnValue` and `objc_retainAutoreleasedReturnValue`) that 
were previously emitted only in ARC mode. This enables retain message sends in 
MRR code to participate in the retainRV/autoreleaseRV handshake, which keeps 
returned objects out of the autorelease pool. Also, it enables the ARC 
optimizer and ARC contract pass to remove retain/autorelease pairs and mark 
autorelease message sends converted to autoreleaseRV calls as tail calls, which 
is necessary for the retainRV/autoreleaseRV handshake to succeed.

rdar://problem/50353574


Repository:
  rC Clang

https://reviews.llvm.org/D61970

Files:
  include/clang/Basic/CodeGenOptions.def
  include/clang/Driver/Options.td
  lib/CodeGen/CGObjC.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenObjC/convert-messages-to-runtime-calls.m

Index: test/CodeGenObjC/convert-messages-to-runtime-calls.m
===================================================================
--- test/CodeGenObjC/convert-messages-to-runtime-calls.m
+++ test/CodeGenObjC/convert-messages-to-runtime-calls.m
@@ -1,12 +1,13 @@
 // RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fno-objc-convert-messages-to-runtime-calls -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS --check-prefix=CALLS-ARC-INTRINSICS
 // RUN: %clang_cc1 -fobjc-runtime=macosx-10.9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
 // RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
-// RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
+// RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS --check-prefix=CALLS-ARC-INTRINSICS
 // RUN: %clang_cc1 -fobjc-runtime=ios-7.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
 // Note: This line below is for tvos for which the driver passes through to use the ios9.0 runtime.
-// RUN: %clang_cc1 -fobjc-runtime=ios-9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
-// RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
+// RUN: %clang_cc1 -fobjc-runtime=ios-9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS --check-prefix=CALLS-ARC-INTRINSICS
+// RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS --check-prefix=CALLS-ARC-INTRINSICS
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions -fobjc-no-builtin-retain-release | FileCheck %s --check-prefix=CALLS --check-prefix=CALLS-NO-ARC-INTRINSICS
 
 #define nil (id)0
 
@@ -28,9 +29,11 @@
   // MSGS: {{call.*@objc_msgSend}}
   // CALLS: {{call.*@objc_alloc}}
   // CALLS: {{call.*@objc_allocWithZone}}
-  // CALLS: {{call.*@objc_retain}}
+  // CALLS-ARC-INTRINSICS: {{call.*@llvm.objc.retainAutoreleasedReturnValue}}
+  // CALLS-NO-ARC-INTRINSICS: {{call.*@objc_retain}}
   // CALLS: {{call.*@objc_release}}
-  // CALLS: {{call.*@objc_autorelease}}
+  // CALLS-ARC-INTRINSICS: {{call.*@llvm.objc.autoreleaseReturnValue}}
+  // CALLS-NO-ARC-INTRINSICS: {{call.*@objc_autorelease}}
   [NSObject alloc];
   [NSObject allocWithZone:nil];
   [x retain];
@@ -111,7 +114,8 @@
 // call will return i8* which we have to cast to A*
 // CHECK-LABEL: define {{.*}}void @test_retain_class_ptr
 A* test_retain_class_ptr(B *b) {
-  // CALLS: {{call.*@objc_retain}}
+  // CALLS-ARC-INTRINSICS: {{call.*@llvm.objc.retainAutoreleasedReturnValue}}
+  // CALLS-NO-ARC-INTRINSICS: {{call.*@objc_retain}}
   // CALLS-NEXT: bitcast i8*
   // CALLS-NEXT: ret
   return [b retain];
@@ -121,7 +125,8 @@
 // call will return i8* which we have to cast to A*
 // CHECK-LABEL: define {{.*}}void @test_autorelease_class_ptr
 A* test_autorelease_class_ptr(B *b) {
-  // CALLS: {{call.*@objc_autorelease}}
+  // CALLS-ARC-INTRINSICS: {{call.*@llvm.objc.autoreleaseReturnValue}}
+  // CALLS-NO-ARC-INTRINSICS: {{call.*@objc_autorelease}}
   // CALLS-NEXT: bitcast i8*
   // CALLS-NEXT: ret
   return [b autorelease];
@@ -161,7 +166,8 @@
 // CHECK-LABEL: define {{.*}}void @retain_self
 + (void)retain_self {
   // MSGS: {{call.*@objc_msgSend}}
-  // CALLS: {{call.*@objc_retain}}
+  // CALLS-ARC-INTRINSICS: {{call.*@llvm.objc.retainAutoreleasedReturnValue}}
+  // CALLS-NO-ARC-INTRINSICS: {{call.*@objc_retain}}
   [self retain];
 }
 
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1163,6 +1163,8 @@
     }
   }
 
+  if (Args.hasArg(OPT_fobjc_no_builtin_retain_release))
+    Opts.ObjCNoBuiltinRetainRelease = 1;
 
   if (Args.hasArg(OPT_fno_objc_convert_messages_to_runtime_calls))
     Opts.ObjCConvertMessagesToRuntimeCalls = 0;
Index: lib/Driver/ToolChains/Clang.cpp
===================================================================
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -2986,6 +2986,9 @@
     Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions);
   }
 
+  if (Args.hasArg(options::OPT_fobjc_no_builtin_retain_release))
+    CmdArgs.push_back("-fobjc-no-builtin-retain-release");
+
   // Allow the user to control whether messages can be converted to runtime
   // functions.
   if (types::isObjC(Input.getType())) {
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -3799,9 +3799,12 @@
   void EmitARCDestroyStrong(Address addr, ARCPreciseLifetime_t precise);
   void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
   llvm::Value *EmitARCAutorelease(llvm::Value *value);
-  llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
+  llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value,
+                                             llvm::Type *returnType = nullptr);
   llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
-  llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
+  llvm::Value *
+  EmitARCRetainAutoreleasedReturnValue(llvm::Value *value,
+                                       llvm::Type *returnType = nullptr);
   llvm::Value *EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value);
 
   llvm::Value *EmitObjCAutorelease(llvm::Value *value, llvm::Type *returnType);
Index: lib/CodeGen/CGObjC.cpp
===================================================================
--- lib/CodeGen/CGObjC.cpp
+++ lib/CodeGen/CGObjC.cpp
@@ -2176,7 +2176,8 @@
 /// Yes, this function name is one character away from a different
 /// call with completely different semantics.
 llvm::Value *
-CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
+CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value,
+                                                      llvm::Type *returnType) {
   emitAutoreleasedReturnValueMarker(*this);
   llvm::CallInst::TailCallKind tailKind =
       CGM.getTargetCodeGenInfo()
@@ -2184,7 +2185,7 @@
           ? llvm::CallInst::TCK_NoTail
           : llvm::CallInst::TCK_None;
   return emitARCValueOperation(
-      *this, value, nullptr,
+      *this, value, returnType,
       CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
       llvm::Intrinsic::objc_retainAutoreleasedReturnValue, tailKind);
 }
@@ -2319,8 +2320,9 @@
 /// Autorelease the given object.
 ///   call i8* \@objc_autoreleaseReturnValue(i8* %value)
 llvm::Value *
-CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
-  return emitARCValueOperation(*this, value, nullptr,
+CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value,
+                                              llvm::Type *returnType) {
+  return emitARCValueOperation(*this, value, returnType,
                             CGM.getObjCEntrypoints().objc_autoreleaseReturnValue,
                                llvm::Intrinsic::objc_autoreleaseReturnValue,
                                llvm::CallInst::TCK_Tail);
@@ -2586,9 +2588,13 @@
 }
 
 /// Autorelease the given object.
-///   call i8* \@objc_autorelease(i8* %value)
+/// If we don't have to handle exceptions and ObjCNoBuiltinRetainRelease isn't
+/// set, call objc_autoreleaseReturnValue. Otherwise, call objc_autorelease.
 llvm::Value *CodeGenFunction::EmitObjCAutorelease(llvm::Value *value,
                                                   llvm::Type *returnType) {
+  // Do not call the ARC intrinsic if we are handling exceptions.
+  if (!CGM.getCodeGenOpts().ObjCNoBuiltinRetainRelease && !getInvokeDest())
+    return EmitARCAutoreleaseReturnValue(value, returnType);
   return emitObjCValueOperation(
       *this, value, returnType,
       CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction,
@@ -2596,9 +2602,13 @@
 }
 
 /// Retain the given object, with normal retain semantics.
-///   call i8* \@objc_retain(i8* %value)
+/// If we don't have to handle exceptions and ObjCNoBuiltinRetainRelease isn't
+/// set, call objc_retainAutoreleasedReturnValue. Otherwise, call objc_retain.
 llvm::Value *CodeGenFunction::EmitObjCRetainNonBlock(llvm::Value *value,
                                                      llvm::Type *returnType) {
+  // Do not call the ARC intrinsic if we are handling exceptions.
+  if (!CGM.getCodeGenOpts().ObjCNoBuiltinRetainRelease && !getInvokeDest())
+    return EmitARCRetainAutoreleasedReturnValue(value, returnType);
   return emitObjCValueOperation(
       *this, value, returnType,
       CGM.getObjCEntrypoints().objc_retainRuntimeFunction, "objc_retain");
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1495,6 +1495,9 @@
 def fno_objc_arc : Flag<["-"], "fno-objc-arc">, Group<f_Group>;
 def fobjc_convert_messages_to_runtime_calls :
   Flag<["-"], "fobjc-convert-messages-to-runtime-calls">, Group<f_Group>;
+def fobjc_no_builtin_retain_release :
+  Flag<["-"], "fobjc-no-builtin-retain-release">, Group<f_Group>,
+  Flags<[CC1Option]>;
 def fno_objc_convert_messages_to_runtime_calls :
   Flag<["-"], "fno-objc-convert-messages-to-runtime-calls">, Group<f_Group>, Flags<[CC1Option]>;
 def fobjc_arc_exceptions : Flag<["-"], "fobjc-arc-exceptions">, Group<f_Group>, Flags<[CC1Option]>,
Index: include/clang/Basic/CodeGenOptions.def
===================================================================
--- include/clang/Basic/CodeGenOptions.def
+++ include/clang/Basic/CodeGenOptions.def
@@ -154,6 +154,7 @@
 ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
 /// Replace certain message sends with calls to ObjC runtime entrypoints
 CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1)
+CODEGENOPT(ObjCNoBuiltinRetainRelease , 1, 0)
 CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
                                         ///< enabled.
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to