r362521 - [CodeGen][ObjC] Convert '[self alloc]' in a class method to a call to

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 4 09:29:58 PDT 2019


Author: ahatanak
Date: Tue Jun  4 09:29:58 2019
New Revision: 362521

URL: http://llvm.org/viewvc/llvm-project?rev=362521&view=rev
Log:
[CodeGen][ObjC] Convert '[self alloc]' in a class method to a call to
'objc_alloc(self)'

Also convert '[[self alloc] init]' in a class method to a call to
'objc_alloc_init(self)'.

rdar://problem/50855121

Differential Revision: https://reviews.llvm.org/D62643

Modified:
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/test/CodeGenObjC/convert-messages-to-runtime-calls.m
    cfe/trunk/test/CodeGenObjC/objc-alloc-init.m

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=362521&r1=362520&r2=362521&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Tue Jun  4 09:29:58 2019
@@ -383,10 +383,12 @@ tryGenerateSpecializedMessageSend(CodeGe
     if (isClassMessage &&
         Runtime.shouldUseRuntimeFunctionsForAlloc() &&
         ResultType->isObjCObjectPointerType()) {
-        // [Foo alloc] -> objc_alloc(Foo)
+        // [Foo alloc] -> objc_alloc(Foo) or
+        // [self alloc] -> objc_alloc(self)
         if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")
           return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
-        // [Foo allocWithZone:nil] -> objc_allocWithZone(Foo)
+        // [Foo allocWithZone:nil] -> objc_allocWithZone(Foo) or
+        // [self allocWithZone:nil] -> objc_allocWithZone(self)
         if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 &&
             Args.size() == 1 && Args.front().getType()->isPointerType() &&
             Sel.getNameForSlot(0) == "allocWithZone") {
@@ -444,22 +446,38 @@ tryEmitSpecializedAllocInit(CodeGenFunct
       Sel.getNameForSlot(0) != "init")
     return None;
 
-  // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]'.
+  // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' or
+  // we are in an ObjC class method and 'receiver' is '[self alloc]'.
   auto *SubOME =
-      dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParens());
+      dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParenCasts());
   if (!SubOME)
     return None;
   Selector SubSel = SubOME->getSelector();
-  if (SubOME->getReceiverKind() != ObjCMessageExpr::Class ||
-      !SubOME->getType()->isObjCObjectPointerType() ||
+
+  // Check if we are in an ObjC class method and the receiver expression is
+  // 'self'.
+  const Expr *SelfInClassMethod = nullptr;
+  if (const auto *CurMD = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
+    if (CurMD->isClassMethod())
+      if ((SelfInClassMethod = SubOME->getInstanceReceiver()))
+        if (!SelfInClassMethod->isObjCSelfExpr())
+          SelfInClassMethod = nullptr;
+
+  if ((SubOME->getReceiverKind() != ObjCMessageExpr::Class &&
+       !SelfInClassMethod) || !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);
+  llvm::Value *Receiver;
+  if (SelfInClassMethod) {
+    Receiver = CGF.EmitScalarExpr(SelfInClassMethod);
+  } else {
+    QualType ReceiverType = SubOME->getClassReceiver();
+    const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
+    const ObjCInterfaceDecl *ID = ObjTy->getInterface();
+    assert(ID && "null interface should be impossible here");
+    Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID);
+  }
   return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));
 }
 
@@ -507,6 +525,10 @@ RValue CodeGenFunction::EmitObjCMessageE
   switch (E->getReceiverKind()) {
   case ObjCMessageExpr::Instance:
     ReceiverType = E->getInstanceReceiver()->getType();
+    if (auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl))
+      if (OMD->isClassMethod())
+        if (E->getInstanceReceiver()->isObjCSelfExpr())
+          isClassMessage = true;
     if (retainSelf) {
       TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
                                                    E->getInstanceReceiver());

Modified: cfe/trunk/test/CodeGenObjC/convert-messages-to-runtime-calls.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/convert-messages-to-runtime-calls.m?rev=362521&r1=362520&r2=362521&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/convert-messages-to-runtime-calls.m (original)
+++ cfe/trunk/test/CodeGenObjC/convert-messages-to-runtime-calls.m Tue Jun  4 09:29:58 2019
@@ -150,6 +150,34 @@ float test_cannot_message_return_float(C
   return [c retain];
 }
 
+ at interface TestSelf
++ (instancetype)alloc;
++ (instancetype)allocWithZone:(void*)zone;
++ (id)classMeth;
+- (id)instanceMeth;
+ at end
+
+ at implementation TestSelf
+// CHECK-LABEL: define internal i8* @"\01+[TestSelf classMeth]"(
++ (id)classMeth {
+  // MSGS: {{call.*@objc_msgSend}}
+  // MSGS: {{call.*@objc_msgSend}}
+  // CALLS: {{call.*@objc_allocWithZone\(}}
+  // CALLS: {{call.*@objc_alloc\(}}
+  [self allocWithZone:nil];
+  return [self alloc];
+}
+// CHECK-LABEL: define internal i8* @"\01-[TestSelf instanceMeth]"(
+- (id)instanceMeth {
+  // MSGS: {{call.*@objc_msgSend}}
+  // MSGS: {{call.*@objc_msgSend}}
+  // CALLS: {{call.*@objc_msgSend}}
+  // CALLS: {{call.*@objc_msgSend}}
+  [self allocWithZone:nil];
+  return [self alloc];
+}
+ at end
+
 @interface NSString : NSObject
 + (void)retain_self;
 - (void)retain_super;

Modified: cfe/trunk/test/CodeGenObjC/objc-alloc-init.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/objc-alloc-init.m?rev=362521&r1=362520&r2=362521&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/objc-alloc-init.m (original)
+++ cfe/trunk/test/CodeGenObjC/objc-alloc-init.m Tue Jun  4 09:29:58 2019
@@ -23,14 +23,20 @@ void f() {
 
 @interface Y : X
 +(void)meth;
+-(void)instanceMeth;
 @end
 
 @implementation Y
 +(void)meth {
   [[self alloc] init];
+  // OPTIMIZED: call i8* @objc_alloc_init(
+  // NOT_OPTIMIZED: call i8* @objc_alloc(
+}
+-(void)instanceMeth {
   // EITHER-NOT: call i8* @objc_alloc
   // EITHER: call {{.*}} @objc_msgSend
   // EITHER: call {{.*}} @objc_msgSend
+  [[self alloc] init];
 }
 @end
 




More information about the cfe-commits mailing list