r354056 - [CodeGenObjC] Emit [[X alloc] init] as objc_alloc_init(X) when available

Erik Pilkington via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 14 11:58:37 PST 2019


Author: epilk
Date: Thu Feb 14 11:58:37 2019
New Revision: 354056

URL: http://llvm.org/viewvc/llvm-project?rev=354056&view=rev
Log:
[CodeGenObjC] Emit [[X alloc] init] as objc_alloc_init(X) when available

This provides a code size win on the caller side, since the init
message send is done in the runtime function.

rdar://44987038

Differential revision: https://reviews.llvm.org/D57936

Added:
    cfe/trunk/test/CodeGenObjC/objc-alloc-init.m
Modified:
    cfe/trunk/include/clang/Basic/ObjCRuntime.h
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.h

Modified: cfe/trunk/include/clang/Basic/ObjCRuntime.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ObjCRuntime.h?rev=354056&r1=354055&r2=354056&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/ObjCRuntime.h (original)
+++ cfe/trunk/include/clang/Basic/ObjCRuntime.h Thu Feb 14 11:58:37 2019
@@ -246,6 +246,22 @@ public:
     llvm_unreachable("bad kind");
   }
 
+  /// Does this runtime provide the objc_alloc_init entrypoint? This can apply
+  /// the same optimization as objc_alloc, but also sends an -init message,
+  /// reducing code size on the caller.
+  bool shouldUseRuntimeFunctionForCombinedAllocInit() const {
+    switch (getKind()) {
+    case MacOSX:
+      return getVersion() >= VersionTuple(10, 14, 4);
+    case iOS:
+      return getVersion() >= VersionTuple(12, 2);
+    case WatchOS:
+      return getVersion() >= VersionTuple(5, 2);
+    default:
+      return false;
+    }
+  }
+
   /// Does this runtime supports optimized setter entrypoints?
   bool hasOptimizedSetter() const {
     switch (getKind()) {

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=354056&r1=354055&r2=354056&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Thu Feb 14 11:58:37 2019
@@ -422,6 +422,40 @@ tryGenerateSpecializedMessageSend(CodeGe
   return None;
 }
 
+/// Instead of '[[MyClass alloc] init]', try to generate
+/// 'objc_alloc_init(MyClass)'. This provides a code size improvement on the
+/// caller side, as well as the optimized objc_alloc.
+static Optional<llvm::Value *>
+tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) {
+  auto &Runtime = CGF.getLangOpts().ObjCRuntime;
+  if (!Runtime.shouldUseRuntimeFunctionForCombinedAllocInit())
+    return None;
+
+  // Match the exact pattern '[[MyClass alloc] init]'.
+  Selector Sel = OME->getSelector();
+  if (!OME->isInstanceMessage() || !OME->getType()->isObjCObjectPointerType() ||
+      !Sel.isUnarySelector() || Sel.getNameForSlot(0) != "init")
+    return None;
+
+  // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]'.
+  auto *SubOME =
+      dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParens());
+  if (!SubOME)
+    return None;
+  Selector SubSel = SubOME->getSelector();
+  if (SubOME->getReceiverKind() != ObjCMessageExpr::Class ||
+      !SubOME->getType()->isObjCObjectPointerType() ||
+      !SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc")
+    return None;
+
+  QualType ReceiverType = SubOME->getClassReceiver();
+  const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
+  const ObjCInterfaceDecl *ID = ObjTy->getInterface();
+  assert(ID && "null interface should be impossible here");
+  llvm::Value *Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID);
+  return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));
+}
+
 RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
                                             ReturnValueSlot Return) {
   // Only the lookup mechanism and first two arguments of the method
@@ -443,6 +477,9 @@ RValue CodeGenFunction::EmitObjCMessageE
     }
   }
 
+  if (Optional<llvm::Value *> Val = tryEmitSpecializedAllocInit(*this, E))
+    return AdjustObjCObjectType(*this, E->getType(), RValue::get(*Val));
+
   // We don't retain the receiver in delegate init calls, and this is
   // safe because the receiver value is always loaded from 'self',
   // which we zero out.  We don't want to Block_copy block receivers,
@@ -2503,6 +2540,13 @@ llvm::Value *CodeGenFunction::EmitObjCAl
                                 "objc_allocWithZone", /*MayThrow=*/true);
 }
 
+llvm::Value *CodeGenFunction::EmitObjCAllocInit(llvm::Value *value,
+                                                llvm::Type *resultType) {
+  return emitObjCValueOperation(*this, value, resultType,
+                                CGM.getObjCEntrypoints().objc_alloc_init,
+                                "objc_alloc_init", /*MayThrow=*/true);
+}
+
 /// Produce the code to do a primitive release.
 /// [tmp drain];
 void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=354056&r1=354055&r2=354056&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Feb 14 11:58:37 2019
@@ -3831,6 +3831,8 @@ public:
                              llvm::Type *returnType);
   llvm::Value *EmitObjCAllocWithZone(llvm::Value *value,
                                      llvm::Type *returnType);
+  llvm::Value *EmitObjCAllocInit(llvm::Value *value, llvm::Type *resultType);
+
   llvm::Value *EmitObjCThrowOperand(const Expr *expr);
   llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
   llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=354056&r1=354055&r2=354056&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu Feb 14 11:58:37 2019
@@ -124,6 +124,9 @@ struct ObjCEntrypoints {
   /// void objc_allocWithZone(id);
   llvm::FunctionCallee objc_allocWithZone;
 
+  /// void objc_alloc_init(id);
+  llvm::FunctionCallee objc_alloc_init;
+
   /// void objc_autoreleasePoolPop(void*);
   llvm::FunctionCallee objc_autoreleasePoolPop;
 

Added: cfe/trunk/test/CodeGenObjC/objc-alloc-init.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/objc-alloc-init.m?rev=354056&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/objc-alloc-init.m (added)
+++ cfe/trunk/test/CodeGenObjC/objc-alloc-init.m Thu Feb 14 11:58:37 2019
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 %s -fobjc-runtime=macosx-10.14.4 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=OPTIMIZED --check-prefix=EITHER
+// RUN: %clang_cc1 %s -fobjc-runtime=macosx-10.14.3 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=NOT_OPTIMIZED --check-prefix=EITHER
+// RUN: %clang_cc1 %s -fobjc-runtime=ios-12.2 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=OPTIMIZED --check-prefix=EITHER
+// RUN: %clang_cc1 %s -fobjc-runtime=ios-12.1 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=NOT_OPTIMIZED --check-prefix=EITHER
+
+ at interface X
++(X *)alloc;
+-(X *)init;
+ at end
+
+void f() {
+  [[X alloc] init];
+  // OPTIMIZED: call i8* @objc_alloc_init(
+  // NOT_OPTIMIZED: call i8* @objc_alloc(
+}
+
+ at interface Y : X
++(void)meth;
+ at end
+
+ at implementation Y
++(void)meth {
+  [[self alloc] init];
+  // EITHER-NOT: call i8* @objc_alloc
+  // EITHER: call {{.*}} @objc_msgSend
+  // EITHER: call {{.*}} @objc_msgSend
+}
+ at end




More information about the cfe-commits mailing list