Author: Akira Hatanaka
Date: 2026-03-13T09:48:47-07:00
New Revision: 186dd22e5acc011fde83d41484d12c925ea874c4

URL: 
https://github.com/llvm/llvm-project/commit/186dd22e5acc011fde83d41484d12c925ea874c4
DIFF: 
https://github.com/llvm/llvm-project/commit/186dd22e5acc011fde83d41484d12c925ea874c4.diff

LOG: [ObjC] Emit class msgSend stub calls (#186433)

Instead of translating class messages to `objc_msgSend` calls, clang now
emits calls to stub functions that are synthesized by the linker. Each
stub loads the class reference and the selector name and forwards them
to `objc_msgSend`.

The stub function is named using the following format:
`objc_msgSendClass$selName$_OBJC_CLASS_$_className`

Note that the optimization is disabled in the following cases:

- When the class name is unknown at compile time (e.g,
  `[idclassMethod]`).
- The selector name contains a `$`, which serves as the delimiter in
  stub function names.
- The class is annotated with either `objc_class_stub` or
  `objc_runtime_visible`.

In such cases, clang reverts to the existing message send optimization,
where each stub loads only the selector name.

Also add class objects to llvm.used when class msgSend optimization is
enabled. This is needed as the linker currently cannot generate the
stub, which references the class object, if LTO internalizes the global
variable for the class object.

This reapplies 077991463253, which was reverted because it broke
offload-Xarch.c and openmp-offload-gpu.c. 14e04edf0725 prevents the
assertion from failing.

rdar://147604613

Added: 
    

Modified: 
    clang/include/clang/Basic/CodeGenOptions.def
    clang/include/clang/Options/Options.td
    clang/lib/CodeGen/CGObjCMac.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Driver/ToolChains/Darwin.cpp
    clang/test/CodeGenObjC/method-selector-stub.m
    clang/test/Driver/darwin-objc-selector-stubs.m

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/CodeGenOptions.def 
b/clang/include/clang/Basic/CodeGenOptions.def
index d7eab59f66dbc..857fe35e12b2b 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -217,6 +217,7 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 
2, Legacy, Benign)
 /// Replace certain message sends with calls to ObjC runtime entrypoints
 CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1, Benign)
 CODEGENOPT(ObjCMsgSendSelectorStubs , 1, 0, Benign) ///< Use per-selector 
linker stubs for objc_msgSend
+CODEGENOPT(ObjCMsgSendClassSelectorStubs, 1, 0, Benign) ///< Use per-class, 
per-selector linker stubs for objc_msgSend
 CODEGENOPT(ObjCAvoidHeapifyLocalBlocks, 1, 0, Benign)
 /// Generate direct method precondition thunks to expose symbols and optimize 
nil checks.
 CODEGENOPT(ObjCDirectPreconditionThunk, 1, 0, Benign)

diff  --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 97aa8767f8c4e..8e17cd5ae15b5 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -3853,6 +3853,10 @@ defm objc_convert_messages_to_runtime_calls : 
BoolFOption<"objc-convert-messages
 defm objc_msgsend_selector_stubs : BoolFOption<"objc-msgsend-selector-stubs",
   CodeGenOpts<"ObjCMsgSendSelectorStubs">, DefaultFalse,
   PosFlag<SetTrue, [], [ClangOption, CC1Option]>, NegFlag<SetFalse>>;
+defm objc_msgsend_class_selector_stubs : 
BoolFOption<"objc-msgsend-class-selector-stubs",
+  CodeGenOpts<"ObjCMsgSendClassSelectorStubs">, DefaultFalse,
+  PosFlag<SetTrue, [], [ClangOption, CC1Option]>,
+  NegFlag<SetFalse>>;
 defm objc_arc_exceptions : BoolFOption<"objc-arc-exceptions",
   CodeGenOpts<"ObjCAutoRefCountExceptions">, DefaultFalse,
   PosFlag<SetTrue, [], [ClangOption, CC1Option],

diff  --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index 4d1b9ed09fdd4..5f6faadfa795d 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -863,8 +863,9 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
   llvm::DenseMap<const ObjCMethodDecl *, DirectMethodInfo>
       DirectMethodDefinitions;
 
