Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -484,9 +484,11 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD, QualType receiverType) { SmallVector argTys; - SmallVector extParamInfos(2); + SmallVector 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())); Index: clang/lib/CodeGen/CGObjC.cpp =================================================================== --- clang/lib/CodeGen/CGObjC.cpp +++ clang/lib/CodeGen/CGObjC.cpp @@ -768,7 +768,8 @@ } 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()); Index: clang/lib/CodeGen/CGObjCMac.cpp =================================================================== --- clang/lib/CodeGen/CGObjCMac.cpp +++ clang/lib/CodeGen/CGObjCMac.cpp @@ -2145,7 +2145,8 @@ 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 @@ // 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())); } Index: clang/test/CodeGenObjC/direct-method.m =================================================================== --- clang/test/CodeGenObjC/direct-method.m +++ clang/test/CodeGenObjC/direct-method.m @@ -28,9 +28,7 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ 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] +