//@}
} CPU;
+ enum FPMathKind {
+ FP_Default,
+ FP_SSE,
+ FP_387
+ } FPMath;
+
public:
X86TargetInfo(const llvm::Triple &Triple)
: TargetInfo(Triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
HasRDRND(false), HasBMI(false), HasBMI2(false), HasPOPCNT(false),
HasRTM(false), HasPRFCHW(false), HasRDSEED(false), HasFMA(false),
HasF16C(false), HasAVX512CD(false), HasAVX512ER(false),
- HasAVX512PF(false), CPU(CK_Generic) {
+ HasAVX512PF(false), CPU(CK_Generic), FPMath(FP_Default) {
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
bool Enabled) const;
virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
virtual bool hasFeature(StringRef Feature) const;
- virtual void HandleTargetFeatures(std::vector<std::string> &Features);
+ virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags);
virtual const char* getABI() const {
if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
return "avx";
llvm_unreachable("Unhandled CPU kind");
}
+ virtual bool setFPMath(StringRef Name);
+
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
// We accept all non-ARM calling conventions
return (CC == CC_X86ThisCall ||
}
};
+bool X86TargetInfo::setFPMath(StringRef Name) {
+ if (Name == "387") {
+ FPMath = FP_387;
+ return true;
+ }
+ if (Name == "sse") {
+ FPMath = FP_SSE;
+ return true;
+ }
+ return false;
+}
+
void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
// FIXME: This *really* should not be here.
/// HandleTargetOptions - Perform initialization based on the user
/// configured set of features.
-void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
+bool X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
// Remember the maximum enabled sselevel.
for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
// Ignore disabled features.
XOPLevel = std::max(XOPLevel, XLevel);
}
+ // LLVM doesn't have a separate switch for fpmath, so only accept it if it
+ // matches the selected sse level.
+ if (FPMath == FP_SSE && SSELevel < SSE1) {
+ Diags.Report(diag::err_target_unsupported_fpmath) << "sse";
+ return false;
+ } else if (FPMath == FP_387 && SSELevel >= SSE1) {
+ Diags.Report(diag::err_target_unsupported_fpmath) << "387";
+ return false;
+ }
+
// Don't tell the backend if we're turning off mmx; it will end up disabling
// SSE, which we don't want.
std::vector<std::string>::iterator it;
it = std::find(Features.begin(), Features.end(), "-mmx");
if (it != Features.end())
Features.erase(it);
+ return true;
}
/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro
return Feature == "aarch64" || (Feature == "neon" && FPU == NeonMode);
}
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
FPU = FPUMode;
for (unsigned i = 0, e = Features.size(); i != e; ++i) {
if (Features[i] == "+neon")
FPU = NeonMode;
}
+ return true;
}
virtual void getGCCRegNames(const char *const *&Names,
std::string ABI, CPU;
+ enum {
+ FP_Default,
+ FP_VFP,
+ FP_Neon
+ } FPMath;
+
unsigned FPU : 4;
unsigned IsAAPCS : 1;
public:
ARMTargetInfo(const llvm::Triple &Triple)
: TargetInfo(Triple), ABI("aapcs-linux"), CPU("arm1136j-s"),
- IsAAPCS(true) {
+ FPMath(FP_Default), IsAAPCS(true) {
BigEndian = false;
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
}
}
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
FPU = 0;
SoftFloat = SoftFloatABI = false;
for (unsigned i = 0, e = Features.size(); i != e; ++i) {
FPU |= NeonFPU;
}
+ if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
+ Diags.Report(diag::err_target_unsupported_fpmath) << "neon";
+ return false;
+ }
+
+ if (FPMath == FP_Neon)
+ Features.push_back("+neonfp");
+ else if (FPMath == FP_VFP)
+ Features.push_back("-neonfp");
+
// Remove front-end specific options which the backend handles differently.
std::vector<std::string>::iterator it;
it = std::find(Features.begin(), Features.end(), "+soft-float");
it = std::find(Features.begin(), Features.end(), "+soft-float-abi");
if (it != Features.end())
Features.erase(it);
+ return true;
}
virtual bool hasFeature(StringRef Feature) const {
CPU = Name;
return true;
}
+ virtual bool setFPMath(StringRef Name);
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
}
};
+bool ARMTargetInfo::setFPMath(StringRef Name) {
+ if (Name == "neon") {
+ FPMath = FP_Neon;
+ return true;
+ } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" ||
+ Name == "vfp4") {
+ FPMath = FP_VFP;
+ return true;
+ }
+ return false;
+}
+
const char * const ARMTargetInfo::GCCRegNames[] = {
// Integer registers
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
public:
SparcTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {}
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
SoftFloat = false;
for (unsigned i = 0, e = Features.size(); i != e; ++i)
if (Features[i] == "+soft-float")
SoftFloat = true;
+ return true;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
return "";
}
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
IsMips16 = false;
IsMicromips = false;
IsSingleFloat = false;
std::find(Features.begin(), Features.end(), "+soft-float");
if (it != Features.end())
Features.erase(it);
+
+ return true;
}
virtual int getEHDataRegisterNumber(unsigned RegNo) const {
return 0;
}
+ // Set the fp math unit.
+ if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) {
+ Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath;
+ return 0;
+ }
+
// Compute the default target features, we need the target to handle this
// because features may have dependencies on one another.
llvm::StringMap<bool> Features;
for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it)
Opts->Features.push_back((it->second ? "+" : "-") + it->first().str());
- Target->HandleTargetFeatures(Opts->Features);
+ if (!Target->HandleTargetFeatures(Opts->Features, Diags))
+ return 0;
return Target.take();
}
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
-// Handle -mfpmath=.
-static void getFPMathFeatures(const Driver &D, const Arg *A,
- const ArgList &Args,
- std::vector<const char *> &Features,
- StringRef CPU) {
- StringRef FPMath = A->getValue();
-
- // Set the target features based on the FPMath.
- if (FPMath == "neon") {
- Features.push_back("+neonfp");
-
- if (CPU != "cortex-a5" && CPU != "cortex-a7" &&
- CPU != "cortex-a8" && CPU != "cortex-a9" &&
- CPU != "cortex-a9-mp" && CPU != "cortex-a15")
- D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU;
-
- } else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" ||
- FPMath == "vfp4") {
- Features.push_back("-neonfp");
- // FIXME: Add warnings when disabling a feature not present for a given CPU.
- } else
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
// Select the float ABI as determined by -msoft-float, -mhard-float, and
// -mfloat-abi=.
static StringRef getARMFloatABI(const Driver &D,
if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
getFPUFeatures(D, A, Args, Features);
- // Honor -mfpmath=.
- if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ))
- getFPMathFeatures(D, A, Args, Features, getARMTargetCPU(Args, Triple));
-
// Setting -msoft-float effectively disables NEON because of the GCC
// implementation, although the same isn't true of VFP or VFP3.
if (FloatABI == "soft")
CmdArgs.push_back(Args.MakeArgString(CPU));
}
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
+ CmdArgs.push_back("-mfpmath");
+ CmdArgs.push_back(A->getValue());
+ }
+
// Add the target features
getTargetFeatures(D, ETriple, Args, CmdArgs);
--- /dev/null
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse -mfpmath 387 %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse -mfpmath sse %s
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \
+// RUN: -mfpmath xyz %s 2>&1 | FileCheck --check-prefix=CHECK-XYZ %s
+// CHECK-XYZ: error: unknown FP unit 'xyz'
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \
+// RUN: -mfpmath 387 %s 2>&1 | FileCheck --check-prefix=CHECK-NO-387 %s
+// CHECK-NO-387: error: the '387' unit is not supported with this instruction set
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature -sse \
+// RUN: -mfpmath sse %s 2>&1 | FileCheck --check-prefix=CHECK-NO-SSE %s
+// CHECK-NO-SSE: error: the 'sse' unit is not supported with this instruction set
+
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp2 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp3 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp4 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \
+// RUN: -mfpmath neon %s
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -mfpmath foo %s 2>&1 \
+// RUN: FileCheck --check-prefix=CHECK-FOO %s
+// CHECK-FOO: unknown FP unit 'foo'
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu arm1136j-s \
+// RUN: -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \
+// RUN: -target-feature -neon -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s
+
+// CHECK-NO-NEON: error: the 'neon' unit is not supported with this instruction set