[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