diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 55 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 3 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 203 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 30 |
4 files changed, 282 insertions, 9 deletions
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 89dd06948ba..b7f70b8aa5c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -33,6 +33,7 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Operator.h" @@ -87,6 +88,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) FMF.setAllowReassoc(); } Builder.setFastMathFlags(FMF); + SetFPModel(); } CodeGenFunction::~CodeGenFunction() { @@ -102,6 +104,59 @@ CodeGenFunction::~CodeGenFunction() { CGM.getOpenMPRuntime().functionFinished(*this); } +// Map the LangOption for rounding mode into +// the corresponding enum in the IR. +static llvm::ConstrainedFPIntrinsic::RoundingMode ToConstrainedRoundingMD( + LangOptions::FPRoundingModeKind Kind) { + + switch (Kind) { + case LangOptions::FPR_ToNearest: + return llvm::ConstrainedFPIntrinsic::rmToNearest; + case LangOptions::FPR_Downward: + return llvm::ConstrainedFPIntrinsic::rmDownward; + case LangOptions::FPR_Upward: + return llvm::ConstrainedFPIntrinsic::rmUpward; + case LangOptions::FPR_TowardZero: + return llvm::ConstrainedFPIntrinsic::rmTowardZero; + case LangOptions::FPR_Dynamic: + return llvm::ConstrainedFPIntrinsic::rmDynamic; + } + llvm_unreachable("Unsupported FP RoundingMode"); +} + +// Map the LangOption for exception behavior into +// the corresponding enum in the IR. +static llvm::ConstrainedFPIntrinsic::ExceptionBehavior ToConstrainedExceptMD( + LangOptions::FPExceptionModeKind Kind) { + + switch (Kind) { + case LangOptions::FPE_Ignore: + return llvm::ConstrainedFPIntrinsic::ebIgnore; + case LangOptions::FPE_MayTrap: + return llvm::ConstrainedFPIntrinsic::ebMayTrap; + case LangOptions::FPE_Strict: + return llvm::ConstrainedFPIntrinsic::ebStrict; + } + llvm_unreachable("Unsupported FP Exception Behavior"); +} + +void CodeGenFunction::SetFPModel() { + auto fpRoundingMode = ToConstrainedRoundingMD( + getLangOpts().getFPRoundingMode()); + auto fpExceptionBehavior = ToConstrainedExceptMD( + getLangOpts().getFPExceptionMode()); + + if (fpExceptionBehavior == llvm::ConstrainedFPIntrinsic::ebIgnore && + fpRoundingMode == llvm::ConstrainedFPIntrinsic::rmToNearest) + // Constrained intrinsics are not used. + ; + else { + Builder.setIsFPConstrained(true); + Builder.setDefaultConstrainedRounding(fpRoundingMode); + Builder.setDefaultConstrainedExcept(fpExceptionBehavior); + } +} + CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, LValueBaseInfo *BaseInfo, TBAAAccessInfo *TBAAInfo) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 5c3d1764fad..b05475a3000 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4156,6 +4156,9 @@ public: /// point operation, expressed as the maximum relative error in ulp. void SetFPAccuracy(llvm::Value *Val, float Accuracy); + /// SetFPModel - Control floating point behavior via fp-model settings. + void SetFPModel(); + private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); void EmitReturnOfRValue(RValue RV, QualType Ty); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6f3f7bfe61f..17cb4816e61 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2234,9 +2234,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, bool AssociativeMath = false; bool ReciprocalMath = false; bool SignedZeros = true; - bool TrappingMath = true; + bool TrappingMath = false; // Implemented via -ffp-exception-behavior + bool TrappingMathPresent = false; // Is trapping-math in args, and not + // overriden by ffp-exception-behavior? + bool RoundingFPMath = false; + bool RoundingMathPresent = false; // Is rounding-math in args? + // -ffp-model values: strict, fast, precise + StringRef FPModel = ""; + // -ffp-exception-behavior options: strict, maytrap, ignore + StringRef FPExceptionBehavior = ""; StringRef DenormalFPMath = ""; StringRef FPContract = ""; + bool StrictFPModel = false; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2244,7 +2253,82 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, } for (const Arg *A : Args) { - switch (A->getOption().getID()) { + auto optID = A->getOption().getID(); + bool PreciseFPModel = false; + switch (optID) { + default: + break; + case options::OPT_ffp_model_EQ: { + StringRef Val = A->getValue(); + if (OFastEnabled && !Val.equals("fast")) { + // Only -ffp-model=fast is compatible with OFast, ignore. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-model=" + Val) + << "-Ofast"; + break; + } + StrictFPModel = false; + PreciseFPModel = true; + // ffp-model= is a Driver option, it is entirely rewritten into more + // granular options before being passed into cc1. + // Use the gcc option in the switch below. + if (!FPModel.empty() && !FPModel.equals(Val)) { + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-model=" + FPModel) + << Args.MakeArgString("-ffp-model=" + Val); + FPContract = ""; + } + if (Val.equals("fast")) { + if (!FPContract.empty() && !FPContract.equals("fast")) + // FPContract has already been set to something else + // so warn about the override. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-contract=" + FPContract) + << "-ffp-contract=fast"; + optID = options::OPT_ffast_math; + FPModel = Val; + FPContract = "fast"; + } else if (Val.equals("precise")) { + if (!FPContract.empty() && !FPContract.equals("fast")) + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-contract=" + FPContract) + << "-ffp-contract=fast"; + optID = options::OPT_ffp_contract; + FPModel = Val; + FPContract = "fast"; + PreciseFPModel = true; + } else if (Val.equals("strict")) { + StrictFPModel = true; + if (!FPContract.empty() && !FPContract.equals("strict")) + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-contract=" + FPContract) + << "-ffp-contract=strict"; + optID = options::OPT_frounding_math; + FPExceptionBehavior = "strict"; + FPModel = Val; + // -ffp-model=strict also enables fno-fast-math + HonorINFs = true; + HonorNaNs = true; + // Turning on -ffast-math (with either flag) removes the need for + // MathErrno. However, turning *off* -ffast-math merely restores the + // toolchain default (which may be false). + MathErrno = TC.IsMathErrnoDefault(); + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + TrappingMath = true; + RoundingFPMath = true; + // -fno_fast_math restores default denormal and fpcontract handling + DenormalFPMath = ""; + FPContract = ""; + } else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + } + + switch (optID) { // If this isn't an FP option skip the claim below default: continue; @@ -2261,20 +2345,72 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; case options::OPT_fsigned_zeros: SignedZeros = true; break; case options::OPT_fno_signed_zeros: SignedZeros = false; break; - case options::OPT_ftrapping_math: TrappingMath = true; break; - case options::OPT_fno_trapping_math: TrappingMath = false; break; + case options::OPT_ftrapping_math: + TrappingMath = true; + TrappingMathPresent = true; + FPExceptionBehavior = "strict"; + break; + case options::OPT_fno_trapping_math: + TrappingMath = false; + TrappingMathPresent = true; + FPExceptionBehavior = "ignore"; + break; + case options::OPT_frounding_math: + // The default setting for frounding-math is True and ffast-math + // sets fno-rounding-math, but we only want to use constrained + // floating point intrinsics if the option is specifically requested. + RoundingFPMath = true; + RoundingMathPresent = true; + break; + case options::OPT_fno_rounding_math: + RoundingFPMath = false; + RoundingMathPresent = false; + break; case options::OPT_fdenormal_fp_math_EQ: DenormalFPMath = A->getValue(); break; - // Validate and pass through -fp-contract option. + // Validate and pass through -ffp-contract option. case options::OPT_ffp_contract: { StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") + if (PreciseFPModel) { + // -ffp-model=precise enables ffp-contract=fast as a side effect + // the FPContract value has already been set to a string literal + // and the Val string isn't a pertinent value. + ; + } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) FPContract = Val; else D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + + // Validate and pass through -ffp-model option. + case options::OPT_ffp_model_EQ: + // This should only occur in the error case + // since the optID has been replaced by a more granular + // floating point option. + break; + + // Validate and pass through -ffp-exception-behavior option. + case options::OPT_ffp_exception_behavior_EQ: { + StringRef Val = A->getValue(); + if (!TrappingMathPresent && !FPExceptionBehavior.empty() && + !FPExceptionBehavior.equals(Val)) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << Args.MakeArgString("-ffp-exception-behavior=" + Val); + TrappingMathPresent = false; + if (Val.equals("ignore") || Val.equals("maytrap")) + FPExceptionBehavior = Val; + else if (Val.equals("strict")) { + FPExceptionBehavior = Val; + TrappingMath = TrappingMathPresent = true; + } else + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; break; } @@ -2293,12 +2429,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = true; SignedZeros = false; TrappingMath = false; + FPExceptionBehavior = ""; break; case options::OPT_fno_unsafe_math_optimizations: AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; TrappingMath = true; + FPExceptionBehavior = "strict"; // -fno_unsafe_math_optimizations restores default denormal handling DenormalFPMath = ""; break; @@ -2316,6 +2454,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = true; SignedZeros = false; TrappingMath = false; + RoundingFPMath = false; // If fast-math is set then set the fp-contract mode to fast. FPContract = "fast"; break; @@ -2329,12 +2468,31 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; - TrappingMath = true; + TrappingMath = false; + RoundingFPMath = false; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = ""; FPContract = ""; break; } + if (StrictFPModel) { + // If -ffp-model=strict has been specified on command line but + // subsequent options conflict then emit warning diagnostic. + if (HonorINFs && HonorNaNs && + !AssociativeMath && !ReciprocalMath && + SignedZeros && TrappingMath && RoundingFPMath && + DenormalFPMath.empty() && FPContract.empty()) + // OK: Current Arg doesn't conflict with -ffp-model=strict + ; + else { + StrictFPModel = false; + FPModel = ""; + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=strict" << + ((A->getNumValues() == 0) ? A->getSpelling() + : Args.MakeArgString(A->getSpelling() + A->getValue())); + } + } // If we handled this option claim it A->claim(); @@ -2362,7 +2520,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (ReciprocalMath) CmdArgs.push_back("-freciprocal-math"); - if (!TrappingMath) + if (TrappingMath) { + // FP Exception Behavior is also set to strict + assert(FPExceptionBehavior.equals("strict")); + CmdArgs.push_back("-ftrapping-math"); + } else if (TrappingMathPresent) CmdArgs.push_back("-fno-trapping-math"); if (!DenormalFPMath.empty()) @@ -2372,14 +2534,37 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!FPContract.empty()) CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + if (!RoundingFPMath) + CmdArgs.push_back(Args.MakeArgString("-fno-rounding-math")); + + if (RoundingFPMath && RoundingMathPresent) + CmdArgs.push_back(Args.MakeArgString("-frounding-math")); + + if (!FPExceptionBehavior.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the // individual features enabled by -ffast-math instead of the option itself as // that's consistent with gcc's behaviour. if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && - ReciprocalMath && !SignedZeros && !TrappingMath) + ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) { CmdArgs.push_back("-ffast-math"); + if (FPModel.equals("fast")) { + if (FPContract.equals("fast")) + // All set, do nothing. + ; + else if (FPContract.empty()) + // Enable -ffp-contract=fast + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); + else + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=fast" + << Args.MakeArgString("-ffp-contract=" + FPContract); + } + } // Handle __FINITE_MATH_ONLY__ similarly. if (!HonorINFs && !HonorNaNs) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 46a7e39770a..195a29d7118 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3129,6 +3129,36 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } + if (Args.hasArg(OPT_frounding_math)) { + Opts.setFPRoundingMode(LangOptions::FPR_Dynamic); + } + + if (Args.hasArg(OPT_fno_rounding_math)) { + Opts.setFPRoundingMode(LangOptions::FPR_ToNearest); + } + + if (Args.hasArg(OPT_ftrapping_math)) { + Opts.setFPExceptionMode(LangOptions::FPE_Strict); + } + + if (Args.hasArg(OPT_fno_trapping_math)) { + Opts.setFPExceptionMode(LangOptions::FPE_Ignore); + } + + LangOptions::FPExceptionModeKind FPEB = LangOptions::FPE_Ignore; + if (Arg *A = Args.getLastArg(OPT_ffp_exception_behavior_EQ)) { + StringRef Val = A->getValue(); + if (Val.equals("ignore")) + FPEB = LangOptions::FPE_Ignore; + else if (Val.equals("maytrap")) + FPEB = LangOptions::FPE_MayTrap; + else if (Val.equals("strict")) + FPEB = LangOptions::FPE_Strict; + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + Opts.setFPExceptionMode(FPEB); + } + Opts.RetainCommentsFromSystemHeaders = Args.hasArg(OPT_fretain_comments_from_system_headers); |