diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index 50908ad1cb5fe2347f357a07ec2450ea6df6a172..68fd0283adbb78755e3e1eb1d06be81f0fd2442f 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -1047,6 +1047,17 @@ are listed below. efficient model can be used. The TLS model can be overridden per variable using the ``tls_model`` attribute. +.. option:: -mhwdiv=[values] + + Select the ARM modes (arm or thumb) that support hardware division + instructions. + + Valid values are: ``arm``, ``thumb`` and ``arm,thumb``. + This option is used to indicate which mode (arm or thumb) supports + hardware division instructions. This only applies to the ARM + architecture. + + Controlling Size of Debug Information ------------------------------------- diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 88b685ba900c29031f59cb9ba8e040557036ae17..85ca258fa7d326c738872631335b3d36231c35ee 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -950,6 +950,7 @@ def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group<cl def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>; def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>; def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>; +def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>; def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>; def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>; def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>; @@ -1279,6 +1280,7 @@ def working_directory_EQ : Joined<["-"], "working-directory=">, Flags<[CC1Option // Double dash options, which are usually an alias for one of the previous // options. +def _mhwdiv_EQ : Separate<["--"], "mhwdiv">, Alias<mhwdiv_EQ>; def _CLASSPATH_EQ : Joined<["--"], "CLASSPATH=">, Alias<fclasspath_EQ>; def _CLASSPATH : Separate<["--"], "CLASSPATH">, Alias<fclasspath_EQ>; def _all_warnings : Flag<["--"], "all-warnings">, Alias<Wall>; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 2f90e98a391d159f88850b4fbffc89a661abd000..f5249e54670cc2e07c071fca8fc34ed87f1479e3 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -3599,6 +3599,12 @@ class ARMTargetInfo : public TargetInfo { NeonFPU = (1 << 3) }; + // Possible HWDiv features. + enum HWDivMode { + HWDivThumb = (1 << 0), + HWDivARM = (1 << 1) + }; + static bool FPUModeIsVFP(FPUMode Mode) { return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU); } @@ -3618,6 +3624,7 @@ class ARMTargetInfo : public TargetInfo { unsigned IsAAPCS : 1; unsigned IsThumb : 1; + unsigned HWDiv : 2; // Initialized via features. unsigned SoftFloat : 1; @@ -3770,6 +3777,7 @@ public: DiagnosticsEngine &Diags) { FPU = 0; SoftFloat = SoftFloatABI = false; + HWDiv = 0; for (unsigned i = 0, e = Features.size(); i != e; ++i) { if (Features[i] == "+soft-float") SoftFloat = true; @@ -3783,6 +3791,10 @@ public: FPU |= VFP4FPU; else if (Features[i] == "+neon") FPU |= NeonFPU; + else if (Features[i] == "+hwdiv") + HWDiv |= HWDivThumb; + else if (Features[i] == "+hwdiv-arm") + HWDiv |= HWDivARM; } if (!(FPU & NeonFPU) && FPMath == FP_Neon) { @@ -3812,6 +3824,8 @@ public: .Case("softfloat", SoftFloat) .Case("thumb", IsThumb) .Case("neon", (FPU & NeonFPU) && !SoftFloat) + .Case("hwdiv", HWDiv & HWDivThumb) + .Case("hwdiv-arm", HWDiv & HWDivARM) .Default(false); } // FIXME: Should we actually have some table instead of these switches? @@ -3905,6 +3919,8 @@ public: if (CPUArch == "6T2" || IsARMv7) Builder.defineMacro("__thumb2__"); } + if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb)) + Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); // Note, this is always on in gcc, even though it doesn't make sense. Builder.defineMacro("__APCS_32__"); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 3c98cb38eef34191cadd57a0559f1981d613a922..4592308e1a57a74cbbff8ddc4b6232093ea413f2 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -596,6 +596,27 @@ static void getAArch64FPUFeatures(const Driver &D, const Arg *A, D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } +// Handle -mhwdiv=. +static void getARMHWDivFeatures(const Driver &D, const Arg *A, + const ArgList &Args, + std::vector<const char *> &Features) { + StringRef HWDiv = A->getValue(); + if (HWDiv == "arm") { + Features.push_back("+hwdiv-arm"); + Features.push_back("-hwdiv"); + } else if (HWDiv == "thumb") { + Features.push_back("-hwdiv-arm"); + Features.push_back("+hwdiv"); + } else if (HWDiv == "arm,thumb" || HWDiv == "thumb,arm") { + Features.push_back("+hwdiv-arm"); + Features.push_back("+hwdiv"); + } else if (HWDiv == "none") { + Features.push_back("-hwdiv-arm"); + Features.push_back("-hwdiv"); + } else + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); +} + // Handle -mfpu=. // // FIXME: Centralize feature selection, defaulting shouldn't be also in the @@ -740,6 +761,8 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, // Honor -mfpu=. if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) getARMFPUFeatures(D, A, Args, Features); + if (const Arg *A = Args.getLastArg(options::OPT_mhwdiv_EQ)) + getARMHWDivFeatures(D, A, Args, Features); // Setting -msoft-float effectively disables NEON because of the GCC // implementation, although the same isn't true of VFP or VFP3. diff --git a/test/Driver/arm-hwdiv.c b/test/Driver/arm-hwdiv.c new file mode 100644 index 0000000000000000000000000000000000000000..b3617ce5345226dfe21b41b73816a22a529871f3 --- /dev/null +++ b/test/Driver/arm-hwdiv.c @@ -0,0 +1,39 @@ +// Test that different values of -mhwdiv pick correct ARM hwdiv target-feature(s). + +// RUN: %clang -### -target arm %s -o %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-DEFAULT %s +// CHECK-DEFAULT-NOT: "-target-feature" "+hwdiv" +// CHECK-DEFAULT-NOT: "-target-feature" "+hwdiv-arm" + +// RUN: %clang -### -target arm %s -mhwdiv=arm -o %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARM %s +// CHECK-ARM: "-target-feature" "+hwdiv-arm" +// CHECK-ARM: "-target-feature" "-hwdiv" + +// RUN: %clang -### -target arm %s -mhwdiv=thumb -o %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-THUMB %s +// CHECK-THUMB: "-target-feature" "-hwdiv-arm" +// CHECK-THUMB: "-target-feature" "+hwdiv" + +// RUN: %clang -### -target arm %s -mhwdiv=arm,thumb -o %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARM-THUMB %s +// CHECK-ARM-THUMB: "-target-feature" "+hwdiv-arm" +// CHECK-ARM-THUMB: "-target-feature" "+hwdiv" + +// RUN: %clang -### -target arm %s -mhwdiv=thumb,arm -o %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-THUMB-ARM %s +// CHECK-THUMB-ARM: "-target-feature" "+hwdiv-arm" +// CHECK-THUMB-ARM: "-target-feature" "+hwdiv" + +// RUN: %clang -### -target arm %s -mhwdiv=none -o %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-NONE %s +// CHECK-NONE: "-target-feature" "-hwdiv-arm" +// CHECK-NONE: "-target-feature" "-hwdiv" + +// Also check the alternative syntax. + +// RUN: %clang -### -target arm %s --mhwdiv arm -o %t.o 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ALT %s +// CHECK-ALT: "-target-feature" "+hwdiv-arm" +// CHECK-ALT: "-target-feature" "-hwdiv" + diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index 1324733786947d985d639a19c6306aee2200ab6f..c3b01504dc8513b133eb90df8107409ef65e3bc5 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -512,6 +512,26 @@ // ARMEABIHARDFP:#define __arm 1 // ARMEABIHARDFP:#define __arm__ 1 +// Check that -mhwdiv works properly for targets which don't have the hwdiv feature enabled by default. + +// RUN: %clang -target arm -mhwdiv=arm -x c -E -dM %s -o - | FileCheck --check-prefix=ARMHWDIV-ARM %s +// ARMHWDIV-ARM:#define __ARM_ARCH_EXT_IDIV__ 1 + +// RUN: %clang -target arm -mthumb -mhwdiv=thumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBHWDIV-THUMB %s +// THUMBHWDIV-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1 + +// RUN: %clang -target arm -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-FALSE %s +// ARM-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__ + +// RUN: %clang -target arm -mthumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMB-FALSE %s +// THUMB-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__ + +// RUN: %clang -target arm -mhwdiv=thumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBHWDIV-ARM-FALSE %s +// THUMBHWDIV-ARM-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__ + +// RUN: %clang -target arm -mthumb -mhwdiv=arm -x c -E -dM %s -o - | FileCheck --check-prefix=ARMHWDIV-THUMB-FALSE %s +// ARMHWDIV-THUMB-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__ + // // RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-none-none < /dev/null | FileCheck -check-prefix I386 %s //