[clang] Allow direct dispatch for the ObjFW runtime (PR #126382)

Jonathan Schleifer via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 8 10:30:45 PST 2025


https://github.com/Midar updated https://github.com/llvm/llvm-project/pull/126382

>From 9b076179061731a647921271e400dbdaea31f60d Mon Sep 17 00:00:00 2001
From: Jonathan Schleifer <js at nil.im>
Date: Sat, 8 Feb 2025 12:12:21 +0100
Subject: [PATCH] Allow direct dispatch for the ObjFW runtime >= 1.3

---
 clang/include/clang/Basic/ObjCRuntime.h |   3 +-
 clang/lib/CodeGen/CGObjCGNU.cpp         | 211 ++++++++++++------------
 2 files changed, 106 insertions(+), 108 deletions(-)

diff --git a/clang/include/clang/Basic/ObjCRuntime.h b/clang/include/clang/Basic/ObjCRuntime.h
index 1ccf60f0b7bee70..a848942b01c02a6 100644
--- a/clang/include/clang/Basic/ObjCRuntime.h
+++ b/clang/include/clang/Basic/ObjCRuntime.h
@@ -473,7 +473,8 @@ class ObjCRuntime {
     case GCC: return false;
     case GNUstep:
       return (getVersion() >= VersionTuple(2, 2));
-    case ObjFW: return false;
+    case ObjFW:
+      return (getVersion() >= VersionTuple(1, 3));
     }
     llvm_unreachable("bad kind");
   }
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index ebd88bb38849e15..6b5a41eedc97e00 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -2029,112 +2029,6 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
         llvm::StructType::get(CGM.getLLVMContext(),
             { PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty });
     }
-
-    void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
-                                      const ObjCMethodDecl *OMD,
-                                      const ObjCContainerDecl *CD) override {
-      auto &Builder = CGF.Builder;
-      bool ReceiverCanBeNull = true;
-      auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
-      auto selfValue = Builder.CreateLoad(selfAddr);
-
-      // Generate:
-      //
-      // /* unless the receiver is never NULL */
-      // if (self == nil) {
-      //     return (ReturnType){ };
-      // }
-      //
-      // /* for class methods only to force class lazy initialization */
-      // if (!__objc_{class}_initialized)
-      // {
-      //   objc_send_initialize(class);
-      //   __objc_{class}_initialized = 1;
-      // }
-      //
-      // _cmd = @selector(...)
-      // ...
-
-      if (OMD->isClassMethod()) {
-        const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
-
-        // Nullable `Class` expressions cannot be messaged with a direct method
-        // so the only reason why the receive can be null would be because
-        // of weak linking.
-        ReceiverCanBeNull = isWeakLinkedClass(OID);
-      }
-
-      llvm::MDBuilder MDHelper(CGM.getLLVMContext());
-      if (ReceiverCanBeNull) {
-        llvm::BasicBlock *SelfIsNilBlock =
-            CGF.createBasicBlock("objc_direct_method.self_is_nil");
-        llvm::BasicBlock *ContBlock =
-            CGF.createBasicBlock("objc_direct_method.cont");
-
-        // if (self == nil) {
-        auto selfTy = cast<llvm::PointerType>(selfValue->getType());
-        auto Zero = llvm::ConstantPointerNull::get(selfTy);
-
-        Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero),
-                             SelfIsNilBlock, ContBlock,
-                             MDHelper.createUnlikelyBranchWeights());
-
-        CGF.EmitBlock(SelfIsNilBlock);
-
-        //   return (ReturnType){ };
-        auto retTy = OMD->getReturnType();
-        Builder.SetInsertPoint(SelfIsNilBlock);
-        if (!retTy->isVoidType()) {
-          CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
-        }
-        CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
-        // }
-
-        // rest of the body
-        CGF.EmitBlock(ContBlock);
-        Builder.SetInsertPoint(ContBlock);
-      }
-
-      if (OMD->isClassMethod()) {
-        // Prefix of the class type.
-        auto *classStart =
-            llvm::StructType::get(PtrTy, PtrTy, PtrTy, LongTy, LongTy);
-        auto &astContext = CGM.getContext();
-        // FIXME: The following few lines up to and including the call to
-        // `CreateLoad` were known to miscompile when MSVC 19.40.33813 is used
-        // to build Clang. When the bug is fixed in future MSVC releases, we
-        // should revert these lines to their previous state. See discussion in
-        // https://github.com/llvm/llvm-project/pull/102681
-        llvm::Value *Val = Builder.CreateStructGEP(classStart, selfValue, 4);
-        auto Align = CharUnits::fromQuantity(
-            astContext.getTypeAlign(astContext.UnsignedLongTy));
-        auto flags = Builder.CreateLoad(Address{Val, LongTy, Align});
-        auto isInitialized =
-            Builder.CreateAnd(flags, ClassFlags::ClassFlagInitialized);
-        llvm::BasicBlock *notInitializedBlock =
-            CGF.createBasicBlock("objc_direct_method.class_uninitialized");
-        llvm::BasicBlock *initializedBlock =
-            CGF.createBasicBlock("objc_direct_method.class_initialized");
-        Builder.CreateCondBr(Builder.CreateICmpEQ(isInitialized, Zeros[0]),
-                             notInitializedBlock, initializedBlock,
-                             MDHelper.createUnlikelyBranchWeights());
-        CGF.EmitBlock(notInitializedBlock);
-        Builder.SetInsertPoint(notInitializedBlock);
-        CGF.EmitRuntimeCall(SentInitializeFn, selfValue);
-        Builder.CreateBr(initializedBlock);
-        CGF.EmitBlock(initializedBlock);
-        Builder.SetInsertPoint(initializedBlock);
-      }
-
-      // only synthesize _cmd if it's referenced
-      if (OMD->getCmdDecl()->isUsed()) {
-        // `_cmd` is not a parameter to direct methods, so storage must be
-        // explicitly declared for it.
-        CGF.EmitVarDecl(*OMD->getCmdDecl());
-        Builder.CreateStore(GetSelector(CGF, OMD),
-                            CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
-      }
-    }
 };
 
 const char *const CGObjCGNUstep2::SectionsBaseNames[8] =