-  /// MethodSelectorStubs - map of selector stub functions
-  llvm::DenseMap<Selector, llvm::Function *> MethodSelectorStubs;
+  /// MethodSelectorStubs - Map from (selector,class) to stub function.
+  llvm::DenseMap<std::pair<Selector, StringRef>, llvm::Function *>
+      MethodSelectorStubs;
 
   /// PropertyNames - uniqued method variable names.
   llvm::DenseMap<IdentifierInfo *, llvm::GlobalVariable *> PropertyNames;
@@ -1086,7 +1087,7 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
                                     const ObjCContainerDecl *CD) override;
 
   llvm::Function *
-  GenerateMethodSelectorStub(Selector Sel,
+  GenerateMethodSelectorStub(Selector Sel, StringRef ClassName,
                              const ObjCCommonTypesHelper &ObjCTypes);
 
   void GenerateProtocol(const ObjCProtocolDecl *PD) override;
@@ -2082,12 +2083,14 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
     const ObjCCommonTypesHelper &ObjCTypes) {
   CodeGenTypes &Types = CGM.getTypes();
   auto selTy = CGF.getContext().getObjCSelType();
+  llvm::Value *ReceiverValue =
+      llvm::PoisonValue::get(Types.ConvertType(Arg0Ty));
   llvm::Value *SelValue = llvm::UndefValue::get(Types.ConvertType(selTy));
 
   CallArgList ActualArgs;
   if (!IsSuper)
     Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
-  ActualArgs.add(RValue::get(Arg0), Arg0Ty);
+  ActualArgs.add(RValue::get(ReceiverValue), Arg0Ty);
   if (!Method || !Method->isDirectMethod())
     ActualArgs.add(RValue::get(SelValue), selTy);
   ActualArgs.addFrom(CallArgs);
@@ -2104,6 +2107,7 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
       canMessageReceiverBeNull(CGF, Method, IsSuper, ClassReceiver, Arg0);
 
   bool RequiresNullCheck = false;
+  bool RequiresReceiverValue = true;
   bool RequiresSelValue = true;
 
   llvm::FunctionCallee Fn = nullptr;
@@ -2130,10 +2134,27 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
     // must be made for it.
     if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
       RequiresNullCheck = true;
-    if (!IsSuper && CGM.getCodeGenOpts().ObjCMsgSendSelectorStubs) {
-      // Try to use a selector stub declaration instead of objc_msgSend.
-      Fn = GenerateMethodSelectorStub(Sel, ObjCTypes);
+    // The class name that's used to create the class msgSend stub declaration.
+    StringRef ClassName;
+
+    // We cannot use class msgSend stubs in the following cases:
+    // 1. The class is annotated with `objc_class_stub` or
+    //    `objc_runtime_visible`.
+    // 2. The selector name contains a '$'.
+    if (CGM.getCodeGenOpts().ObjCMsgSendClassSelectorStubs && ClassReceiver &&
+        Method && Method->isClassMethod() &&
+        !ClassReceiver->hasAttr<ObjCClassStubAttr>() &&
+        !ClassReceiver->hasAttr<ObjCRuntimeVisibleAttr>() &&
+        Sel.getAsString().find('$') == std::string::npos)
+      ClassName = ClassReceiver->getObjCRuntimeNameAsString();
+
+    bool UseClassStub = ClassName.data();
+    // Try to use a selector stub declaration instead of objc_msgSend.
+    if (!IsSuper &&
+        (CGM.getCodeGenOpts().ObjCMsgSendSelectorStubs || UseClassStub)) {
+      Fn = GenerateMethodSelectorStub(Sel, ClassName, ObjCTypes);
       // Selector stubs synthesize `_cmd` in the stub, so we don't have to.
+      RequiresReceiverValue = !UseClassStub;
       RequiresSelValue = false;
     } else {
       Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
@@ -2159,6 +2180,10 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
     nullReturn.init(CGF, Arg0);
   }
 
+  // Pass the receiver value if it's needed.
+  if (RequiresReceiverValue)
+    ActualArgs[0] = CallArg(RValue::get(Arg0), Arg0Ty);
+
   // If a selector value needs to be passed, emit the load before the call.
   if (RequiresSelValue) {
     SelValue = GetSelector(CGF, Sel);
@@ -4062,8 +4087,11 @@ void CGObjCCommonMac::GenerateDirectMethodPrologue(
 }
 
 llvm::Function *CGObjCCommonMac::GenerateMethodSelectorStub(
-    Selector Sel, const ObjCCommonTypesHelper &ObjCTypes) {
-  auto I = MethodSelectorStubs.find(Sel);
+    Selector Sel, StringRef ClassName, const ObjCCommonTypesHelper &ObjCTypes) 
{
+  assert((!ClassName.data() || !ClassName.empty()) &&
+         "class name cannot be an empty string");
+  auto Key = std::make_pair(Sel, ClassName);
+  auto I = MethodSelectorStubs.find(Key);
 
   if (I != MethodSelectorStubs.end())
     return I->second;
@@ -4071,11 +4099,19 @@ llvm::Function 
*CGObjCCommonMac::GenerateMethodSelectorStub(
   auto *FnTy = llvm::FunctionType::get(
       ObjCTypes.ObjectPtrTy, {ObjCTypes.ObjectPtrTy, ObjCTypes.SelectorPtrTy},
       /*IsVarArg=*/true);
-  auto *Fn = cast<llvm::Function>(
-      CGM.CreateRuntimeFunction(FnTy, "objc_msgSend$" + Sel.getAsString())
-          .getCallee());
+  std::string FnName;
+
+  if (ClassName.data())
+    FnName = ("objc_msgSendClass$" + Sel.getAsString() + "$_OBJC_CLASS_$_" +
+              llvm::Twine(ClassName))
+                 .str();
+  else
+    FnName = "objc_msgSend$" + Sel.getAsString();
+
+  auto *Fn =
+      cast<llvm::Function>(CGM.CreateRuntimeFunction(FnTy, 
FnName).getCallee());
 
-  MethodSelectorStubs.insert(std::make_pair(Sel, Fn));
+  MethodSelectorStubs.insert(std::make_pair(Key, Fn));
   return Fn;
 }
 
@@ -6406,6 +6442,8 @@ llvm::GlobalVariable 
*CGObjCNonFragileABIMac::BuildClassObject(
   if (!CGM.getTriple().isOSBinFormatCOFF())
     if (HiddenVisibility)
       GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  if (CGM.getCodeGenOpts().ObjCMsgSendClassSelectorStubs && !isMetaclass)
+    CGM.addUsedGlobal(GV);
   return GV;
 }
 

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 61199e2c6b5b3..c5b75bdb2511f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4174,11 +4174,16 @@ static void RenderObjCOptions(const ToolChain &TC, 
const Driver &D,
     }
   }
 
-  // Pass down -fobjc-msgsend-selector-stubs if present.
   if (types::isObjC(Input.getType())) {
+    // Pass down -fobjc-msgsend-selector-stubs if present.
     if (Args.hasFlag(options::OPT_fobjc_msgsend_selector_stubs,
                      options::OPT_fno_objc_msgsend_selector_stubs, false))
       CmdArgs.push_back("-fobjc-msgsend-selector-stubs");
+
+    // Pass down -fobjc-msgsend-class-selector-stubs if present.
+    if (Args.hasFlag(options::OPT_fobjc_msgsend_class_selector_stubs,
+                     options::OPT_fno_objc_msgsend_class_selector_stubs, 
false))
+      CmdArgs.push_back("-fobjc-msgsend-class-selector-stubs");
   }
 
   // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option

diff  --git a/clang/lib/Driver/ToolChains/Darwin.cpp 
b/clang/lib/Driver/ToolChains/Darwin.cpp
index 756b69444ee3f..86810e1f28f36 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -3391,6 +3391,15 @@ void Darwin::addClangTargetOptions(
       (getLinkerVersion(DriverArgs) >= VersionTuple(811, 2)))
     CC1Args.push_back("-fobjc-msgsend-selector-stubs");
 
+  // Enable objc_msgSend class selector stubs by default if the linker supports
+  // it. ld64-1250+ does, for arm64, arm64e, and arm64_32.
+  if (!DriverArgs.hasArgNoClaim(
+          options::OPT_fobjc_msgsend_class_selector_stubs,
+          options::OPT_fno_objc_msgsend_class_selector_stubs) &&
+      getTriple().isAArch64() &&
+      (getLinkerVersion(DriverArgs) >= VersionTuple(1250, 0)))
+    CC1Args.push_back("-fobjc-msgsend-class-selector-stubs");
+
   // Pass "-fno-sized-deallocation" only when the user hasn't manually enabled
   // or disabled sized deallocations.
   if (!DriverArgs.hasArgNoClaim(options::OPT_fsized_deallocation,

diff  --git a/clang/test/CodeGenObjC/method-selector-stub.m 
b/clang/test/CodeGenObjC/method-selector-stub.m
index 9359b70832ad3..1f908d6120d5d 100644
--- a/clang/test/CodeGenObjC/method-selector-stub.m
+++ b/clang/test/CodeGenObjC/method-selector-stub.m
@@ -1,39 +1,54 @@
-// RUN: %clang_cc1 -emit-llvm -fobjc-msgsend-selector-stubs -triple 
arm64-apple-ios15 %s -o - | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -fobjc-msgsend-selector-stubs -triple 
arm64_32-apple-watchos8 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fobjc-msgsend-selector-stubs -triple 
arm64-apple-ios15 %s -o - | FileCheck -check-prefix=CHECK 
-check-prefix=INST_STUB %s
+// RUN: %clang_cc1 -emit-llvm -fobjc-msgsend-selector-stubs -triple 
arm64_32-apple-watchos8 %s -o - | FileCheck -check-prefix=CHECK 
-check-prefix=INST_STUB %s
+// RUN: %clang_cc1 -emit-llvm -fobjc-msgsend-selector-stubs 
-fobjc-msgsend-class-selector-stubs -triple arm64-apple-ios15 %s -o - | 
FileCheck -check-prefix=CHECK -check-prefix=CLASS_STUB %s
+// RUN: %clang_cc1 -emit-llvm -fobjc-msgsend-selector-stubs 
-fobjc-msgsend-class-selector-stubs -triple arm64_32-apple-watchos8 %s -o - | 
FileCheck -check-prefix=CHECK -check-prefix=CLASS_STUB %s
 
 __attribute__((objc_root_class))
 @interface Root
 - (int)test0;
+- (int)test$0;
 + (int)class0;
+- (int)class0;
++ (int)class0$;
 - (int)test1: (int)a0;
 - (int)test2: (int)a0 withA: (int)a1;
 
 @property(readonly) int intProperty;
 @end
 
+__attribute__((objc_root_class))
+@interface Root2
++ (int)class0;
+@end
+
 @interface Foo : Root
 @end
 
 @interface Foo ()
 - (int)testSuper0;
 - (int)methodInExtension;
++ (int)classMethodInExtension;
 @end
 
 @interface Foo (Cat)
 - (int)methodInCategory;
++ (int)classMethodInCategory;
 @end
 
 
 // CHECK: [[TEST0_METHNAME:@OBJC_METH_VAR_NAME_[^ ]*]] = private unnamed_addr 
constant [6 x i8] c"test0\00", section "__TEXT,__objc_methname,cstring_literals"
 // CHECK: [[TEST0_SELREF:@OBJC_SELECTOR_REFERENCES_[^ ]*]] = internal 
externally_initialized global ptr [[TEST0_METHNAME]], section 
"__DATA,__objc_selrefs,literal_pointers,no_dead_strip"
 
+// INST_STUB-NOT: @llvm.used =
+// CLASS_STUB: @llvm.used = appending global [1 x ptr] [ptr 
@"OBJC_CLASS_$_Foo"],
+
 @implementation Foo
 
 - (int)testSuper0 {
   // Super calls don't have stubs.
   // CHECK-LABEL: define{{.*}} i32 @"\01-[Foo testSuper0]"(
   // CHECK: [[SEL:%[^ ]]] = load ptr, ptr [[TEST0_SELREF]]
-  // CHECK: %{{[^ ]*}}  = call i32 @objc_msgSendSuper2(ptr {{[^,]+}}, ptr 
{{[^,)]*}}[[SEL]])
+  // CHECK: %{{[^ ]*}} = call i32 @objc_msgSendSuper2(ptr {{[^,]*}}%{{[^,]+}}, 
ptr {{[^,]+}}[[SEL]])
 
   return [super test0];
 }
@@ -55,25 +70,84 @@ - (int)methodInCategoryNoDecl {
 }
 @end
 
+__attribute__((objc_root_class,objc_runtime_name("_Foo1234")))
+@interface Foo2
++(void)m0;
+@end
+
+__attribute__((objc_class_stub, objc_subclassing_restricted))
+@interface Foo3
++(void)m0;
+@end
+
+__attribute__((objc_runtime_visible))
+@interface Foo4
++(void)m0;
+@end
+
 int test_root_test0(Root *r) {
   // CHECK-LABEL: define{{.*}} i32 @test_root_test0(
-  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$test0"(ptr {{[^,]+}}, ptr 
{{[^,)]*}}undef)
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$test0"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
   return [r test0];
 }
 
 // CHECK: declare ptr @"objc_msgSend$test0"(ptr, ptr, ...)
 
