NeXT: Clean up dispatch method policy selection.
- Replace -cc1 level -fobjc-legacy-dispatch with -fobjc-dispatch-method={legacy,non-legacy,mixed}.
- Lift "mixed" vs "non-mixed" policy choice up to driver level, instead of being buried in CGObjCMac.cpp.
- No intended functionality change.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102255 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h
index 51b9c57..54d3ba0 100644
--- a/include/clang/CodeGen/CodeGenOptions.h
+++ b/include/clang/CodeGen/CodeGenOptions.h
@@ -28,6 +28,12 @@
OnlyAlwaysInlining // Only run the always inlining pass.
};
+ enum ObjCDispatchMethodKind {
+ Legacy = 0,
+ NonLegacy = 1,
+ Mixed = 2
+ };
+
unsigned AsmVerbose : 1; /// -dA, -fverbose-asm.
unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors.
unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
@@ -45,8 +51,7 @@
unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled.
unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled.
unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss
- unsigned ObjCLegacyDispatch: 1; /// Use legacy Objective-C dispatch, even with
- /// 2.0 runtime.
+ unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use.
unsigned OptimizationLevel : 3; /// The -O[0-4] option specified.
unsigned OptimizeSize : 1; /// If -Os is specified.
unsigned SoftFloat : 1; /// -soft-float.
@@ -100,7 +105,7 @@
NoCommon = 0;
NoImplicitFloat = 0;
NoZeroInitializedInBSS = 0;
- ObjCLegacyDispatch = 0;
+ ObjCDispatchMethod = Legacy;
OptimizationLevel = 0;
OptimizeSize = 0;
SoftFloat = 0;
@@ -113,6 +118,10 @@
Inlining = NoInlining;
RelocationModel = "pic";
}
+
+ ObjCDispatchMethodKind getObjCDispatchMethod() const {
+ return ObjCDispatchMethodKind(ObjCDispatchMethod);
+ }
};
} // end namespace clang
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 9fd21e9..18b54ef 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -391,8 +391,8 @@
HelpText<"Enable Objective-C garbage collection">;
def fobjc_gc_only : Flag<"-fobjc-gc-only">,
HelpText<"Use GC exclusively for Objective-C related memory management">;
-def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">,
- HelpText<"Use legacy dispatch with the Objective-C non-fragile ABI">;
+def fobjc_dispatch_method_EQ : Joined<"-fobjc-dispatch-method=">,
+ HelpText<"Objective-C dispatch method to use">;
def print_ivar_layout : Flag<"-print-ivar-layout">,
HelpText<"Enable Objective-C Ivar layout bitmap print trace">;
def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">,
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index b58205c..1a8ae77 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -103,6 +103,10 @@
/// ABI).
virtual bool IsObjCLegacyDispatchDefault() const { return false; }
+ /// UseObjCMixedDispatchDefault - When using non-legacy dispatch, should the
+ /// mixed dispatch method be used?
+ virtual bool UseObjCMixedDispatch() const { return false; }
+
/// GetDefaultStackProtectorLevel - Get the default stack protector level for
/// this tool chain (0=off, 1=on, 2=all).
virtual unsigned GetDefaultStackProtectorLevel() const { return 0; }
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index e000bd2..098a0f8 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -4275,13 +4275,19 @@
/// message dispatch call for all the rest.
///
bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
- if (CGM.getCodeGenOpts().ObjCLegacyDispatch)
+ switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
+ default:
+ assert(0 && "Invalid dispatch method!");
+ case CodeGenOptions::Legacy:
return true;
- /* Leopard */
- if (CGM.getContext().Target.getTriple().getOS() == llvm::Triple::Darwin &&
- CGM.getContext().Target.getTriple().getDarwinMajorNumber() <= 9)
+ case CodeGenOptions::NonLegacy:
return false;
-
+ case CodeGenOptions::Mixed:
+ break;
+ }
+
+ // If so, see whether this selector is in the white-list of things which must
+ // use the new dispatch convention. We lazily build a dense set for this.
if (NonLegacyDispatchMethods.empty()) {
NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
@@ -4311,6 +4317,7 @@
NonLegacyDispatchMethods.insert(
CGM.getContext().Selectors.getSelector(3, KeyIdents));
}
+
return (NonLegacyDispatchMethods.count(Sel) == 0);
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 9e61b89..a307b2b 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -168,6 +168,12 @@
return (getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::thumb);
}
+ virtual bool UseObjCMixedDispatch() const {
+ // Mixed dispatch is only used on x86_64 for 10.6 and later.
+ return (!isTargetIPhoneOS() &&
+ getTriple().getArch() == llvm::Triple::x86_64 &&
+ !isMacosxVersionLT(10, 6));
+ }
virtual bool IsUnwindTablesDefault() const;
virtual unsigned GetDefaultStackProtectorLevel() const {
// Stack protectors default to on for 10.6 and beyond.
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 2e8db00..8ad04aa 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1230,13 +1230,17 @@
if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) ||
getToolChain().IsObjCNonFragileABIDefault()) {
CmdArgs.push_back("-fobjc-nonfragile-abi");
-
- // -fobjc-legacy-dispatch is only relevant with the nonfragile-abi, and
- // defaults to off.
- if (Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
- options::OPT_fno_objc_legacy_dispatch,
- getToolChain().IsObjCLegacyDispatchDefault()))
- CmdArgs.push_back("-fobjc-legacy-dispatch");
+
+ // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
+ // legacy is the default.
+ if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ getToolChain().IsObjCLegacyDispatchDefault())) {
+ if (getToolChain().UseObjCMixedDispatch())
+ CmdArgs.push_back("-fobjc-dispatch-method=mixed");
+ else
+ CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
+ }
}
}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index db937bc..68842a4 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -178,8 +178,16 @@
}
if (Opts.NoZeroInitializedInBSS)
Res.push_back("-mno-zero-initialized-bss");
- if (Opts.ObjCLegacyDispatch)
- Res.push_back("-fobjc-legacy-dispatch");
+ switch (Opts.getObjCDispatchMethod()) {
+ case CodeGenOptions::Legacy:
+ break;
+ case CodeGenOptions::Mixed:
+ Res.push_back("-fobjc-dispatch-method=mixed");
+ break;
+ case CodeGenOptions::NonLegacy:
+ Res.push_back("-fobjc-dispatch-method=non-legacy");
+ break;
+ }
if (Opts.SoftFloat)
Res.push_back("-msoft-float");
if (Opts.UnwindTables)
@@ -820,7 +828,6 @@
Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi);
Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
- Opts.ObjCLegacyDispatch = Args.hasArg(OPT_fobjc_legacy_dispatch);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
@@ -830,6 +837,19 @@
Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
+
+ if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
+ llvm::StringRef Name = A->getValue(Args);
+ unsigned Method = llvm::StringSwitch<unsigned>(Name)
+ .Case("legacy", CodeGenOptions::Legacy)
+ .Case("non-legacy", CodeGenOptions::NonLegacy)
+ .Case("mixed", CodeGenOptions::Mixed)
+ .Default(~0U);
+ if (Method == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ else
+ Opts.ObjCDispatchMethod = Method;
+ }
}
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
diff --git a/test/CodeGenObjC/legacy-api-leopard-test.m b/test/CodeGenObjC/legacy-api-leopard-test.m
deleted file mode 100644
index 1a229c6..0000000
--- a/test/CodeGenObjC/legacy-api-leopard-test.m
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
-// rdar: // 7866951
-
-@interface NSObject
-- (id)init;
-@end
-
-@interface ClangTest : NSObject @end
-
-@implementation ClangTest
-- (id)init
-{
- [super init];
- return self;
-}
-@end
-
-// CHECK-LP64: objc_msgSendSuper2_fixup_init
-// CHECK-LP64: objc_msgSendSuper2_fixup
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index 886d53a..dbc06d7 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed -emit-llvm -o %t %s
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: grep '@"OBJC_CLASS_$_A" = global' %t
diff --git a/test/CodeGenObjC/next-objc-dispatch.m b/test/CodeGenObjC/next-objc-dispatch.m
new file mode 100644
index 0000000..a3e8e19
--- /dev/null
+++ b/test/CodeGenObjC/next-objc-dispatch.m
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-dispatch-method=legacy | \
+// RUN: FileCheck -check-prefix CHECK-FRAGILE_LEGACY %s
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=legacy | \
+// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_LEGACY %s
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=non-legacy | \
+// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_NONLEGACY %s
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed | \
+// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_MIXED %s
+//
+// <rdar://problem/7866951>
+
+// There are basically four ways that we end up doing message dispatch for the
+// NeXT runtime. They are:
+// (1) fragile ABI, legacy dispatch
+// (2) non-fragile ABI, legacy dispatch
+// (2) non-fragile ABI, non-legacy dispatch
+// (2) non-fragile ABI, mixed dispatch
+//
+// Note that fragile ABI and non-fragile ABI legacy dispatch are not the same,
+// they use some different API calls (objc_msgSendSuper vs objc_msgSendSuper2).
+
+// CHECK-FRAGILE_LEGACY: ModuleID
+// CHECK-FRAGILE_LEGACY-NOT: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-FRAGILE_LEGACY-NOT: declare i8* @objc_msgSend_fixup(
+// CHECK-FRAGILE_LEGACY: declare i8* @objc_msgSendSuper(
+// CHECK-FRAGILE_LEGACY: declare i8* @objc_msgSend(
+
+// CHECK-NONFRAGILE_LEGACY: ModuleID
+// CHECK-NONFRAGILE_LEGACY-NOT: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-NONFRAGILE_LEGACY-NOT: declare i8* @objc_msgSend_fixup(
+// CHECK-NONFRAGILE_LEGACY: declare i8* @objc_msgSendSuper2(
+// CHECK-NONFRAGILE_LEGACY: declare i8* @objc_msgSend(
+
+// CHECK-NONFRAGILE_NONLEGACY: ModuleID
+// CHECK-NONFRAGILE_NONLEGACY: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-NONFRAGILE_NONLEGACY: declare i8* @objc_msgSend_fixup(
+
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSendSuper2(
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSend_fixup(
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSend(
+
+@interface NSObject
++ (id)alloc;
+- (id)init;
+@end
+
+@interface I0 : NSObject
+-(void) im0;
+@end
+
+@implementation I0
++(id) alloc {
+ return [super alloc];
+}
+-(id) init {
+ [super init];
+ return self;
+}
+-(void) im0 {}
+@end
+
+void f0(I0 *a) {
+ [I0 alloc];
+ [a im0];
+}
diff --git a/test/CodeGenObjC/objc2-legacy-dispatch.m b/test/CodeGenObjC/objc2-legacy-dispatch.m
index 9f9a6aa..7a99d15 100644
--- a/test/CodeGenObjC/objc2-legacy-dispatch.m
+++ b/test/CodeGenObjC/objc2-legacy-dispatch.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_NEW_DISPATCH %s
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_NEW_DISPATCH %s
//
// CHECK_NEW_DISPATCH: define void @f0
// CHECK_NEW_DISPATCH: bitcast {{.*}}objc_msgSend_fixup_alloc
// CHECK_NEW_DISPATCH: define void @f1
// CHECK_NEW_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
//
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-legacy-dispatch -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_OLD_DISPATCH %s
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-dispatch-method=legacy -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_OLD_DISPATCH %s
//
// CHECK_OLD_DISPATCH: define void @f0
// CHECK_OLD_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES