Commit df91cc64 authored by Renato Golin's avatar Renato Golin
Browse files

Merging r243352, r243353:

[ARM] Changes to Arch/CPU handling to help with -Wa,-mfpu etc. (nfc)
[ARM] Implement -Wa,-mfpu and friends for assemblers

llvm-svn: 243629
parent e314cfdc
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -305,12 +305,17 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
    // Thumb2 is the default for V7 on Darwin.
    //
    // FIXME: Thumb should just be another -target-feaure, not in the triple.
    StringRef MCPU, MArch;
    if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
      MCPU = A->getValue();
    if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
      MArch = A->getValue();
    std::string CPU = Triple.isOSBinFormatMachO()
      ? tools::arm::getARMCPUForMArch(Args, Triple)
      : tools::arm::getARMTargetCPU(Args, Triple);
      ? tools::arm::getARMCPUForMArch(MArch, Triple)
      : tools::arm::getARMTargetCPU(MCPU, MArch, Triple);
    StringRef Suffix = 
      tools::arm::getLLVMArchSuffixForARM(CPU,
                                          tools::arm::getARMArch(Args, Triple));
                                          tools::arm::getARMArch(MArch, Triple));
    bool ThumbDefault = Suffix.startswith("v6m") || Suffix.startswith("v7m") ||
      Suffix.startswith("v7em") ||
      (Suffix.startswith("v7") && getTriple().isOSBinFormatMachO());
+162 −69
Original line number Diff line number Diff line
@@ -502,11 +502,46 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) {
  }
}

// ARM tools start.

// Get SubArch (vN).
static int getARMSubArchVersionNumber(const llvm::Triple &Triple) {
  llvm::StringRef Arch = Triple.getArchName();
  return llvm::ARMTargetParser::parseArchVersion(Arch);
}

// True if M-profile.
static bool isARMMProfile(const llvm::Triple &Triple) {
  llvm::StringRef Arch = Triple.getArchName();
  unsigned Profile = llvm::ARMTargetParser::parseArchProfile(Arch);
  return Profile == llvm::ARM::PK_M;
}

// Get Arch/CPU from args.
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,
                                const ArgList &Args, StringRef HWDiv,
                                std::vector<const char *> &Features) {
  StringRef HWDiv = A->getValue();
  if (HWDiv == "arm") {
    Features.push_back("+hwdiv-arm");
    Features.push_back("-hwdiv");
@@ -525,23 +560,32 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A,

// Handle -mfpu=.
static void getARMFPUFeatures(const Driver &D, const Arg *A,
                              const ArgList &Args,
                              const ArgList &Args, StringRef FPU,
                              std::vector<const char *> &Features) {
  StringRef FPU = A->getValue();
  unsigned FPUID = llvm::ARMTargetParser::parseFPU(FPU);
  if (!llvm::ARMTargetParser::getFPUFeatures(FPUID, Features))
    D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}

static int getARMSubArchVersionNumber(const llvm::Triple &Triple) {
  llvm::StringRef Arch = Triple.getArchName();
  return llvm::ARMTargetParser::parseArchVersion(Arch);
// 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);
  if (llvm::ARMTargetParser::parseArch(MArch) == llvm::ARM::AK_INVALID)
    D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}

static bool isARMMProfile(const llvm::Triple &Triple) {
  llvm::StringRef Arch = Triple.getArchName();
  unsigned Profile = llvm::ARMTargetParser::parseArchProfile(Arch);
  return Profile == llvm::ARM::PK_M;
// 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);
  if (strcmp(arm::getLLVMArchSuffixForARM(CPU, Arch), "") == 0)
    D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}

// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -641,6 +685,9 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
  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
@@ -661,31 +708,75 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
    // 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, Features);
  if (const Arg *A = Args.getLastArg(options::OPT_mhwdiv_EQ))
    getARMHWDivFeatures(D, A, Args, 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.
  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
    std::string Arch = arm::getARMArch(Args, Triple);
    if (llvm::ARMTargetParser::parseArch(Arch) == llvm::ARM::AK_INVALID)
      D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
  }

  // 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 (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
    std::string CPU = arm::getARMTargetCPU(Args, Triple);
    std::string Arch = arm::getARMArch(Args, Triple);
    if (strcmp(arm::getLLVMArchSuffixForARM(CPU, Arch), "") == 0)
      D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
  // 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 (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 (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
@@ -836,6 +927,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs,
    CmdArgs.push_back("-arm-reserve-r9");
  }
}
// ARM tools end.