+int test_root_test0_dollar(Root *r) {
+  // CHECK-LABEL: define{{.*}} i32 @test_root_test0_dollar(
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$test$0"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
+  return [r test$0];
+}
+
+// CHECK: declare ptr @"objc_msgSend$test$0"(ptr, ptr, ...)
+
 int test_root_class0() {
   // CHECK-LABEL: define{{.*}} i32 @test_root_class0(
-  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$class0"(ptr {{[^,]+}}, ptr 
{{[^,)]*}}undef)
+  // INST_STUB: %{{[^ ]*}} = call i32 @"objc_msgSend$class0"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
+  // CLASS_STUB: %{{[^ ]*}} = call i32 
@"objc_msgSendClass$class0$_OBJC_CLASS_$_Root"(ptr {{[^,)]*}}poison, ptr 
{{[^,)]*}}undef)
   return [Root class0];
 }
 
-// CHECK: declare ptr @"objc_msgSend$class0"(ptr, ptr, ...)
+// INST_STUB: declare ptr @"objc_msgSend$class0"(ptr, ptr, ...)
+// CLASS_STUB: declare ptr @"objc_msgSendClass$class0$_OBJC_CLASS_$_Root"(ptr, 
ptr, ...)
+
+int test_root2_class0() {
+  // CHECK-LABEL: define{{.*}} i32 @test_root2_class0(
+  // INST_STUB: %{{[^ ]*}} = call i32 @"objc_msgSend$class0"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
+  // CLASS_STUB: %{{[^ ]*}} = call i32 
@"objc_msgSendClass$class0$_OBJC_CLASS_$_Root2"(ptr {{[^,)]*}}poison, ptr 
{{[^,)]*}}undef)
+  return [Root2 class0];
+}
+
+// CLASS_STUB: declare ptr 
@"objc_msgSendClass$class0$_OBJC_CLASS_$_Root2"(ptr, ptr, ...)
+
+int test_root_class0_inst(Root *r) {
+  // CHECK-LABEL: define{{.*}} i32 @test_root_class0_inst(
+  // CHECK: %[[R_ADDR:.*]] = alloca ptr,
+  // CHECK: store ptr %{{.*}}, ptr %[[R_ADDR]],
+  // CHECK: %[[V0:.*]] = load ptr, ptr %[[R_ADDR]],
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$class0"(ptr {{[^,]*}}%[[V0]], 
ptr {{[^,)]*}}undef)
+  return [r class0];
+}
+
+// CLASS_STUB: declare ptr @"objc_msgSend$class0"(ptr, ptr, ...)
+
+int test_root_class0_dollar() {
+  // CHECK-LABEL: define{{.*}} i32 @test_root_class0_dollar(
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$class0$"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
+  return [Root class0$];
+}
+
+// CHECK: declare ptr @"objc_msgSend$class0$"(ptr, ptr, ...)
+
+int test_id_class0(id r) {
+  // CHECK-LABEL: define{{.*}} i32 @test_id_class0(
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$class0"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
+  return [r class0];
+}
 
 int test_root_test1(Root *r) {
   // CHECK-LABEL: define{{.*}} i32 @test_root_test1(
-  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$test1:"(ptr {{[^,]+}}, ptr 
{{[^,)]*}}undef, i32 {{[^,)]*}}42)
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$test1:"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef, i32 {{[^,)]*}}42)
   return [r test1: 42];
 }
 
