[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-14 Thread Phabricator via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC354056: [CodeGenObjC] Emit [[X alloc] init] as 
objc_alloc_init(X) when available (authored by epilk, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D57936?vs=186784=186894#toc

Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57936/new/

https://reviews.llvm.org/D57936

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

Index: lib/CodeGen/CodeGenModule.h
===
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -124,6 +124,9 @@
   /// 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;
 
Index: lib/CodeGen/CGObjC.cpp
===
--- lib/CodeGen/CGObjC.cpp
+++ lib/CodeGen/CGObjC.cpp
@@ -422,6 +422,40 @@
   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
+tryEmitSpecializedAllocInit(CodeGenFunction , const ObjCMessageExpr *OME) {
+  auto  = 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(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();
+  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 @@
 }
   }
 
+  if (Optional 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 @@
 "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) {
Index: lib/CodeGen/CodeGenFunction.h
===
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -3831,6 +3831,8 @@
  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);
Index: include/clang/Basic/ObjCRuntime.h
===
--- include/clang/Basic/ObjCRuntime.h
+++ include/clang/Basic/ObjCRuntime.h
@@ -246,6 +246,22 @@
 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 

[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-13 Thread John McCall via Phabricator via cfe-commits
rjmccall accepted this revision.
rjmccall added inline comments.
This revision is now accepted and ready to land.



Comment at: clang/lib/CodeGen/CGObjC.cpp:475-483
   case ObjCMessageExpr::Class: {
 ReceiverType = E->getClassReceiver();
 const ObjCObjectType *ObjTy = ReceiverType->getAs();
 assert(ObjTy && "Invalid Objective-C class message send");
 OID = ObjTy->getInterface();
 assert(OID && "Invalid Objective-C class message send");
 Receiver = Runtime.GetClass(*this, OID);

erik.pilkington wrote:
> > Also, I think getInterface() can return null here, although it might need 
> > to be contrived to fit the other requirements. Class, where 
> > that protocol declares +alloc? If there isn't a way to just emit the 
> > receiver pointer of a normal message send from an ObjCMessageExpr, that's 
> > really too bad.
> 
> Are you sure? It looks like we unconditionally dereference  getInterface() 
> here, and we would take this path if not for the new check above.
It looks like `ObjCMessageExpr::Class` is only for messages to type names, and 
Sema rejects types in that case that aren't just an ObjC class, so you're 
right, I misunderstood.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57936/new/

https://reviews.llvm.org/D57936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-13 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington marked 2 inline comments as done.
erik.pilkington added inline comments.



Comment at: clang/lib/CodeGen/CGObjC.cpp:459
+  llvm::Value *Receiver =
+  CGF.CGM.getObjCRuntime().GetClass(CGF, ObjTy->getInterface());
+  return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));

gparker42 wrote:
> gparker42 wrote:
> > rjmccall wrote:
> > > You might need to check for a `super` message send, which can be a class 
> > > message send in a class method.
> > > 
> > > Also, I think `getInterface()` can return null here, although it might 
> > > need to be contrived to fit the other requirements.  
> > > `Class`, where that protocol declares `+alloc`?  If there 
> > > isn't a way to just emit the receiver pointer of a normal message send 
> > > from an `ObjCMessageExpr`, that's really too bad.
> > Should this be done inside `tryGenerateSpecializedMessageSend`, or from the 
> > same place that calls `tryGenerateSpecializedMessageSend`? That position 
> > already rejects `[super …]` call sites, and might make it more obvious how 
> > the `objc_alloc` and `objc_alloc_init` optimizations interact. (Currently 
> > it takes some digging to verify that the `objc_alloc_init` generator does 
> > not need to look for the pattern `[objc_alloc(cls) init]`).
> (Never mind, that super check wouldn't help catch `[[super alloc] 
> init]`because it's checking `init`'s receiver.)
> You might need to check for a super message send, which can be a class 
> message send in a class method.

Ah, good catch. New patch only does this for class message sends.



Comment at: clang/lib/CodeGen/CGObjC.cpp:475-483
   case ObjCMessageExpr::Class: {
 ReceiverType = E->getClassReceiver();
 const ObjCObjectType *ObjTy = ReceiverType->getAs();
 assert(ObjTy && "Invalid Objective-C class message send");
 OID = ObjTy->getInterface();
 assert(OID && "Invalid Objective-C class message send");
 Receiver = Runtime.GetClass(*this, OID);

> Also, I think getInterface() can return null here, although it might need to 
> be contrived to fit the other requirements. Class, where that 
> protocol declares +alloc? If there isn't a way to just emit the receiver 
> pointer of a normal message send from an ObjCMessageExpr, that's really too 
> bad.

Are you sure? It looks like we unconditionally dereference  getInterface() 
here, and we would take this path if not for the new check above.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57936/new/

https://reviews.llvm.org/D57936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-13 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington updated this revision to Diff 186784.
erik.pilkington marked an inline comment as done.
erik.pilkington added a comment.

Address review comments.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57936/new/

https://reviews.llvm.org/D57936

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

Index: clang/test/CodeGenObjC/objc-alloc-init.m
===
--- /dev/null
+++ clang/test/CodeGenObjC/objc-alloc-init.m
@@ -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
+
+@interface X
++(X *)alloc;
+-(X *)init;
+@end
+
+void f() {
+  [[X alloc] init];
+  // OPTIMIZED: call i8* @objc_alloc_init(
+  // NOT_OPTIMIZED: call i8* @objc_alloc(
+}
+
+@interface Y : X
++(void)meth;
+@end
+
+@implementation Y
++(void)meth {
+  [[self alloc] init];
+  // EITHER-NOT: call i8* @objc_alloc
+  // EITHER: call {{.*}} @objc_msgSend
+  // EITHER: call {{.*}} @objc_msgSend
+}
+@end
Index: clang/lib/CodeGen/CodeGenModule.h
===
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -124,6 +124,9 @@
   /// 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;
 
Index: clang/lib/CodeGen/CodeGenFunction.h
===
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3831,6 +3831,8 @@
  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);
Index: clang/lib/CodeGen/CGObjC.cpp
===
--- clang/lib/CodeGen/CGObjC.cpp
+++ clang/lib/CodeGen/CGObjC.cpp
@@ -422,6 +422,40 @@
   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
+tryEmitSpecializedAllocInit(CodeGenFunction , const ObjCMessageExpr *OME) {
+  auto  = 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(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();
+  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 @@
 }
   }
 
+  if (Optional 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 

[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-08 Thread Greg Parker via Phabricator via cfe-commits
gparker42 added inline comments.



Comment at: clang/lib/CodeGen/CGObjC.cpp:459
+  llvm::Value *Receiver =
+  CGF.CGM.getObjCRuntime().GetClass(CGF, ObjTy->getInterface());
+  return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));

gparker42 wrote:
> rjmccall wrote:
> > You might need to check for a `super` message send, which can be a class 
> > message send in a class method.
> > 
> > Also, I think `getInterface()` can return null here, although it might need 
> > to be contrived to fit the other requirements.  `Class`, 
> > where that protocol declares `+alloc`?  If there isn't a way to just emit 
> > the receiver pointer of a normal message send from an `ObjCMessageExpr`, 
> > that's really too bad.
> Should this be done inside `tryGenerateSpecializedMessageSend`, or from the 
> same place that calls `tryGenerateSpecializedMessageSend`? That position 
> already rejects `[super …]` call sites, and might make it more obvious how 
> the `objc_alloc` and `objc_alloc_init` optimizations interact. (Currently it 
> takes some digging to verify that the `objc_alloc_init` generator does not 
> need to look for the pattern `[objc_alloc(cls) init]`).
(Never mind, that super check wouldn't help catch `[[super alloc] init]`because 
it's checking `init`'s receiver.)


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57936/new/

https://reviews.llvm.org/D57936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-08 Thread Greg Parker via Phabricator via cfe-commits
gparker42 added inline comments.



Comment at: clang/lib/CodeGen/CGObjC.cpp:459
+  llvm::Value *Receiver =
+  CGF.CGM.getObjCRuntime().GetClass(CGF, ObjTy->getInterface());
+  return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));

rjmccall wrote:
> You might need to check for a `super` message send, which can be a class 
> message send in a class method.
> 
> Also, I think `getInterface()` can return null here, although it might need 
> to be contrived to fit the other requirements.  `Class`, where 
> that protocol declares `+alloc`?  If there isn't a way to just emit the 
> receiver pointer of a normal message send from an `ObjCMessageExpr`, that's 
> really too bad.
Should this be done inside `tryGenerateSpecializedMessageSend`, or from the 
same place that calls `tryGenerateSpecializedMessageSend`? That position 
already rejects `[super …]` call sites, and might make it more obvious how the 
`objc_alloc` and `objc_alloc_init` optimizations interact. (Currently it takes 
some digging to verify that the `objc_alloc_init` generator does not need to 
look for the pattern `[objc_alloc(cls) init]`).


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57936/new/

https://reviews.llvm.org/D57936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-07 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: clang/lib/CodeGen/CGObjC.cpp:459
+  llvm::Value *Receiver =
+  CGF.CGM.getObjCRuntime().GetClass(CGF, ObjTy->getInterface());
+  return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));

You might need to check for a `super` message send, which can be a class 
message send in a class method.

Also, I think `getInterface()` can return null here, although it might need to 
be contrived to fit the other requirements.  `Class`, where that 
protocol declares `+alloc`?  If there isn't a way to just emit the receiver 
pointer of a normal message send from an `ObjCMessageExpr`, that's really too 
bad.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57936/new/

https://reviews.llvm.org/D57936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D57936: [CodeGenObjC] When available, emit a direct call to objc_alloc_init(cls) instead of [objc_alloc(cls) init]

2019-02-07 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington created this revision.
erik.pilkington added reviewers: rjmccall, pete, ahatanak.
Herald added subscribers: dexonsmith, jkorous.
Herald added a project: clang.

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

rdar://44987038

Thanks!
Erik


Repository:
  rC Clang

https://reviews.llvm.org/D57936

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

Index: clang/test/CodeGenObjC/objc-alloc-init.m
===
--- /dev/null
+++ clang/test/CodeGenObjC/objc-alloc-init.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -fobjc-runtime=macosx-10.14.4 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=OPTIMIZED
+// RUN: %clang_cc1 %s -fobjc-runtime=macosx-10.14.3 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=NOT_OPTIMIZED
+// RUN: %clang_cc1 %s -fobjc-runtime=ios-12.2 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=OPTIMIZED
+// RUN: %clang_cc1 %s -fobjc-runtime=ios-12.1 -emit-llvm -O0 -o - | FileCheck %s --check-prefix=NOT_OPTIMIZED
+
+@interface X
++(X *)alloc;
+-(X *)init;
+@end
+
+void f() {
+  [[X alloc] init];
+  // OPTIMIZED: call i8* @objc_alloc_init(
+  // NOT_OPTIMIZED: call i8* @objc_alloc(
+}
Index: clang/lib/CodeGen/CodeGenModule.h
===
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -124,6 +124,9 @@
   /// 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;
 
Index: clang/lib/CodeGen/CodeGenFunction.h
===
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3827,6 +3827,8 @@
  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);
Index: clang/lib/CodeGen/CGObjC.cpp
===
--- clang/lib/CodeGen/CGObjC.cpp
+++ clang/lib/CodeGen/CGObjC.cpp
@@ -425,6 +425,41 @@
   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
+tryEmitSpecializedAllocInit(CodeGenFunction , const ObjCMessageExpr *OME) {
+  auto  = 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(OME->getInstanceReceiver()->IgnoreParens());
+  if (!SubOME)
+return None;
+  Selector SubSel = SubOME->getSelector();
+  if (!SubOME->isClassMessage() ||
+  !SubOME->getType()->isObjCObjectPointerType() ||
+  !SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc")
+return None;
+
+  QualType ReceiverType = SubOME->getClassReceiver();
+  const ObjCObjectType *ObjTy = ReceiverType->getAs();
+  if (!ObjTy)
+return None;
+  llvm::Value *Receiver =
+  CGF.CGM.getObjCRuntime().GetClass(CGF, ObjTy->getInterface());
+  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
@@ -446,6 +481,9 @@
 }
   }
 
+  if (Optional 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,
@@ -2506,6 +2544,13 @@
 "objc_allocWithZone", /*MayThrow=*/true);
 }
 
+llvm::Value *CodeGenFunction::EmitObjCAllocInit(llvm::Value *value,
+llvm::Type *resultType) {
+  return