Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -518,19 +518,29 @@ } // Get Arch/CPU from args. -static void getARMArchCPUFromArgs(const ArgList &Args, - llvm::StringRef &Arch, - llvm::StringRef &CPU) { +static void getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, + llvm::StringRef &CPU, bool FromAs = false) { if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) CPU = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) Arch = A->getValue(); + if (!FromAs) + return; + + for (const Arg *A : + Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { + StringRef Value = A->getValue(); + if (Value.startswith("-mcpu=")) + CPU = Value.substr(6); + if (Value.startswith("-march=")) + Arch = Value.substr(7); + } } // Handle -mhwdiv=. +// FIXME: Use ARMTargetParser. static void getARMHWDivFeatures(const Driver &D, const Arg *A, - const ArgList &Args, - StringRef HWDiv, + const ArgList &Args, StringRef HWDiv, std::vector &Features) { if (HWDiv == "arm") { Features.push_back("+hwdiv-arm"); @@ -550,17 +560,17 @@ // Handle -mfpu=. static void getARMFPUFeatures(const Driver &D, const Arg *A, - const ArgList &Args, - StringRef FPU, + const ArgList &Args, StringRef FPU, std::vector &Features) { unsigned FPUID = llvm::ARMTargetParser::parseFPU(FPU); if (!llvm::ARMTargetParser::getFPUFeatures(FPUID, Features)) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } -// Check -march=. -static void checkARMArchName(const Driver &D, const Arg *A, - const ArgList &Args, +// Check if -march is valid by checking if it can be canonicalised and parsed. +// getARMArch is used here instead of just checking the -march value in order +// to handle -march=native correctly. +static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef ArchName, const llvm::Triple &Triple) { std::string MArch = arm::getARMArch(ArchName, Triple); @@ -568,11 +578,9 @@ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } -// Check -mcpu=. -static void checkARMCPUName(const Driver &D, const Arg *A, - const ArgList &Args, - llvm::StringRef CPUName, - llvm::StringRef ArchName, +// Check -mcpu=. Needs ArchName to handle -mcpu=generic. +static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, + llvm::StringRef CPUName, llvm::StringRef ArchName, const llvm::Triple &Triple) { std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); std::string Arch = arm::getARMArch(ArchName, Triple); @@ -677,6 +685,9 @@ bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); + const Arg *WaCPU = nullptr, *WaFPU = nullptr; + const Arg *WaHdiv = nullptr, *WaArch = nullptr; + if (!ForAS) { // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these // yet (it uses the -mfloat-abi and -msoft-float options), and it is @@ -697,31 +708,75 @@ // Use software floating point argument passing? if (FloatABI != "hard") Features.push_back("+soft-float-abi"); + } else { + // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down + // to the assembler correctly. + for (const Arg *A : + Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { + StringRef Value = A->getValue(); + if (Value.startswith("-mfpu=")) { + WaFPU = A; + } else if (Value.startswith("-mcpu=")) { + WaCPU = A; + } else if (Value.startswith("-mhwdiv=")) { + WaHdiv = A; + } else if (Value.startswith("-march=")) { + WaArch = A; + } + } } - // Honor -mfpu=. - if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) - getARMFPUFeatures(D, A, Args, A->getValue(), Features); - // Honor -mhwdiv= - if (const Arg *A = Args.getLastArg(options::OPT_mhwdiv_EQ)) - getARMHWDivFeatures(D, A, Args, A->getValue(), Features); - - // Check if -march is valid by checking if it can be canonicalised and parsed. - // getARMArch is used here instead of just checking the -march value in order - // to handle -march=native correctly. + // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. + const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); + if (WaFPU) { + if (FPUArg) + D.Diag(clang::diag::warn_drv_unused_argument) + << FPUArg->getAsString(Args); + getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), + Features); + } else if (FPUArg) { + getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); + } + + // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. + const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); + if (WaHdiv) { + if (HDivArg) + D.Diag(clang::diag::warn_drv_unused_argument) + << HDivArg->getAsString(Args); + getARMHWDivFeatures(D, WaHdiv, Args, + StringRef(WaHdiv->getValue()).substr(8), Features); + } else if (HDivArg) + getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); + + // Check -march. ClangAs gives preference to -Wa,-march=. + const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); StringRef ArchName; - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - ArchName = A->getValue(); - checkARMArchName(D, A, Args, ArchName, Triple); - } - - // We do a similar thing with -mcpu, but here things are complicated because - // the only function we have to check if a cpu is valid is - // getLLVMArchSuffixForARM which also needs an architecture. + if (WaArch) { + if (ArchArg) + D.Diag(clang::diag::warn_drv_unused_argument) + << ArchArg->getAsString(Args); + ArchName = StringRef(WaArch->getValue()).substr(7); + checkARMArchName(D, WaArch, Args, ArchName, Triple); + // FIXME: Set Arch. + D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args); + } else if (ArchArg) { + ArchName = ArchArg->getValue(); + checkARMArchName(D, ArchArg, Args, ArchName, Triple); + } + + // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. + const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); StringRef CPUName; - if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - CPUName = A->getValue(); - checkARMCPUName(D, A, Args, CPUName, ArchName, Triple); + if (WaCPU) { + if (CPUArg) + D.Diag(clang::diag::warn_drv_unused_argument) + << CPUArg->getAsString(Args); + CPUName = StringRef(WaCPU->getValue()).substr(6); + checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Triple); + } else if (CPUArg) { + CPUName = CPUArg->getValue(); + checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Triple); } // Setting -msoft-float effectively disables NEON because of the GCC @@ -869,7 +924,6 @@ if (!Args.hasFlag(options::OPT_mimplicit_float, options::OPT_mno_implicit_float, true)) CmdArgs.push_back("-no-implicit-float"); - } // ARM tools end. @@ -977,7 +1031,7 @@ DefMips32CPU = "mips32r6"; DefMips64CPU = "mips64r6"; } - + // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android). if (Triple.getEnvironment() == llvm::Triple::Android) DefMips64CPU = "mips64r6"; @@ -1503,7 +1557,8 @@ } } -static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) { +static std::string getCPUName(const ArgList &Args, const llvm::Triple &T, + bool FromAs = false) { switch (T.getArch()) { default: return ""; @@ -1517,7 +1572,7 @@ case llvm::Triple::thumb: case llvm::Triple::thumbeb: { StringRef MArch, MCPU; - getARMArchCPUFromArgs(Args, MArch, MCPU); + getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs); return arm::getARMTargetCPU(MCPU, MArch, T); } case llvm::Triple::mips: @@ -2241,12 +2296,12 @@ Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { A->claim(); - for (const StringRef Value : A->getValues()) { - if (TakeNextArg) { - CmdArgs.push_back(Value.data()); - TakeNextArg = false; - continue; - } + for (const StringRef Value : A->getValues()) { + if (TakeNextArg) { + CmdArgs.push_back(Value.data()); + TakeNextArg = false; + continue; + } if (Value == "-force_cpusubtype_ALL") { // Do nothing, this is the default and we don't support anything else. @@ -2270,6 +2325,9 @@ TakeNextArg = true; } else if (Value.startswith("-gdwarf-")) { CmdArgs.push_back(Value.data()); + } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || + Value.startswith("-mhwdiv") || Value.startswith("-march")) { + // Do nothing, we'll validate it later. } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; @@ -2794,8 +2852,7 @@ if (ProfileGenerateArg && ProfileUseArg) D.Diag(diag::err_drv_argument_not_allowed_with) - << ProfileGenerateArg->getSpelling() - << ProfileUseArg->getSpelling(); + << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling(); if (ProfileGenerateArg && ProfileGenerateArg->getOption().matches( @@ -2951,8 +3008,7 @@ assert((isa(JA) || isa(JA)) && "Invalid action for clang tool."); - if (JA.getType() == types::TY_LTO_IR || - JA.getType() == types::TY_LTO_BC) { + if (JA.getType() == types::TY_LTO_IR || JA.getType() == types::TY_LTO_BC) { CmdArgs.push_back("-flto"); } if (JA.getType() == types::TY_Nothing) { @@ -3478,7 +3534,7 @@ } // Add the target cpu - std::string CPU = getCPUName(Args, Triple); + std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); @@ -4278,8 +4334,7 @@ llvm::sys::path::append(Path, "modules"); } else if (Path.empty()) { // No module path was provided: use the default. - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, - Path); + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path); llvm::sys::path::append(Path, "org.llvm.clang."); appendUserToPath(Path); llvm::sys::path::append(Path, "ModuleCache"); @@ -5309,7 +5364,7 @@ // Add the target cpu const llvm::Triple Triple(TripleStr); - std::string CPU = getCPUName(Args, Triple); + std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); @@ -5837,8 +5892,7 @@ } // AMDGPU tools end. -const std::string arm::getARMArch(StringRef Arch, - const llvm::Triple &Triple) { +const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { std::string MArch; if (!Arch.empty()) MArch = Arch; @@ -5864,8 +5918,7 @@ return MArch; } /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. -const char *arm::getARMCPUForMArch(StringRef Arch, - const llvm::Triple &Triple) { +const char *arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { std::string MArch = getARMArch(Arch, Triple); // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch // here means an -march=native that we can't handle, so instead return no CPU. @@ -5882,8 +5935,7 @@ } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. -std::string arm::getARMTargetCPU(StringRef CPU, - StringRef Arch, +std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, const llvm::Triple &Triple) { // FIXME: Warn on inconsistent use of -mcpu and -march. // If we have -mcpu=, use that. @@ -7396,8 +7448,9 @@ case llvm::Triple::thumb: case llvm::Triple::thumbeb: { StringRef MArch, MCPU; - getARMArchCPUFromArgs(Args, MArch, MCPU); - std::string Arch = arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple()); + getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); + std::string Arch = + arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple()); CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); break; } Index: test/Driver/arm-ias-Wa.s =================================================================== --- /dev/null +++ test/Driver/arm-ias-Wa.s @@ -0,0 +1,64 @@ +// Test that different values of -Wa,-mcpu/mfpu/march/mhwdiv pick correct ARM target-feature(s). +// Complete tests about -mcpu/mfpu/march/mhwdiv on other files. + +// CHECK-DUP-CPU: warning: argument unused during compilation: '-mcpu=cortex-a8' +// CHECK-DUP-FPU: warning: argument unused during compilation: '-mfpu=vfpv3' +// CHECK-DUP-ARCH: warning: argument unused during compilation: '-march=armv7' +// CHECK-DUP-HDIV: warning: argument unused during compilation: '-mhwdiv=arm' + +// CHECK: "cc1as" +// ================================================================= CPU +// RUN: %clang -target arm-linux-gnueabi -Wa,-mcpu=cortex-a15 -c %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-CPU %s +// CHECK-CPU: "-target-cpu" "cortex-a15" + +// RUN: %clang -target arm -Wa,-mcpu=bogus -c %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-BOGUS-CPU %s +// CHECK-BOGUS-CPU: error: {{.*}} does not support '-Wa,-mcpu=bogus' + +// RUN: %clang -target arm -mcpu=cortex-a8 -Wa,-mcpu=cortex-a15 -c %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-DUP-CPU %s +// CHECK-DUP-CPU: "-target-cpu" "cortex-a15" + +// ================================================================= FPU +// RUN: %clang -target arm-linux-eabi -Wa,-mfpu=neon -c %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-NEON %s +// CHECK-NEON: "-target-feature" "+neon" + +// RUN: %clang -target arm-linux-eabi -Wa,-mfpu=bogus -c %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-BOGUS-FPU %s +// CHECK-BOGUS-FPU: error: {{.*}} does not support '-Wa,-mfpu=bogus' + +// RUN: %clang -target arm-linux-eabi -mfpu=vfpv3 -Wa,-mfpu=neon -c %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-DUP-FPU %s +// CHECK-DUP-FPU: "-target-feature" "+neon" + +// ================================================================= Arch +// Arch validation only for now, in case we're passing to an external asm + +// RUN: %clang -target arm -Wa,-march=armbogusv6 -c %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-BOGUS-ARCH %s +// CHECK-BOGUS-ARCH: error: {{.*}} does not support '-Wa,-march=armbogusv6' + +// RUN: %clang -target arm -march=armv7 -Wa,-march=armv6 -c %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-DUP-ARCH %s + +// ================================================================= HD Div +// RUN: %clang -target arm -Wa,-mhwdiv=arm -c %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARM %s +// CHECK-ARM: "-target-feature" "+hwdiv-arm" +// CHECK-ARM: "-target-feature" "-hwdiv" + +// RUN: %clang -target arm -Wa,-mhwdiv=thumb -c %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-THUMB %s +// CHECK-THUMB: "-target-feature" "-hwdiv-arm" +// CHECK-THUMB: "-target-feature" "+hwdiv" + +// RUN: %clang -target arm -Wa,-mhwdiv=bogus -c %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-BOGUS-HDIV %s +// CHECK-BOGUS-HDIV: error: {{.*}} does not support '-Wa,-mhwdiv=bogus' + +// RUN: %clang -target arm -mhwdiv=arm -Wa,-mhwdiv=thumb -c %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-DUP-HDIV %s +// CHECK-DUP-HDIV: "-target-feature" "-hwdiv-arm" +// CHECK-DUP-HDIV: "-target-feature" "+hwdiv"