@@ -81,7 +155,7 @@ int test_root_test1(Root *r) {
 
 int test_root_test2(Root *r) {
   // CHECK-LABEL: define{{.*}} i32 @test_root_test2(
-  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$test2:withA:"(ptr {{[^,]+}}, 
ptr {{[^,)]*}}undef, i32 {{[^,)]*}}42, i32 {{[^,)]*}}84)
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$test2:withA:"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef, i32 {{[^,)]*}}42, i32 {{[^,)]*}}84)
   return [r test2: 42 withA: 84];
 
 }
@@ -90,23 +164,62 @@ int test_root_test2(Root *r) {
 
 int test_extension(Foo *f) {
   // CHECK-LABEL: define{{.*}} i32 @test_extension
-  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$methodInExtension"(ptr 
{{[^,]+}}, ptr {{[^,)]*}}undef)
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$methodInExtension"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
   return [f methodInExtension];
 }
 
 // CHECK: declare ptr @"objc_msgSend$methodInExtension"(ptr, ptr, ...)
 
+int test_class_method_extension(void) {
+  // CHECK-LABEL: define{{.*}} i32 @test_class_method_extension
+  // INST_STUB: %{{[^ ]*}} = call i32 
@"objc_msgSend$classMethodInExtension"(ptr {{[^,]*}}%{{[^,]+}}, ptr 
{{[^,)]*}}undef)
+  // CLASS_STUB: %{{[^ ]*}} = call i32 
@"objc_msgSendClass$classMethodInExtension$_OBJC_CLASS_$_Foo"(ptr 
{{[^,)]*}}poison, ptr {{[^,)]*}}undef)
+  return [Foo classMethodInExtension];
+}
+
+// INST_STUB: declare ptr @"objc_msgSend$classMethodInExtension"(ptr, ptr, ...)
+// CLASS_STUB: declare ptr 
@"objc_msgSendClass$classMethodInExtension$_OBJC_CLASS_$_Foo"(ptr, ptr, ...)
+
 int test_category(Foo *f) {
   // CHECK-LABEL: define{{.*}} i32 @test_category
-  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$methodInCategory"(ptr 
{{[^,]+}}, ptr {{[^,)]*}}undef)
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$methodInCategory"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
   return [f methodInCategory];
 }
 
 // CHECK: declare ptr @"objc_msgSend$methodInCategory"(ptr, ptr, ...)
 
