// Decode ARM features from string like +[no]featureA+[no]featureB+...
static bool DecodeARMFeatures(const Driver &D, StringRef text,
+ StringRef CPU, llvm::ARM::ArchKind ArchKind,
std::vector<StringRef> &Features) {
SmallVector<StringRef, 8> Split;
text.split(Split, StringRef("+"), -1, false);
for (StringRef Feature : Split) {
- StringRef FeatureName = llvm::ARM::getArchExtFeature(Feature);
- if (!FeatureName.empty())
- Features.push_back(FeatureName);
- else
+ if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features))
return false;
}
return true;
// 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,
+ llvm::StringRef ArchName, llvm::StringRef CPUName,
std::vector<StringRef> &Features,
const llvm::Triple &Triple) {
std::pair<StringRef, StringRef> Split = ArchName.split("+");
std::string MArch = arm::getARMArch(ArchName, Triple);
- if (llvm::ARM::parseArch(MArch) == llvm::ARM::ArchKind::INVALID ||
- (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
+ llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch);
+ if (ArchKind == llvm::ARM::ArchKind::INVALID ||
+ (Split.second.size() && !DecodeARMFeatures(
+ D, Split.second, CPUName, ArchKind, Features)))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
std::pair<StringRef, StringRef> Split = CPUName.split("+");
std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
- if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() ||
- (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
+ llvm::ARM::ArchKind ArchKind =
+ arm::getLLVMArchKindForARM(CPU, ArchName, Triple);
+ if (ArchKind == llvm::ARM::ArchKind::INVALID ||
+ (Split.second.size() && !DecodeARMFeatures(
+ D, Split.second, CPU, ArchKind, Features)))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
if (ThreadPointer == arm::ReadTPMode::Cp15)
Features.push_back("+read-tp-hard");
- // Check -march. ClangAs gives preference to -Wa,-march=.
const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ);
+ const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_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, Features, 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, Features, Triple);
- }
+ StringRef CPUName;
// 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)
} else if (CPUArg)
CPUName = CPUArg->getValue();
+ // Check -march. ClangAs gives preference to -Wa,-march=.
+ 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, CPUName, Features, 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, CPUName, Features, Triple);
+ }
+
// Add CPU features for generic CPUs
if (CPUName == "native") {
llvm::StringMap<bool> HostFeatures;
return getARMCPUForMArch(Arch, Triple);
}
-/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
-/// CPU (or Arch, if CPU is generic).
-// FIXME: This is redundant with -mcpu, why does LLVM use this.
-StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
- const llvm::Triple &Triple) {
+/// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a
+/// particular CPU (or Arch, if CPU is generic). This is needed to
+/// pass to functions like llvm::ARM::getDefaultFPU which need an
+/// ArchKind as well as a CPU name.
+llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch,
+ const llvm::Triple &Triple) {
llvm::ARM::ArchKind ArchKind;
if (CPU == "generic") {
std::string ARMArch = tools::arm::getARMArch(Arch, Triple);
? llvm::ARM::ArchKind::ARMV7K
: llvm::ARM::parseCPUArch(CPU);
}
+ return ArchKind;
+}
+
+/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
+/// CPU (or Arch, if CPU is generic).
+// FIXME: This is redundant with -mcpu, why does LLVM use this.
+StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
+ const llvm::Triple &Triple) {
+ llvm::ARM::ArchKind ArchKind = getLLVMArchKindForARM(CPU, Arch, Triple);
if (ArchKind == llvm::ARM::ArchKind::INVALID)
return "";
return llvm::ARM::getSubArch(ArchKind);
// RUN: FileCheck --check-prefix=CHECK-DSP < %t %s
// CHECK-DSP: "-target-feature" "+dsp"
+// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+fp -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-FP < %t %s
+// CHECK-FP: "-target-feature" "+fp-armv8"
+// CHECK-FP-NOT: "-target-feature" "+fp64"
+// CHECK-FP-NOT: "-target-feature" "+d32"
+// CHECK-FP: "-target-feature" "+fullfp16"
+
+// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+nofp -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NOFP < %t %s
+// CHECK-NOFP: "-target-feature" "-vfp2" "-target-feature" "-vfp3" "-target-feature" "-fp16" "-target-feature" "-vfp4" "-target-feature" "-fp-armv8" "-target-feature" "-fp64" "-target-feature" "-d32" "-target-feature" "-neon" "-target-feature" "-crypto"
+
+// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+fp.dp -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-FPDP < %t %s
+// CHECK-FPDP: "-target-feature" "+fp-armv8"
+// CHECK-FPDP: "-target-feature" "+fullfp16"
+// CHECK-FPDP: "-target-feature" "+fp64"
+// CHECK-FPDP-NOT: "-target-feature" "+d32"
+
+// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+nofp.dp -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NOFPDP < %t %s
+// CHECK-NOFPDP: "-target-feature" "-fp64"
+
// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+mve -### %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-MVE < %t %s
// CHECK-MVE: "-target-feature" "+mve"
+// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+nomve -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NOMVE < %t %s
+// CHECK-NOMVE: "-target-feature" "-mve"
+
// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+mve.fp -### %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-MVEFP < %t %s
// CHECK-MVEFP: "-target-feature" "+mve.fp"
// CHECK-MVEFP-NOT: "-target-feature" "+fp64"
+// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+nomve.fp -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NOMVEFP < %t %s
+// CHECK-NOMVEFP: "-target-feature" "-mve.fp"
+
+// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main+mve.fp+fp.dp -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-MVEFP_DP < %t %s
+// CHECK-MVEFP_DP: "-target-feature" "+mve.fp"
+// CHECK-MVEFP_DP: "-target-feature" "+fp64"
+
double foo (double a) { return a; }
# RUN: FileCheck --check-prefix=ERROR-V81M < %t %s
# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+dsp -o /dev/null %s 2>%t
# RUN: FileCheck --check-prefix=ERROR-V81M_DSP < %t %s
+# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+fp -o /dev/null %s 2>%t
+# RUN: FileCheck --check-prefix=ERROR-V81M_FP < %t %s
+# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+nofp -o /dev/null %s 2>%t
+# RUN: FileCheck --check-prefix=ERROR-V81M_FP < %t %s
+# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+fp.dp -o /dev/null %s 2>%t
+# RUN: FileCheck --check-prefix=ERROR-V81M_FPDP < %t %s
+# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+nofp.dp -o /dev/null %s 2>%t
+# RUN: FileCheck --check-prefix=ERROR-V81M_FPDP < %t %s
# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+mve -o /dev/null %s 2>%t
# RUN: FileCheck --check-prefix=ERROR-V81M_MVE < %t %s
+# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+nomve -o /dev/null %s 2>%t
+# RUN: FileCheck --check-prefix=ERROR-V81M_MVE < %t %s
+# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+mve+fp -o /dev/null %s 2>%t
+# RUN: FileCheck --check-prefix=ERROR-V81M_MVE_FP < %t %s
# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+mve.fp -o /dev/null %s 2>%t
# RUN: FileCheck --check-prefix=ERROR-V81M_MVEFP < %t %s
+# RUN: not %clang -c -target arm-none-none-eabi -march=armv8.1-m.main+nomve.fp -o /dev/null %s 2>%t
+# RUN: FileCheck --check-prefix=ERROR-V81M_MVEFP < %t %s
.syntax unified
.thumb
# ERROR-V8M: :[[@LINE-1]]:1: error
# ERROR-V81M: :[[@LINE-2]]:1: error
# ERROR-V81M_DSP: :[[@LINE-3]]:1: error
-# ERROR-V81M_MVE: :[[@LINE-4]]:1: error
-# ERROR-V81M_MVEFP: :[[@LINE-5]]:1: error
+# ERROR-V81M_FP: :[[@LINE-4]]:1: error
+# ERROR-V81M_MVE: :[[@LINE-5]]:1: error
+# ERROR-V81M_MVE_FP: :[[@LINE-6]]:1: error
+# ERROR-V81M_MVEFP: :[[@LINE-7]]:1: error
asrl r0, r1, r2
# ERROR-V8M: :[[@LINE-1]]:1: error
# ERROR-V81M: :[[@LINE-2]]:1: error
# ERROR-V81M_DSP: :[[@LINE-3]]:1: error
+# ERROR-V81M_FP: :[[@LINE-4]]:1: error
+# ERROR-V81M_FPDP: :[[@LINE-5]]:1: error
vcadd.i8 q0, q1, q2, #90
# ERROR-V8M: :[[@LINE-1]]:1: error
# ERROR-V81M: :[[@LINE-2]]:1: error
# ERROR-V81M_DSP: :[[@LINE-3]]:1: error
+# ERROR-V81M_FP: :[[@LINE-4]]:1: error
+# ERROR-V81M_FPDP: :[[@LINE-5]]:1: error