[clang] Allow direct dispatch for the ObjFW runtime >= 1.3 (PR #126382)
Jonathan Schleifer via cfe-commits
cfe-commits at lists.llvm.org
Sat Feb 8 10:53:39 PST 2025
https://github.com/Midar updated https://github.com/llvm/llvm-project/pull/126382
>From ddc24b92cb8cc629082d0943de0f726a7604241e 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
---
clang/include/clang/Basic/ObjCRuntime.h | 2 +-
clang/lib/CodeGen/CGObjCGNU.cpp | 90 +++++++++++++++++++++++++
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/ObjCRuntime.h b/clang/include/clang/Basic/ObjCRuntime.h
index 1ccf60f0b7bee7..df42b438986111 100644
--- a/clang/include/clang/Basic/ObjCRuntime.h
+++ b/clang/include/clang/Basic/ObjCRuntime.h
@@ -473,7 +473,7 @@ class ObjCRuntime {
case GCC: return false;
case GNUstep:
return (getVersion() >= VersionTuple(2, 2));
- case ObjFW: return false;
+ case ObjFW: return true;
}
llvm_unreachable("bad kind");
}
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index ebd88bb38849e1..d2c882122ab087 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -2222,6 +2222,96 @@ class CGObjCObjFW: public CGObjCGNU {
return ClassSymbol;
}
+ 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:
+ //
+ // /* for class methods only to force class lazy initialization */
+ // self = [self self];
+ //
+ // /* unless the receiver is never NULL */
+ // if (self == nil) {
+ // return (ReturnType){ };
+ // }
+ //
+ // _cmd = @selector(...)
+ // ...
+
+ if (OMD->isClassMethod()) {
+ const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
+ assert(
+ OID &&
+ "GenerateDirectMethod() should be called with the Class Interface");
+ Selector SelfSel = GetNullarySelector("self", CGM.getContext());
+ auto ResultType = CGF.getContext().getObjCIdType();
+ RValue result;
+ CallArgList Args;
+
+ // TODO: If this method is inlined, the caller might know that `self` is
+ // already initialized; for example, it might be an ordinary Objective-C
+ // method which always receives an initialized `self`, or it might have
+ // just forced initialization on its own.
+ //
+ // We should find a way to eliminate this unnecessary initialization in
+ // such cases in LLVM.
+ result = GeneratePossiblySpecializedMessageSend(
+ CGF, ReturnValueSlot(), ResultType, SelfSel, selfValue, Args, OID,
+ nullptr, true);
+ Builder.CreateStore(result.getScalarVal(), selfAddr);
+
+ // 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);
+ }
+
+ 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);
+
+ llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+ 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);
+ }
+
+ // 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()));
+ }
+ }
+
public:
CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
// IMP objc_msg_lookup(id, SEL);
More information about the cfe-commits
mailing list