pete updated this revision to Diff 40426.
pete added a comment.

Updated the driver test to ensure that the option is set for tvOS and watchOS.


http://reviews.llvm.org/D14737

Files:
  include/clang/Basic/LangOptions.def
  include/clang/Basic/ObjCRuntime.h
  include/clang/Driver/Options.td
  lib/CodeGen/CGObjC.cpp
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/CodeGen/CodeGenModule.h
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenObjC/convert-messages-to-runtime-calls.m
  test/Driver/objc-convert-messages-to-runtime-calls.m

Index: test/Driver/objc-convert-messages-to-runtime-calls.m
===================================================================
--- /dev/null
+++ test/Driver/objc-convert-messages-to-runtime-calls.m
@@ -0,0 +1,21 @@
+// RUN: %clang %s -### -o %t.o 2>&1 -fobjc-convert-messages-to-runtime-calls -fsyntax-only -fno-objc-convert-messages-to-runtime-calls -target x86_64-apple-macosx10.10.0 | FileCheck  %s --check-prefix=DISABLE
+// RUN: %clang %s -### -o %t.o 2>&1 -fobjc-convert-messages-to-runtime-calls -fsyntax-only -target x86_64-apple-macosx10.10.0 | FileCheck  %s --check-prefix=ENABLE
+// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -target x86_64-apple-macosx10.10.0 | FileCheck  %s --check-prefix=SUPPORTED_MACOS
+// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -target x86_64-apple-macosx10.9.0 | FileCheck  %s --check-prefix=UNSUPPORTED_MACOS
+// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -target armv7-apple-ios8.0 | FileCheck  %s --check-prefix=SUPPORTED_IOS
+// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -target armv7-apple-ios7.0 | FileCheck  %s --check-prefix=UNSUPPORTED_IOS
+// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -target arm64-apple-tvos9.0 | FileCheck  %s --check-prefix=SUPPORTED_TVOS
+// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -target armv7k-apple-watchos2.0 | FileCheck  %s --check-prefix=SUPPORTED_WATCHOS
+
+// Check that we pass fobjc-convert-messages-to-runtime-calls only when supported, and not explicitly disabled.
+
+// DISABLE-NOT: "-fobjc-convert-messages-to-runtime-calls"
+// ENABLE: "-fobjc-convert-messages-to-runtime-calls"
+// SUPPORTED_MACOS: "-fobjc-convert-messages-to-runtime-calls"
+// UNSUPPORTED_MACOS-NOT: "-fobjc-convert-messages-to-runtime-calls"
+// SUPPORTED_IOS: "-fobjc-convert-messages-to-runtime-calls"
+// UNSUPPORTED_IOS-NOT: "-fobjc-convert-messages-to-runtime-calls"
+// SUPPORTED_TVOS: "-fobjc-convert-messages-to-runtime-calls"
+// SUPPORTED_WATCHOS: "-fobjc-convert-messages-to-runtime-calls"
+
+
Index: test/CodeGenObjC/convert-messages-to-runtime-calls.m
===================================================================
--- /dev/null
+++ test/CodeGenObjC/convert-messages-to-runtime-calls.m
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.10.0 -emit-llvm -o - %s -fobjc-convert-messages-to-runtime-calls | FileCheck %s --check-prefix=CALLS
+
+@interface NSObject
++ (id)alloc;
++ (id)alloc2;
+- (id)init;
+- (id)retain;
+- (void)release;
+- (id)autorelease;
+@end
+
+@interface NSString : NSObject
+@end
+
+// CHECK-LABEL: define {{.*}}void @test1
+void test1(id x) {
+  // MSGS: {{call.*@objc_msgSend}}
+  // MSGS: {{call.*@objc_msgSend}}
+  // MSGS: {{call.*@objc_msgSend}}
+  // MSGS: {{call.*@objc_msgSend}}
+  // CALLS: {{call.*@objc_alloc}}
+  // CALLS: {{call.*@objc_retain}}
+  // CALLS: {{call.*@objc_release}}
+  // CALLS: {{call.*@objc_autorelease}}
+  [NSObject alloc];
+  [x retain];
+  [x release];
+  [x autorelease];
+}
+
+// CHECK-LABEL: define {{.*}}void @test2
+void test2() {
+  // MSGS: {{call.*@objc_msgSend}}
+  // CALLS: {{call.*@objc_msgSend}}
+  // Make sure alloc has the correct name and number of types.
+  [NSObject alloc2];
+}
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1519,6 +1519,9 @@
     if (Args.hasArg(OPT_fobjc_subscripting_legacy_runtime))
       Opts.ObjCSubscriptingLegacyRuntime =
         (Opts.ObjCRuntime.getKind() == ObjCRuntime::FragileMacOSX);
+
+    if (Args.hasArg(OPT_fobjc_convert_messages_to_runtime_calls))
+      Opts.ObjCConvertMessagesToRuntimeCalls = 1;
   }
 
   if (Args.hasArg(OPT_fgnu89_inline)) {
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -4842,6 +4842,15 @@
 
   }
 