+int test_class_method_category(void) {
+  // CHECK-LABEL: define{{.*}} i32 @test_class_method_category
+  // INST_STUB: %{{[^ ]*}} = call i32 
@"objc_msgSend$classMethodInCategory"(ptr {{[^,]*}}%{{[^,]+}}, ptr 
{{[^,)]*}}undef)
+  // CLASS_STUB: %{{[^ ]*}} = call i32 
@"objc_msgSendClass$classMethodInCategory$_OBJC_CLASS_$_Foo"(ptr 
{{[^,]*}}poison, ptr {{[^,)]*}}undef)
+  return [Foo classMethodInCategory];
+}
+
+// INST_STUB: declare ptr @"objc_msgSend$classMethodInCategory"(ptr, ptr, ...)
+// CLASS_STUB: declare ptr 
@"objc_msgSendClass$classMethodInCategory$_OBJC_CLASS_$_Foo"(ptr, ptr, ...)
+
+void test_class_method_objc_runtime_name(void) {
+  // CHECK-LABEL: define{{.*}} void @test_class_method_objc_runtime_name(
+  // INST_STUB: call void @"objc_msgSend$m0"(ptr {{[^,]*}}%{{[^,]+}}, ptr 
{{[^,)]*}}undef)
+  // CLASS_STUB: call void @"objc_msgSendClass$m0$_OBJC_CLASS_$__Foo1234"(ptr 
{{[^,]*}}poison, ptr {{[^,)]*}}undef)
+  [Foo2 m0];
+}
+
+void test_class_method_class_stub(void) {
+  // CHECK-LABEL: define{{.*}} void @test_class_method_class_stub(
+  // CHECK: call void @"objc_msgSend$m0"(ptr {{[^,]*}}%{{[^,]+}}, ptr 
{{[^,)]*}}undef)
+  [Foo3 m0];
+}
+
+void test_class_method_objc_runtime_visible(void) {
+  // CHECK-LABEL: define{{.*}} void @test_class_method_objc_runtime_visible(
+  // CHECK: call void @"objc_msgSend$m0"(ptr {{[^,]*}}%{{[^,]+}}, ptr 
{{[^,)]*}}undef)
+  [Foo4 m0];
+}
+
 int test_category_nodecl(Foo *f) {
   // CHECK-LABEL: define{{.*}} i32 @test_category_nodecl
-  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$methodInCategoryNoDecl"(ptr 
{{[^,]+}}, ptr {{[^,)]*}}undef)
+  // CHECK: %{{[^ ]*}} = call i32 @"objc_msgSend$methodInCategoryNoDecl"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef)
   return [f methodInCategoryNoDecl];
 }
 
