summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp43
-rw-r--r--clang/lib/CodeGen/CGObjCGNU.cpp10
-rw-r--r--clang/lib/CodeGen/CGObjCMac.cpp202
-rw-r--r--clang/lib/CodeGen/CGObjCRuntime.h21
4 files changed, 238 insertions, 38 deletions
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index c509149af3f..984fa599a99 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -430,6 +430,20 @@ tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
return None;
}
+CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
+ CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType,
+ Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
+ const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
+ bool isClassMessage) {
+ if (Optional<llvm::Value *> SpecializedResult =
+ tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
+ Sel, Method, isClassMessage)) {
+ return RValue::get(SpecializedResult.getValue());
+ }
+ return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID,
+ Method);
+}
+
/// Instead of '[[MyClass alloc] init]', try to generate
/// 'objc_alloc_init(MyClass)'. This provides a code size improvement on the
/// caller side, as well as the optimized objc_alloc.
@@ -611,16 +625,9 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
method);
} else {
// Call runtime methods directly if we can.
- if (Optional<llvm::Value *> SpecializedResult =
- tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args,
- E->getSelector(), method,
- isClassMessage)) {
- result = RValue::get(SpecializedResult.getValue());
- } else {
- result = Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(), Receiver, Args,
- OID, method);
- }
+ result = Runtime.GeneratePossiblySpecializedMessageSend(
+ *this, Return, ResultType, E->getSelector(), Receiver, Args, OID,
+ method, isClassMessage);
}
// For delegate init calls in ARC, implicitly store the result of
@@ -683,7 +690,13 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
- CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
+ if (OMD->isDirectMethod()) {
+ Fn->setVisibility(llvm::Function::HiddenVisibility);
+ CGM.SetLLVMFunctionAttributes(OMD, FI, Fn);
+ CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn);
+ } else {
+ CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
+ }
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
@@ -696,6 +709,14 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
OMD->getLocation(), StartLoc);
+ if (OMD->isDirectMethod()) {
+ // This function is a direct call, it has to implement a nil check
+ // on entry.
+ //
+ // TODO: possibly have several entry points to elide the check
+ CGM.getObjCRuntime().GenerateDirectMethodPrologue(*this, Fn, OMD, CD);
+ }
+
// In ARC, certain methods get an extra cleanup.
if (CGM.getLangOpts().ObjCAutoRefCount &&
OMD->isInstanceMethod() &&
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index c2702374858..12454bb5cb0 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -606,6 +606,9 @@ public:
llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) override;
+ void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) override;
void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override;
@@ -3871,6 +3874,13 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
return Method;
}
+void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF,
+ llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ // GNU runtime doesn't support direct calls at this time
+}
+
llvm::FunctionCallee CGObjCGNU::GetPropertyGetFunction() {
return GetPropertyFn;
}
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index d08a26f538b..775e3406da7 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -874,6 +874,10 @@ protected:
/// this translation unit.
llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
+ /// DirectMethodDefinitions - map of direct methods which have been defined in
+ /// this translation unit.
+ llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> DirectMethodDefinitions;
+
/// PropertyNames - uniqued method variable names.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
@@ -1065,7 +1069,7 @@ protected:
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
- llvm::Value *Sel,
+ Selector Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
@@ -1092,6 +1096,13 @@ public:
llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD=nullptr) override;
+ llvm::Function *GenerateDirectMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD);
+
+ void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) override;
+
void GenerateProtocol(const ObjCProtocolDecl *PD) override;
/// GetOrEmitProtocol - Get the protocol object for the given
@@ -1573,9 +1584,13 @@ private:
// base of the ivar access is a parameter to an Objective C method.
// However, because the parameters are not available in the current
// interface, we cannot perform this check.
+ //
+ // Note that for direct methods, because objc_msgSend is skipped,
+ // and that the method may be inlined, this optimization actually
+ // can't be performed.
if (const ObjCMethodDecl *MD =
dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
- if (MD->isInstanceMethod())
+ if (MD->isInstanceMethod() && !MD->isDirectMethod())
if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
return IV->getContainingInterface()->isSuperClassOf(ID);
return false;
@@ -2103,10 +2118,9 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, Class, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(),
+ ObjCTypes.SuperPtrCTy, true, CallArgs, Method, Class,
+ ObjCTypes);
}
/// Generate code for a message send expression.
@@ -2118,10 +2132,9 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
- return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, Class, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType, Sel, Receiver,
+ CGF.getContext().getObjCIdType(), false, CallArgs,
+ Method, Class, ObjCTypes);
}
static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) {
@@ -2137,7 +2150,7 @@ CodeGen::RValue
CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
- llvm::Value *Sel,
+ Selector Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
@@ -2145,11 +2158,24 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
const ObjCMethodDecl *Method,
const ObjCInterfaceDecl *ClassReceiver,
const ObjCCommonTypesHelper &ObjCTypes) {
+ CodeGenTypes &Types = CGM.getTypes();
+ auto selTy = CGF.getContext().getObjCSelType();
+ llvm::Value *SelValue;
+
+ if (Method && Method->isDirectMethod()) {
+ // Direct methods will synthesize the proper `_cmd` internally,
+ // so just don't bother with setting the `_cmd` argument.
+ assert(!IsSuper);
+ SelValue = llvm::UndefValue::get(Types.ConvertType(selTy));
+ } else {
+ SelValue = GetSelector(CGF, Sel);
+ }
+
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
- ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
+ ActualArgs.add(RValue::get(SelValue), selTy);
ActualArgs.addFrom(CallArgs);
// If we're calling a method, use the formal signature.
@@ -2190,7 +2216,9 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
bool RequiresNullCheck = false;
llvm::FunctionCallee Fn = nullptr;
- if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
+ if (Method && Method->isDirectMethod()) {
+ Fn = GenerateDirectMethod(Method, Method->getClassInterface());
+ } else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
if (ReceiverCanBeNull) RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
@@ -3297,6 +3325,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
values.addInt(ObjCTypes.IntTy, Properties.size());
auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy);
for (auto PD : Properties) {
+ if (PD->isDirectProperty())
+ continue;
auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy);
property.add(GetPropertyName(PD->getIdentifier()));
property.add(GetPropertyTypeString(PD, Container));
@@ -3372,7 +3402,8 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
};
SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
for (const auto *MD : OCD->methods()) {
- Methods[unsigned(MD->isClassMethod())].push_back(MD);
+ if (!MD->isDirectMethod())
+ Methods[unsigned(MD->isClassMethod())].push_back(MD);
}
Values.add(GetClassName(OCD->getName()));
@@ -3554,11 +3585,14 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
};
SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
for (const auto *MD : ID->methods()) {
- Methods[unsigned(MD->isClassMethod())].push_back(MD);
+ if (!MD->isDirectMethod())
+ Methods[unsigned(MD->isClassMethod())].push_back(MD);
}
for (const auto *PID : ID->property_impls()) {
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
+ if (PID->getPropertyDecl()->isDirectProperty())
+ continue;
if (ObjCMethodDecl *MD = PID->getGetterMethodDecl())
if (GetMethodDefinition(MD))
Methods[InstanceMethods].push_back(MD);
@@ -3957,7 +3991,8 @@ llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT,
values.addInt(ObjCTypes.IntTy, methods.size());
auto methodArray = values.beginArray(ObjCTypes.MethodTy);
for (auto MD : methods) {
- emitMethodConstant(methodArray, MD);
+ if (!MD->isDirectMethod())
+ emitMethodConstant(methodArray, MD);
}
methodArray.finishAndAddTo(values);
@@ -3968,6 +4003,34 @@ llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT,
llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
+ llvm::Function *Method;
+
+ if (OMD->isDirectMethod()) {
+ Method = GenerateDirectMethod(OMD, CD);
+ } else {
+ SmallString<256> Name;
+ GetNameForMethod(OMD, CD, Name);
+
+ CodeGenTypes &Types = CGM.getTypes();
+ llvm::FunctionType *MethodTy =
+ Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
+ Method =
+ llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage,
+ Name.str(), &CGM.getModule());
+ }
+
+ MethodDefinitions.insert(std::make_pair(OMD, Method));
+
+ return Method;
+}
+
+llvm::Function *
+CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ auto I = DirectMethodDefinitions.find(OMD);
+ if (I != DirectMethodDefinitions.end())
+ return I->second;
+
SmallString<256> Name;
GetNameForMethod(OMD, CD, Name);
@@ -3975,15 +4038,98 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
llvm::Function *Method =
- llvm::Function::Create(MethodTy,
- llvm::GlobalValue::InternalLinkage,
- Name.str(),
- &CGM.getModule());
- MethodDefinitions.insert(std::make_pair(OMD, Method));
+ llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
+ Name.str(), &CGM.getModule());
+ DirectMethodDefinitions.insert(std::make_pair(OMD, Method));
return Method;
}
+void CGObjCCommonMac::GenerateDirectMethodPrologue(
+ CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ 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.createBranchWeights(1, 1 << 20));
+
+ 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()) {
+ Builder.CreateStore(GetSelector(CGF, OMD),
+ CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
+ }
+}
+
llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
ConstantStructBuilder &Init,
StringRef Section,
@@ -6226,10 +6372,12 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
SmallVector<const ObjCMethodDecl*, 16> methods;
if (flags & NonFragileABI_Class_Meta) {
for (const auto *MD : ID->class_methods())
- methods.push_back(MD);
+ if (!MD->isDirectMethod())
+ methods.push_back(MD);
} else {
for (const auto *MD : ID->instance_methods())
- methods.push_back(MD);
+ if (!MD->isDirectMethod())
+ methods.push_back(MD);
}
values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
@@ -6550,6 +6698,8 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
SmallVector<const ObjCMethodDecl *, 16> instanceMethods;
SmallVector<const ObjCMethodDecl *, 8> classMethods;
for (const auto *MD : OCD->methods()) {
+ if (MD->isDirectMethod())
+ continue;
if (MD->isInstanceMethod()) {
instanceMethods.push_back(MD);
} else {
@@ -7218,8 +7368,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method)
- : EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
+ : EmitMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, Class, ObjCTypes);
}
@@ -7450,8 +7599,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
true, CallArgs, Method)
- : EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
+ : EmitMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, Class, ObjCTypes);
}
diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h
index 471816cb598..f0b3525cfde 100644
--- a/clang/lib/CodeGen/CGObjCRuntime.h
+++ b/clang/lib/CodeGen/CGObjCRuntime.h
@@ -169,6 +169,21 @@ public:
const ObjCInterfaceDecl *Class = nullptr,
const ObjCMethodDecl *Method = nullptr) = 0;
+ /// Generate an Objective-C message send operation.
+ ///
+ /// This variant allows for the call to be substituted with an optimized
+ /// variant.
+ CodeGen::RValue
+ GeneratePossiblySpecializedMessageSend(CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ const CallArgList& Args,
+ const ObjCInterfaceDecl *OID,
+ const ObjCMethodDecl *Method,
+ bool isClassMessage);
+
/// Generate an Objective-C message send operation to the super
/// class initiated in a method for Class and with the given Self
/// object.
@@ -205,6 +220,12 @@ public:
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) = 0;
+ /// Generates prologue for direct Objective-C Methods.
+ virtual void GenerateDirectMethodPrologue(CodeGenFunction &CGF,
+ llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) = 0;
+
/// Return the runtime function for getting properties.
virtual llvm::FunctionCallee GetPropertyGetFunction() = 0;
OpenPOWER on IntegriCloud