@@ -4121,7 +4015,110 @@ void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF,
                                              llvm::Function *Fn,
                                              const ObjCMethodDecl *OMD,
                                              const ObjCContainerDecl *CD) {
-  // GNU runtime doesn't support direct calls at this time
+  if (!CGM.getLangOpts().ObjCRuntime.allowsDirectDispatch())
+    return;
+
+  auto &Builder = CGF.Builder;
+  bool ReceiverCanBeNull = true;
+  auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
+  auto selfValue = Builder.CreateLoad(selfAddr);
+
+  // Generate:
+  //
+  // /* unless the receiver is never NULL */
+  // if (self == nil) {
+  //     return (ReturnType){ };
+  // }
+  //
+  // /* for class methods only to force class lazy initialization */
+  // if (!__objc_{class}_initialized)
+  // {
+  //   objc_send_initialize(class);
+  //   __objc_{class}_initialized = 1;
+  // }
+  //
+  // _cmd = @selector(...)
+  // ...
+
+  if (OMD->isClassMethod()) {
+    const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
+
+    // Nullable `Class` expressions cannot be messaged with a direct method
+    // so the only reason why the receive can be null would be because
+    // of weak linking.
+    ReceiverCanBeNull = isWeakLinkedClass(OID);
+  }
+
+  llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+  if (ReceiverCanBeNull) {
+    llvm::BasicBlock *SelfIsNilBlock =
+        CGF.createBasicBlock("objc_direct_method.self_is_nil");
+    llvm::BasicBlock *ContBlock =
+        CGF.createBasicBlock("objc_direct_method.cont");
+
+    // if (self == nil) {
+    auto selfTy = cast<llvm::PointerType>(selfValue->getType());
+    auto Zero = llvm::ConstantPointerNull::get(selfTy);
+
+    Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero),
+                         SelfIsNilBlock, ContBlock,
+                         MDHelper.createUnlikelyBranchWeights());
+
+    CGF.EmitBlock(SelfIsNilBlock);
+
+    //   return (ReturnType){ };
+    auto retTy = OMD->getReturnType();
+    Builder.SetInsertPoint(SelfIsNilBlock);
+    if (!retTy->isVoidType()) {
+      CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
+    }
+    CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
+    // }
+
+    // rest of the body
+    CGF.EmitBlock(ContBlock);
+    Builder.SetInsertPoint(ContBlock);
+  }
+
+  if (OMD->isClassMethod()) {
+    // Prefix of the class type.
+    auto *classStart =
+        llvm::StructType::get(PtrTy, PtrTy, PtrTy, LongTy, LongTy);
+    auto &astContext = CGM.getContext();
+    // FIXME: The following few lines up to and including the call to
+    // `CreateLoad` were known to miscompile when MSVC 19.40.33813 is used
+    // to build Clang. When the bug is fixed in future MSVC releases, we
+    // should revert these lines to their previous state. See discussion in
+    // https://github.com/llvm/llvm-project/pull/102681
+    llvm::Value *Val = Builder.CreateStructGEP(classStart, selfValue, 4);
+    auto Align = CharUnits::fromQuantity(
+        astContext.getTypeAlign(astContext.UnsignedLongTy));
+    auto flags = Builder.CreateLoad(Address{Val, LongTy, Align});
+    auto isInitialized =
+        Builder.CreateAnd(flags, ClassFlags::ClassFlagInitialized);
+    llvm::BasicBlock *notInitializedBlock =
+        CGF.createBasicBlock("objc_direct_method.class_uninitialized");
+    llvm::BasicBlock *initializedBlock =
+        CGF.createBasicBlock("objc_direct_method.class_initialized");
+    Builder.CreateCondBr(Builder.CreateICmpEQ(isInitialized, Zeros[0]),
+                         notInitializedBlock, initializedBlock,
+                         MDHelper.createUnlikelyBranchWeights());
+    CGF.EmitBlock(notInitializedBlock);
+    Builder.SetInsertPoint(notInitializedBlock);
+    CGF.EmitRuntimeCall(SentInitializeFn, selfValue);
+    Builder.CreateBr(initializedBlock);
+    CGF.EmitBlock(initializedBlock);
+    Builder.SetInsertPoint(initializedBlock);
+  }
+
+  // only synthesize _cmd if it's referenced
+  if (OMD->getCmdDecl()->isUsed()) {
+    // `_cmd` is not a parameter to direct methods, so storage must be
+    // explicitly declared for it.
+    CGF.EmitVarDecl(*OMD->getCmdDecl());
+    Builder.CreateStore(GetSelector(CGF, OMD),
+                        CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
+  }
 }
 
 llvm::FunctionCallee CGObjCGNU::GetPropertyGetFunction() {



More information about the cfe-commits mailing list