+  // Allow the user to control whether messages can be converted to runtime
+  // functions.
+  if (types::isObjC(InputType) &&
+      Args.hasFlag(options::OPT_fobjc_convert_messages_to_runtime_calls,
+                   options::OPT_fno_objc_convert_messages_to_runtime_calls,
+                   true) &&
+      objcRuntime.shouldUseARCFunctionsForRetainRelease())
+    CmdArgs.push_back("-fobjc-convert-messages-to-runtime-calls");
+
   // -fobjc-infer-related-result-type is the default, except in the Objective-C
   // rewriter.
   if (rewriteKind != RK_None)
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -111,6 +111,9 @@
 struct ObjCEntrypoints {
   ObjCEntrypoints() { memset(this, 0, sizeof(*this)); }
 
+  /// void objc_alloc(id);
+  llvm::Constant *objc_alloc;
+
     /// void objc_autoreleasePoolPop(void*);
   llvm::Constant *objc_autoreleasePoolPop;
 
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -2799,6 +2799,7 @@
   std::pair<LValue,llvm::Value*>
   EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
 
+  llvm::Value *EmitObjCAlloc(llvm::Value *value);
   llvm::Value *EmitObjCThrowOperand(const Expr *expr);
   llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
   llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
Index: lib/CodeGen/CGObjCMac.cpp
===================================================================
--- lib/CodeGen/CGObjCMac.cpp
+++ lib/CodeGen/CGObjCMac.cpp
@@ -1867,6 +1867,41 @@
                                  const ObjCMethodDecl *Method,
                                  const ObjCInterfaceDecl *ClassReceiver,
                                  const ObjCCommonTypesHelper &ObjCTypes) {
+  // Call runtime methods directly if we can.
+  if (Method && CGM.getLangOpts().ObjCConvertMessagesToRuntimeCalls) {
+    switch (Method->getMethodFamily()) {
+      case OMF_alloc: {
+        // Make sure the name is exactly 'alloc'.  All methods with that prefix
+        // are identified as OMF_alloc but we only want to call the runtime for
+        // this version.
+        Selector S = Method->getSelector();
+        if (S.isUnarySelector() && S.getNameForSlot(0) == "alloc" &&
+            ResultType->isObjCIdType() && Arg0Ty->isObjCIdType())
+          return RValue::get(CGF.EmitObjCAlloc(Arg0));
+        break;
+      }
+      case OMF_autorelease:
+        if (ResultType->isObjCIdType() && Arg0Ty->isObjCIdType())
+          return RValue::get(CGF.EmitARCAutorelease(Arg0));
+        break;
+
+      case OMF_retain:
+        if (ResultType->isObjCIdType() && Arg0Ty->isObjCIdType())
+          return RValue::get(CGF.EmitARCRetainNonBlock(Arg0));
+        break;
+
+      case OMF_release:
+        if (ResultType->isVoidType() && Arg0Ty->isObjCIdType()) {
+          CGF.EmitARCRelease(Arg0, ARCImpreciseLifetime);
+          return RValue::get(nullptr);
+        }
+        break;
+
+      default:
+        break;
+    }
+  }
+
   CallArgList ActualArgs;
   if (!IsSuper)
     Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
Index: lib/CodeGen/CGObjC.cpp
===================================================================
--- lib/CodeGen/CGObjC.cpp
+++ lib/CodeGen/CGObjC.cpp
@@ -2333,6 +2333,14 @@
   return InitRV.getScalarVal();
 }
 
+/// Allocate the given objc object.
+///   call i8* \@objc_alloc(i8* %value)
+llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value) {
+  return emitARCValueOperation(*this, value,
+                               CGM.getObjCEntrypoints().objc_alloc,
+                               "objc_alloc");
+}
+
 /// Produce the code to do a primitive release.
 /// [tmp drain];
 void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -892,6 +892,12 @@
 def fobjc_arc : Flag<["-"], "fobjc-arc">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Synthesize retain and release calls for Objective-C pointers">;
 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>, Flags<[CC1Option]>,
+  HelpText<"Convert eligible message sends to runtime calls">;
+def fno_objc_convert_messages_to_runtime_calls :
+  Flag<["-"], "fno-objc-convert-messages-to-runtime-calls">, Group<f_Group>;
 def fobjc_arc_exceptions : Flag<["-"], "fobjc-arc-exceptions">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">;
 def fno_objc_arc_exceptions : Flag<["-"], "fno-objc-arc-exceptions">, Group<f_Group>;
Index: include/clang/Basic/ObjCRuntime.h
===================================================================
--- include/clang/Basic/ObjCRuntime.h
+++ include/clang/Basic/ObjCRuntime.h
@@ -171,6 +171,27 @@
     llvm_unreachable("bad kind");
   }
 
+  /// Does this runtime have entrypoints which can handle messaging
+  /// retain/release.
+  ///
+  /// It is faster to call objc_retain(x) than [x retain].  Newer versions of
+  /// the runtime are aware of custom retain/release methods and so can send
+  /// the message if required, but otherwise are able to take a fast-path.
+  bool shouldUseARCFunctionsForRetainRelease() const {
+    switch (getKind()) {
+    case FragileMacOSX: return false;
+    case MacOSX: return getVersion() >= VersionTuple(10, 10);
+    case iOS: return getVersion() >= VersionTuple(8);
+    case WatchOS:
+      return true;
+
+    case GCC: return false;
+    case GNUstep: return false;
+    case ObjFW: return false;
+    }
+    llvm_unreachable("bad kind");
+  }
+
   /// \brief Does this runtime supports optimized setter entrypoints?
   bool hasOptimizedSetter() const {
     switch (getKind()) {
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -191,6 +191,7 @@
 LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
 LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
 LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
+LANGOPT(ObjCConvertMessagesToRuntimeCalls         , 1, 0, "objc_* support for retain/release in the runtime")
 LANGOPT(ObjCWeakRuntime     , 1, 0, "__weak support in the ARC runtime")
 LANGOPT(ObjCWeak            , 1, 0, "Objective-C __weak in ARC and MRC files")
 LANGOPT(ObjCSubscriptingLegacyRuntime         , 1, 0, "Subscripting support in legacy ObjectiveC runtime")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to