Remove the unused/undefined `_cmd` parameter in `objc_direct` methods.

When `objc_direct` methods were implemented, the implicit `_cmd` parameter was left as an argument to the method implementation function, but was unset by callers; if the method body referenced the `_cmd` variable, a selector load would be emitted inside the body. However, this leaves an unused argument in the ABI, and is unnecessary.

This change removes the empty/unset argument, and if `_cmd` is referenced inside an `objc_direct` method it will emit local storage for the implicit variable. From the ABI perspective, `objc_direct` methods will have the implicit `self` parameter, immediately followed by whatever explicit arguments are defined on the method, rather than having one unset/undefined register in the middle.

Differential Revision: https://reviews.llvm.org/D131424
This commit is contained in:
Michael Wyman 2022-09-14 14:42:30 -07:00
parent 1d8a7adca6
commit aa4bcaab96
4 changed files with 32 additions and 20 deletions

View File

@ -484,9 +484,11 @@ const CGFunctionInfo &
CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
QualType receiverType) {
SmallVector<CanQualType, 16> argTys;
SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(2);
SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(
MD->isDirectMethod() ? 1 : 2);
argTys.push_back(Context.getCanonicalParamType(receiverType));
argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
if (!MD->isDirectMethod())
argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
// FIXME: Kill copy?
for (const auto *I : MD->parameters()) {
argTys.push_back(Context.getCanonicalParamType(I->getType()));

View File

@ -768,7 +768,8 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
}
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
if (!OMD->isDirectMethod())
args.push_back(OMD->getCmdDecl());
args.append(OMD->param_begin(), OMD->param_end());

View File

@ -2145,7 +2145,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
ActualArgs.add(RValue::get(SelValue), selTy);
if (!Method || !Method->isDirectMethod())
ActualArgs.add(RValue::get(SelValue), selTy);
ActualArgs.addFrom(CallArgs);
// If we're calling a method, use the formal signature.
@ -4103,6 +4104,9 @@ void CGObjCCommonMac::GenerateDirectMethodPrologue(
// 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()));
}

View File

@ -28,9 +28,7 @@ __attribute__((objc_root_class))
// CHECK-LABEL: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca
// CHECK-NEXT: [[SELFADDR:%.*]] = alloca %0*,
// CHECK-NEXT: [[_CMDADDR:%.*]] = alloca i8*,
// CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]],
// CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
// self nil-check
// CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** [[SELFADDR]],
@ -60,9 +58,7 @@ __attribute__((objc_root_class))
// loading parameters
// CHECK-LABEL: entry:
// CHECK-NEXT: [[SELFADDR:%.*]] = alloca i8*,
// CHECK-NEXT: [[_CMDADDR:%.*]] = alloca i8*,
// CHECK-NEXT: store i8* %{{.*}}, i8** [[SELFADDR]],
// CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
// [self self]
// CHECK-NEXT: [[SELF:%.*]] = load i8*, i8** [[SELFADDR]],
@ -81,9 +77,7 @@ __attribute__((objc_root_class))
// CHECK-LABEL: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca
// CHECK-NEXT: [[SELFADDR:%.*]] = alloca %0*,
// CHECK-NEXT: [[_CMDADDR:%.*]] = alloca i8*,
// CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]],
// CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
// self nil-check
// CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** [[SELFADDR]],
@ -125,9 +119,7 @@ __attribute__((objc_root_class))
// loading parameters
// CHECK-LABEL: entry:
// CHECK-NEXT: [[SELFADDR:%.*]] = alloca %0*,
// CHECK-NEXT: [[_CMDADDR:%.*]] = alloca i8*,
// CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]],
// CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
// self nil-check
// CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** [[SELFADDR]],
@ -159,6 +151,19 @@ __attribute__((objc_root_class))
// CHECK: ret void
}
// CHECK-LABEL: define hidden void @"\01-[Root accessCmd]"(
- (void)accessCmd __attribute__((objc_direct)) {
// CHECK-LABEL: entry:
// CHECK-NEXT: [[SELFADDR:%.*]] = alloca %0*,
// CHECK-NEXT: [[CMDVAL:%_cmd]] = alloca i8*,
// loading the _cmd selector
// CHECK-LABEL: objc_direct_method.cont:
// CHECK-NEXT: [[CMD1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: store i8* [[CMD1]], i8** [[CMDVAL]],
SEL sel = _cmd;
}
@end
// CHECK-LABEL: define hidden i32 @"\01-[Root intProperty]"
@ -205,19 +210,19 @@ __attribute__((objc_direct_members))
int useRoot(Root *r) {
// CHECK-LABEL: define{{.*}} i32 @useRoot
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root getInt]"
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty]"
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty2]"
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root getInt]" to i32 (i8*)
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty]" to i32 (i8*)
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty2]" to i32 (i8*)
return [r getInt] + [r intProperty] + [r intProperty2];
}
int useFoo(Foo *f) {
// CHECK-LABEL: define{{.*}} i32 @useFoo
// CHECK: call void bitcast {{.*}} @"\01-[Foo setGetDynamic_setDirect:]"
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo getDirect_setDynamic]"
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInExtension]"
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInCategory]"
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInCategoryNoDecl]"
// CHECK: call void bitcast {{.*}} @"\01-[Foo setGetDynamic_setDirect:]" to void (i8*, i32)
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo getDirect_setDynamic]" to i32 (i8*)
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInExtension]" to i32 (i8*)
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInCategory]" to i32 (i8*)
// CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInCategoryNoDecl]" to i32 (i8*)
[f setGetDynamic_setDirect:1];
return [f getDirect_setDynamic] +
[f directMethodInExtension] +