/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
/// targeting.
@@ -1463,7 +1555,8 @@ static const char *getX86TargetCPU(const ArgList &Args,
  }
}

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 "";
@@ -1475,9 +1568,11 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
  case llvm::Triple::arm:
  case llvm::Triple::armeb:
  case llvm::Triple::thumb:
  case llvm::Triple::thumbeb:
    return arm::getARMTargetCPU(Args, T);

  case llvm::Triple::thumbeb: {
    StringRef MArch, MCPU;
    getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs);
    return arm::getARMTargetCPU(MCPU, MArch, T);
  }
  case llvm::Triple::mips:
  case llvm::Triple::mipsel:
  case llvm::Triple::mips64:
@@ -2227,6 +2322,9 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
          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;
@@ -2751,8 +2849,7 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D,

  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(
@@ -2908,8 +3005,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
    assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(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) {
@@ -3435,7 +3531,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
  }

  // 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));
@@ -4235,8 +4331,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
      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");
@@ -5271,7 +5366,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,

  // 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));
@@ -5776,16 +5871,12 @@ void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
// Hexagon tools end.

const std::string arm::getARMArch(const ArgList &Args,
                                  const llvm::Triple &Triple) {
const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) {
  std::string MArch;
  if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
    // Otherwise, if we have -march= choose the base CPU for that arch.
    MArch = A->getValue();
  } else {
    // Otherwise, use the Arch from the triple.
  if (!Arch.empty())
    MArch = Arch;
  else
    MArch = Triple.getArchName();
  }
  MArch = StringRef(MArch).lower();

  // Handle -march=native.
@@ -5806,9 +5897,8 @@ const std::string arm::getARMArch(const ArgList &Args,
  return MArch;
}
/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting.
const char *arm::getARMCPUForMArch(const ArgList &Args,
                                   const llvm::Triple &Triple) {
  std::string MArch = getARMArch(Args, 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.
  if (MArch.empty())
@@ -5824,12 +5914,12 @@ const char *arm::getARMCPUForMArch(const ArgList &Args,
}

/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
std::string arm::getARMTargetCPU(const ArgList &Args,
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.
  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
    std::string MCPU = StringRef(A->getValue()).lower();
  if (!CPU.empty()) {
    std::string MCPU = StringRef(CPU).lower();
    // Handle -mcpu=native.
    if (MCPU == "native")
      return llvm::sys::getHostCPUName();
@@ -5837,7 +5927,7 @@ std::string arm::getARMTargetCPU(const ArgList &Args,
      return MCPU;
  }

  return getARMCPUForMArch(Args, Triple);
  return getARMCPUForMArch(Arch, Triple);
}

/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
@@ -7336,8 +7426,11 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
  case llvm::Triple::armeb:
  case llvm::Triple::thumb:
  case llvm::Triple::thumbeb: {
    std::string MArch = arm::getARMTargetCPU(Args, getToolChain().getTriple());
    CmdArgs.push_back(Args.MakeArgString("-mcpu=" + MArch));
    StringRef MArch, MCPU;
    getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true);
    std::string Arch =
        arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple());
    CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch));
    break;
  }

+3 −3
Original line number Diff line number Diff line
@@ -231,11 +231,11 @@ public:
} // end namespace hexagon.

namespace arm {
  std::string getARMTargetCPU(const llvm::opt::ArgList &Args,
  std::string getARMTargetCPU(StringRef CPU, StringRef Arch,
                              const llvm::Triple &Triple);
  const std::string getARMArch(const llvm::opt::ArgList &Args,
  const std::string getARMArch(StringRef Arch,
                               const llvm::Triple &Triple);
  const char* getARMCPUForMArch(const llvm::opt::ArgList &Args,
  const char* getARMCPUForMArch(StringRef Arch,
                                const llvm::Triple &Triple);
  const char* getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch);

+64 −0
Original line number Diff line number Diff line
// 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"