@@ -122,7 +235,7 @@ @interface NSArray
 
 void test_fastenum_rawsel(NSArray *array) {
   // CHECK-LABEL: define{{.*}} void @test_fastenum_rawsel
-  // CHECK: %{{[^ ]*}} = call {{i32|i64}} 
@"objc_msgSend$countByEnumeratingWithState:objects:count:"(ptr {{[^,]+}}, ptr
+  // CHECK: %{{[^ ]*}} = call {{i32|i64}} 
@"objc_msgSend$countByEnumeratingWithState:objects:count:"(ptr 
{{[^,]*}}%{{[^,]+}}, ptr {{[^,)]*}}undef,
   // CHECK-NOT: @objc_msgSend to
   for (id x in array)
     use(x);

diff  --git a/clang/test/Driver/darwin-objc-selector-stubs.m 
b/clang/test/Driver/darwin-objc-selector-stubs.m
index 47d9473bffed3..b4a23ce768586 100644
--- a/clang/test/Driver/darwin-objc-selector-stubs.m
+++ b/clang/test/Driver/darwin-objc-selector-stubs.m
@@ -3,40 +3,63 @@
 // Enabled by default with ld64-811.2+ ...
 
 // ... for arm64
-// RUN: %clang -target arm64-apple-ios15            -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64-apple-ios15            -mlinker-version=1250  
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64-apple-ios15            -mlinker-version=1249  
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
+// RUN: %clang -target arm64-apple-ios15            -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
 // RUN: %clang -target arm64-apple-ios15            -mlinker-version=811   
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 
-// RUN: %clang -target arm64-apple-macos12          -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64-apple-macos12          -mlinker-version=1250  
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64-apple-macos12          -mlinker-version=1249  
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
+// RUN: %clang -target arm64-apple-macos12          -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
 // RUN: %clang -target arm64-apple-macos12          -mlinker-version=811   
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 
 // ... for arm64e
-// RUN: %clang -target arm64e-apple-ios15           -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64e-apple-ios15           -mlinker-version=1250  
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64e-apple-ios15           -mlinker-version=1249  
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
+// RUN: %clang -target arm64e-apple-ios15           -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
 // RUN: %clang -target arm64e-apple-ios15           -mlinker-version=811   
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 
 // ... and arm64_32.
-// RUN: %clang -target arm64_32-apple-watchos8      -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64_32-apple-watchos8      -mlinker-version=1250  
-### %s 2>&1 | FileCheck %s
+// RUN: %clang -target arm64_32-apple-watchos8      -mlinker-version=1249  
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
+// RUN: %clang -target arm64_32-apple-watchos8      -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s --check-prefix=INST_STUB_ONLY
 // RUN: %clang -target arm64_32-apple-watchos8      -mlinker-version=811   
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 
 
 // Disabled elsewhere, e.g. x86_64.
+// RUN: %clang -target x86_64-apple-macos12         -mlinker-version=1250  
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 // RUN: %clang -target x86_64-apple-macos12         -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 // RUN: %clang -target x86_64-apple-macos12         -mlinker-version=811   
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 
+// RUN: %clang -target x86_64-apple-ios15-simulator -mlinker-version=1250  
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 // RUN: %clang -target x86_64-apple-ios15-simulator -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 // RUN: %clang -target x86_64-apple-ios15-simulator -mlinker-version=811   
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 
 // ... or armv7k.
+// RUN: %clang -target armv7k-apple-watchos6        -mlinker-version=1250  
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 // RUN: %clang -target armv7k-apple-watchos6        -mlinker-version=811.2 
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 // RUN: %clang -target armv7k-apple-watchos6        -mlinker-version=811   
-### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
 
 
 // Enabled if you ask for it.
-// RUN: %clang -target arm64-apple-macos12 -fobjc-msgsend-selector-stubs       
             -### %s 2>&1 | FileCheck %s
-// RUN: %clang -target arm64-apple-macos12 -fobjc-msgsend-selector-stubs 
-mlinker-version=0 -### %s 2>&1 | FileCheck %s
+// If the linker version isn't specified on the command line, the cmake 
default version is used.
+// RUN: %clang -target arm64-apple-macos12 -fobjc-msgsend-selector-stubs       
             -### %s 2>&1 | FileCheck %s -check-prefix=INST_STUB
+
+// RUN: %clang -target arm64-apple-macos12 -fobjc-msgsend-selector-stubs 
-mlinker-version=0 -### %s 2>&1 | FileCheck %s -check-prefix=INST_STUB_ONLY
+// RUN: %clang -target arm64-apple-macos12 -fobjc-msgsend-class-selector-stubs 
-mlinker-version=0 -### %s 2>&1 | FileCheck %s -check-prefix=CLASS_STUB_ONLY
 
 // Disabled if you ask for that.
 // RUN: %clang -target arm64-apple-macos12 -fno-objc-msgsend-selector-stubs 
-mlinker-version=811.2 -### %s 2>&1 | FileCheck %s --check-prefix=NOSTUBS
+// RUN: %clang -target arm64-apple-macos12 -fno-objc-msgsend-selector-stubs 
-mlinker-version=1250 -### %s 2>&1  | FileCheck %s 
--check-prefix=CLASS_STUB_ONLY
+// RUN: %clang -target arm64-apple-macos12 
-fno-objc-msgsend-class-selector-stubs -mlinker-version=1250 -### %s 2>&1 | 
FileCheck %s --check-prefix=INST_STUB_ONLY
 
 
-// CHECK: "-fobjc-msgsend-selector-stubs"
-// NOSTUBS-NOT: objc-msgsend-selector-stubs
+// CHECK: "-fobjc-msgsend-selector-stubs" "-fobjc-msgsend-class-selector-stubs"
+// INST_STUB_ONLY-NOT: objc-msgsend-class-selector-stubs
+// INST_STUB_ONLY: objc-msgsend-selector-stubs
+// INST_STUB_ONLY-NOT: objc-msgsend-class-selector-stubs
+// INST_STUB: objc-msgsend-selector-stubs
+// CLASS_STUB_ONLY-NOT: objc-msgsend-selector-stubs
+// CLASS_STUB_ONLY: objc-msgsend-class-selector-stubs
+// CLASS_STUB_ONLY-NOT: objc-msgsend-selector-stubs
+// NOSTUBS-NOT: objc-msgsend-{{.*}}selector-stubs


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to