From d0f8a8d17082266c1e774ca07d58bcd4811b2681 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Mon, 11 May 2009 19:25:47 +0000 Subject: [PATCH] Patch to allow Nonfragile ABI to use 32-bit style legacy message dispage API for all but a few messages. This is a runtime performance improvement and there is not meant to be a functional change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71467 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjCMac.cpp | 325 +++++++++++++++++-------- test/CodeGenObjC/metadata-symbols-64.m | 7 +- 2 files changed, 222 insertions(+), 110 deletions(-) diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 0088a3e22e..9d57fcb786 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -145,6 +145,100 @@ namespace { // metadata, string concatenation is lame. class ObjCCommonTypesHelper { +private: + llvm::Constant *getMessageSendFn() const { + // id objc_msgSend (id, SEL, ...) + std::vector Params; + Params.push_back(ObjectPtrTy); + Params.push_back(SelectorPtrTy); + return + CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, + Params, true), + "objc_msgSend"); + } + + llvm::Constant *getMessageSendStretFn() const { + // id objc_msgSend_stret (id, SEL, ...) + std::vector Params; + Params.push_back(ObjectPtrTy); + Params.push_back(SelectorPtrTy); + return + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, + Params, true), + "objc_msgSend_stret"); + + } + + llvm::Constant *getMessageSendFpretFn() const { + // FIXME: This should be long double on x86_64? + // [double | long double] objc_msgSend_fpret(id self, SEL op, ...) + std::vector Params; + Params.push_back(ObjectPtrTy); + Params.push_back(SelectorPtrTy); + return + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::DoubleTy, + Params, + true), + "objc_msgSend_fpret"); + + } + + llvm::Constant *getMessageSendSuperFn() const { + // id objc_msgSendSuper(struct objc_super *super, SEL op, ...) + const char *SuperName = "objc_msgSendSuper"; + std::vector Params; + Params.push_back(SuperPtrTy); + Params.push_back(SelectorPtrTy); + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, + Params, true), + SuperName); + } + + llvm::Constant *getMessageSendSuperFn2() const { + // id objc_msgSendSuper2(struct objc_super *super, SEL op, ...) + const char *SuperName = "objc_msgSendSuper2"; + std::vector Params; + Params.push_back(SuperPtrTy); + Params.push_back(SelectorPtrTy); + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, + Params, true), + SuperName); + } + + llvm::Constant *getMessageSendSuperStretFn() const { + // void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super, + // SEL op, ...) + std::vector Params; + Params.push_back(Int8PtrTy); + Params.push_back(SuperPtrTy); + Params.push_back(SelectorPtrTy); + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, + Params, true), + "objc_msgSendSuper_stret"); + } + + llvm::Constant *getMessageSendSuperStretFn2() const { + // void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super, + // SEL op, ...) + std::vector Params; + Params.push_back(Int8PtrTy); + Params.push_back(SuperPtrTy); + Params.push_back(SelectorPtrTy); + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, + Params, true), + "objc_msgSendSuper2_stret"); + } + + llvm::Constant *getMessageSendSuperFpretFn() const { + // There is no objc_msgSendSuper_fpret? How can that work? + return getMessageSendSuperFn(); + } + + llvm::Constant *getMessageSendSuperFpretFn2() const { + // There is no objc_msgSendSuper_fpret? How can that work? + return getMessageSendSuperFn2(); + } + protected: CodeGen::CodeGenModule &CGM; @@ -308,78 +402,37 @@ public: return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); } - ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm); - ~ObjCCommonTypesHelper(){} -}; - -/// ObjCTypesHelper - Helper class that encapsulates lazy -/// construction of varies types used during ObjC generation. -class ObjCTypesHelper : public ObjCCommonTypesHelper { -private: - - llvm::Constant *getMessageSendFn() { - // id objc_msgSend (id, SEL, ...) - std::vector Params; - Params.push_back(ObjectPtrTy); - Params.push_back(SelectorPtrTy); - return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - "objc_msgSend"); + llvm::Constant *getSendFn(bool IsSuper) const { + return IsSuper ? getMessageSendSuperFn() : getMessageSendFn(); } - llvm::Constant *getMessageSendStretFn() { - // id objc_msgSend_stret (id, SEL, ...) - std::vector Params; - Params.push_back(ObjectPtrTy); - Params.push_back(SelectorPtrTy); - return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, true), - "objc_msgSend_stret"); - + llvm::Constant *getSendFn2(bool IsSuper) const { + return IsSuper ? getMessageSendSuperFn2() : getMessageSendFn(); } - llvm::Constant *getMessageSendFpretFn() { - // FIXME: This should be long double on x86_64? - // [double | long double] objc_msgSend_fpret(id self, SEL op, ...) - std::vector Params; - Params.push_back(ObjectPtrTy); - Params.push_back(SelectorPtrTy); - return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::DoubleTy, - Params, - true), - "objc_msgSend_fpret"); - + llvm::Constant *getSendStretFn(bool IsSuper) const { + return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn(); } - llvm::Constant *getMessageSendSuperFn() { - // id objc_msgSendSuper(struct objc_super *super, SEL op, ...) - std::vector Params; - Params.push_back(SuperPtrTy); - Params.push_back(SelectorPtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - "objc_msgSendSuper"); + llvm::Constant *getSendStretFn2(bool IsSuper) const { + return IsSuper ? getMessageSendSuperStretFn2() : getMessageSendStretFn(); } - llvm::Constant *getMessageSendSuperStretFn() { - // void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super, - // SEL op, ...) - std::vector Params; - Params.push_back(Int8PtrTy); - Params.push_back(SuperPtrTy); - Params.push_back(SelectorPtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, true), - "objc_msgSendSuper_stret"); + + llvm::Constant *getSendFpretFn(bool IsSuper) const { + return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn(); } - llvm::Constant *getMessageSendSuperFpretFn() { - // There is no objc_msgSendSuper_fpret? How can that work? - return getMessageSendSuperFn(); + llvm::Constant *getSendFpretFn2(bool IsSuper) const { + return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn(); } + + ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm); + ~ObjCCommonTypesHelper(){} +}; +/// ObjCTypesHelper - Helper class that encapsulates lazy +/// construction of varies types used during ObjC generation. +class ObjCTypesHelper : public ObjCCommonTypesHelper { public: /// SymtabTy - LLVM type for struct objc_symtab. const llvm::StructType *SymtabTy; @@ -488,19 +541,6 @@ public: public: ObjCTypesHelper(CodeGen::CodeGenModule &cgm); ~ObjCTypesHelper() {} - - - llvm::Constant *getSendFn(bool IsSuper) { - return IsSuper ? getMessageSendSuperFn() : getMessageSendFn(); - } - - llvm::Constant *getSendStretFn(bool IsSuper) { - return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn(); - } - - llvm::Constant *getSendFpretFn(bool IsSuper) { - return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn(); - } }; /// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's @@ -871,6 +911,15 @@ protected: /// ivars. void GetNamedIvarList(const ObjCInterfaceDecl *OID, llvm::SmallVector &Res) const; + + CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, + QualType ResultType, + llvm::Value *Sel, + llvm::Value *Arg0, + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs, + const ObjCCommonTypesHelper &ObjCTypes); public: CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm) @@ -1090,6 +1139,14 @@ private: /// EHTypeReferences - uniqued class ehtype references. llvm::DenseMap EHTypeReferences; + /// NoneLegacyDispatchMethods - List of methods for which we do *not* generate + /// legacy messaging dispatch. + llvm::StringMap NoneLegacyDispatchMethods; + + /// LegacyDispatchedSelector - Returns true if SEL is not in the list of + /// NoneLegacyDispatchMethods; flase otherwise. + bool LegacyDispatchedSelector(Selector Sel); + /// FinishNonFragileABIModule - Write out global data structures at the end of /// processing a translation unit. void FinishNonFragileABIModule(); @@ -1387,10 +1444,10 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - - return EmitMessageSend(CGF, ResultType, Sel, - ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs); + return EmitLegacyMessageSend(CGF, ResultType, + EmitSelector(CGF.Builder, Sel), + ObjCSuper, ObjCTypes.SuperPtrCTy, + true, CallArgs, ObjCTypes); } /// Generate code for a message send expression. @@ -1401,42 +1458,56 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { - return EmitMessageSend(CGF, ResultType, Sel, - Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs); + return EmitLegacyMessageSend(CGF, ResultType, + EmitSelector(CGF.Builder, Sel), + Receiver, CGF.getContext().getObjCIdType(), + false, CallArgs, ObjCTypes); } -CodeGen::RValue CGObjCMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, - QualType ResultType, - Selector Sel, - llvm::Value *Arg0, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs) { +CodeGen::RValue CGObjCCommonMac::EmitLegacyMessageSend( + CodeGen::CodeGenFunction &CGF, + QualType ResultType, + llvm::Value *Sel, + llvm::Value *Arg0, + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs, + const ObjCCommonTypesHelper &ObjCTypes) { CallArgList ActualArgs; if (!IsSuper) Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp"); ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty)); - ActualArgs.push_back(std::make_pair(RValue::get(EmitSelector(CGF.Builder, - Sel)), + ActualArgs.push_back(std::make_pair(RValue::get(Sel), CGF.getContext().getObjCSelType())); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); - + CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); - // FIXME. vararg flag must be true when this API is used for 64bit code gen. - const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, false); - - llvm::Constant *Fn; + // In 64bit ABI, type must be assumed VARARG. It 32bit abi, + // it seems not to matter. + const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, (ObjCABI == 2)); + + llvm::Constant *Fn = NULL; if (CGM.ReturnTypeUsesSret(FnInfo)) { - Fn = ObjCTypes.getSendStretFn(IsSuper); + Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper) + : ObjCTypes.getSendStretFn(IsSuper); } else if (ResultType->isFloatingType()) { // FIXME: Sadly, this is wrong. This actually depends on the // architecture. This happens to be right for x86-32 though. - Fn = ObjCTypes.getSendFpretFn(IsSuper); + if (ObjCABI == 2) { + if (const BuiltinType *BT = ResultType->getAsBuiltinType()) { + BuiltinType::Kind k = BT->getKind(); + Fn = (k == BuiltinType::LongDouble) ? ObjCTypes.getSendFpretFn2(IsSuper) + : ObjCTypes.getSendFn2(IsSuper); + } + } + else + Fn = ObjCTypes.getSendFpretFn(IsSuper); } else { - Fn = ObjCTypes.getSendFn(IsSuper); + Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper) + : ObjCTypes.getSendFn(IsSuper); } + assert(Fn && "EmitLegacyMessageSend - unknown API"); Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy)); return CGF.EmitCall(FnInfo, Fn, ActualArgs); } @@ -4054,6 +4125,41 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { } +/// LegacyDispatchedSelector - Returns true if SEL is not in the list of +/// NoneLegacyDispatchMethods; flase otherwise. What this means is that +/// except for the 19 selectors in the list, we generate 32bit-style +/// message dispatch call for all the rest. +/// +bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { + // FIXME! Lagcy API in Nonfragile ABI is for 10.6 on + if (NoneLegacyDispatchMethods.empty()) { + NoneLegacyDispatchMethods["allocWithZone:"] = true; + NoneLegacyDispatchMethods["alloc"] = true; + NoneLegacyDispatchMethods["class"] = true; + NoneLegacyDispatchMethods["self"] = true; + NoneLegacyDispatchMethods["isKindOfClass:"] = true; + NoneLegacyDispatchMethods["respondsToSelector:"] = true; + NoneLegacyDispatchMethods["isFlipped"] = true; + NoneLegacyDispatchMethods["length"] = true; + NoneLegacyDispatchMethods["objectForKey:"] = true; + NoneLegacyDispatchMethods["count"] = true; + NoneLegacyDispatchMethods["objectAtIndex:"] = true; + NoneLegacyDispatchMethods["isEqualToString:"] = true; + NoneLegacyDispatchMethods["isEqual:"] = true; + NoneLegacyDispatchMethods["retain"] = true; + NoneLegacyDispatchMethods["release"] = true; + NoneLegacyDispatchMethods["autorelease"] = true; + NoneLegacyDispatchMethods["hash"] = true; + NoneLegacyDispatchMethods["addObject:"] = true; + NoneLegacyDispatchMethods["countByEnumeratingWithState:objects:count:"] + = true; + } + const char *name = Sel.getAsString().c_str(); + if (NoneLegacyDispatchMethods[name]) + return false; + return true; +} + // Metadata flags enum MetaDataDlags { CLS = 0x0, @@ -5003,9 +5109,13 @@ CodeGen::RValue CGObjCNonFragileABIMac::GenerateMessageSend( bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { - return EmitMessageSend(CGF, ResultType, Sel, - Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs); + return LegacyDispatchedSelector(Sel) + ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), + Receiver, CGF.getContext().getObjCIdType(), + false, CallArgs, ObjCTypes) + : EmitMessageSend(CGF, ResultType, Sel, + Receiver, CGF.getContext().getObjCIdType(), + false, CallArgs); } llvm::GlobalVariable * @@ -5149,9 +5259,14 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return EmitMessageSend(CGF, ResultType, Sel, - ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs); + return (LegacyDispatchedSelector(Sel)) + ? EmitLegacyMessageSend(CGF, ResultType,EmitSelector(CGF.Builder, Sel), + ObjCSuper, ObjCTypes.SuperPtrCTy, + true, CallArgs, + ObjCTypes) + : EmitMessageSend(CGF, ResultType, Sel, + ObjCSuper, ObjCTypes.SuperPtrCTy, + true, CallArgs); } llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, @@ -5167,7 +5282,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, llvm::GlobalValue::InternalLinkage, Casted, "\01L_OBJC_SELECTOR_REFERENCES_", &CGM.getModule()); - Entry->setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip"); + Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip"); UsedGlobals.push_back(Entry); } diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m index 4f3691022f..bfc4ae9e75 100644 --- a/test/CodeGenObjC/metadata-symbols-64.m +++ b/test/CodeGenObjC/metadata-symbols-64.m @@ -13,10 +13,7 @@ // RUN: grep '@"\\01L_OBJC_METH_VAR_NAME_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t && // RUN: grep '@"\\01L_OBJC_METH_VAR_TYPE_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t && // RUN: grep '@"\\01L_OBJC_PROP_NAME_ATTR_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t && - -// FIXME: clang is not currently using "optimized" message dispatch in 64-bit mode. -// RUNX: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_[0-9]*" = internal global .* section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8' %t && - +// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_*" = internal global .* section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"' %t && // RUN: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t && // RUN: grep '@"\\01l_OBJC_$_CATEGORY_CLASS_METHODS_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t && // RUN: grep '@"\\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t && @@ -35,7 +32,7 @@ // RUN: grep '@_objc_empty_cache = external global' %t && // RUN: grep '@_objc_empty_vtable = external global' %t && // RUN: grep '@objc_msgSend_fixup(' %t && -// RUN: grep '@objc_msgSend_fpret_fixup(' %t && +// RUN: grep '@objc_msgSend_fpret(' %t && // RUN: true -- 2.40.0