diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bc3acf165f075..6e4009deaf874 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -264,6 +264,16 @@ New Compiler Flags * ``-fopenacc`` was added as a part of the effort to support OpenACC in clang. +* ``-fcx-limited-range`` enables the naive mathematical formulas for complex + division and multiplication with no NaN checking of results. The default is + ``-fno-cx-limited-range``, but this option is enabled by ``-ffast-math``. + +* ``-fcx-fortran-rules`` enables the naive mathematical formulas for complex + multiplication and enables application of Smith's algorithm for complex + division. See SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 + (1962). The default is ``-fno-cx-fortran-rules``. + + Deprecated Compiler Flags ------------------------- @@ -1002,6 +1012,9 @@ Floating Point Support in Clang ``__builtin_exp10f128`` builtins. - Add ``__builtin_iszero``, ``__builtin_issignaling`` and ``__builtin_issubnormal``. +- Add support for C99's ``#pragma STDC CX_LIMITED_RANGE`` feature. This + enables the naive mathematical formulas for complex multiplication and + division, which are faster but do not correctly handle overflow and infinities. AST Matchers ------------ diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index f1b344ef5109b..7c30570437e8b 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1468,6 +1468,7 @@ floating point semantic models: precise (the default), strict, and fast. With the exception of ``-ffp-contract=fast``, using any of the options below to disable any of the individual optimizations in ``-ffast-math`` will cause ``__FAST_MATH__`` to no longer be set. + ``-ffast-math`` enables ``-fcx-limited-range``. This option implies: @@ -1834,6 +1835,20 @@ floating point semantic models: precise (the default), strict, and fast. * ``16`` - Forces ``_Float16`` operations to be emitted without using excess precision arithmetic. +.. option:: -fcx-limited-range: + + This option enables the naive mathematical formulas for complex division and + multiplication with no NaN checking of results. The default is + ``-fno-cx-limited-range``, but this option is enabled by the ``-ffast-math`` + option. + +.. option:: -fcx-fortran-rules: + + This option enables the naive mathematical formulas for complex + multiplication and enables application of Smith's algorithm for complex + division. See SMITH, R. L. Algorithm 116: Complex division. Commun. + ACM 5, 8 (1962). The default is ``-fno-cx-fortran-rules``. + .. _floating-point-environment: Accessing the floating point environment diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def index 5b923a1944e50..79f04c89c9fed 100644 --- a/clang/include/clang/Basic/FPOptions.def +++ b/clang/include/clang/Basic/FPOptions.def @@ -28,4 +28,5 @@ OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc) OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod) OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, Float16ExcessPrecision) OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision) +OPTION(ComplexRange, LangOptions::ComplexRangeKind, 2, MathErrno) #undef OPTION diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index df1eff8cbcc9f..7473e00a7bd86 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -104,6 +104,7 @@ FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) FEATURE(swiftasynccc, PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) == clang::TargetInfo::CCCR_OK) +FEATURE(pragma_stdc_cx_limited_range, true) // Objective-C features FEATURE(objc_arr, LangOpts.ObjCAutoRefCount) // FIXME: REMOVE? FEATURE(objc_arc, LangOpts.ObjCAutoRefCount) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index c3d5399905a3f..152d9f65f86db 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -220,6 +220,8 @@ BENIGN_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization wit BENIGN_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal") BENIGN_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation") +ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 2, CX_Full, "Enable use of range reduction for complex arithmetics.") + BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars") BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index c4979b9a38c0c..9f986fce2d441 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -392,6 +392,8 @@ class LangOptions : public LangOptionsBase { IncompleteOnly = 3, }; + enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran }; + public: /// The used language standard. LangStandard::Kind LangStd; @@ -741,6 +743,7 @@ class FPOptions { setAllowFEnvAccess(true); else setAllowFEnvAccess(LangOptions::FPM_Off); + setComplexRange(LO.getComplexRange()); } bool allowFPContractWithinStatement() const { diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 5f9915d210221..3f0e1e1a7d45a 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -911,6 +911,11 @@ PRAGMA_ANNOTATION(pragma_fenv_access_ms) // handles them. PRAGMA_ANNOTATION(pragma_fenv_round) +// Annotation for #pragma STDC CX_LIMITED_RANGE +// The lexer produces these so that they only take effect when the parser +// handles them. +PRAGMA_ANNOTATION(pragma_cx_limited_range) + // Annotation for #pragma float_control // The lexer produces these so that they only take effect when the parser // handles them. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index cf969cb0b318a..25c76cf2ad2c8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1010,6 +1010,30 @@ defm offload_uniform_block : BoolFOption<"offload-uniform-block", NegFlag, BothFlags<[], [ClangOption], " that kernels are launched with uniform block sizes (default true for CUDA/HIP and false otherwise)">>; +def fcx_limited_range : Joined<["-"], "fcx-limited-range">, + Group, Visibility<[ClangOption, CC1Option]>, + HelpText<"Basic algebraic expansions of complex arithmetic operations " + "involving are enabled.">; + +def fno_cx_limited_range : Joined<["-"], "fno-cx-limited-range">, + Group, Visibility<[ClangOption, CC1Option]>, + HelpText<"Basic algebraic expansions of complex arithmetic operations " + "involving are disabled.">; + +def fcx_fortran_rules : Joined<["-"], "fcx-fortran-rules">, + Group, Visibility<[ClangOption, CC1Option]>, + HelpText<"Range reduction is enabled for complex arithmetic operations.">; + +def fno_cx_fortran_rules : Joined<["-"], "fno-cx-fortran-rules">, + Group, Visibility<[ClangOption, CC1Option]>, + HelpText<"Range reduction is disabled for complex arithmetic operations.">; + +def complex_range_EQ : Joined<["-"], "complex-range=">, Group, + Visibility<[CC1Option]>, + Values<"full,limited,fortran">, NormalizedValuesScope<"LangOptions">, + NormalizedValues<["CX_Full", "CX_Limited", "CX_Fortran"]>, + MarshallingInfoEnum, "CX_Full">; + // OpenCL-only Options def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group, Visibility<[ClangOption, CC1Option]>, diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 0663498235164..2dbe090bd0932 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -769,6 +769,10 @@ class Parser : public CodeCompletionHandler { /// #pragma STDC FENV_ROUND... void HandlePragmaFEnvRound(); + /// Handle the annotation token produced for + /// #pragma STDC CX_LIMITED_RANGE... + void HandlePragmaCXLimitedRange(); + /// Handle the annotation token produced for /// #pragma float_control void HandlePragmaFloatControl(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f45e0a7d3d52d..1902d098f3c25 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11023,6 +11023,11 @@ class Sema final { /// \#pragma STDC FENV_ACCESS void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled); + /// ActOnPragmaCXLimitedRange - Called on well formed + /// \#pragma STDC CX_LIMITED_RANGE + void ActOnPragmaCXLimitedRange(SourceLocation Loc, + LangOptions::ComplexRangeKind Range); + /// Called on well formed '\#pragma clang fp' that has option 'exceptions'. void ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind); diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index f3cbd1d0451eb..e532794b71bdb 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -275,6 +275,10 @@ class ComplexExprEmitter ComplexPairTy EmitBinSub(const BinOpInfo &Op); ComplexPairTy EmitBinMul(const BinOpInfo &Op); ComplexPairTy EmitBinDiv(const BinOpInfo &Op); + ComplexPairTy EmitAlgebraicDiv(llvm::Value *A, llvm::Value *B, llvm::Value *C, + llvm::Value *D); + ComplexPairTy EmitRangeReductionDiv(llvm::Value *A, llvm::Value *B, + llvm::Value *C, llvm::Value *D); ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName, const BinOpInfo &Op); @@ -781,6 +785,10 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { ResR = Builder.CreateFSub(AC, BD, "mul_r"); ResI = Builder.CreateFAdd(AD, BC, "mul_i"); + if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited || + Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran) + return ComplexPairTy(ResR, ResI); + // Emit the test for the real part becoming NaN and create a branch to // handle it. We test for NaN by comparing the number to itself. Value *IsRNaN = Builder.CreateFCmpUNO(ResR, ResR, "isnan_cmp"); @@ -846,23 +854,139 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { return ComplexPairTy(ResR, ResI); } +ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr, + llvm::Value *LHSi, + llvm::Value *RHSr, + llvm::Value *RHSi) { + // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) + llvm::Value *DSTr, *DSTi; + + llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c + llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d + llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd + + llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c + llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d + llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd + + llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c + llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d + llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad + + DSTr = Builder.CreateFDiv(ACpBD, CCpDD); + DSTi = Builder.CreateFDiv(BCmAD, CCpDD); + return ComplexPairTy(DSTr, DSTi); +} + +// EmitFAbs - Emit a call to @llvm.fabs. +static llvm::Value *EmitllvmFAbs(CodeGenFunction &CGF, llvm::Value *Value) { + llvm::Function *Func = + CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Value->getType()); + llvm::Value *Call = CGF.Builder.CreateCall(Func, Value); + return Call; +} + +// EmitRangeReductionDiv - Implements Smith's algorithm for complex division. +// SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962). +ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr, + llvm::Value *LHSi, + llvm::Value *RHSr, + llvm::Value *RHSi) { + // (a + ib) / (c + id) = (e + if) + llvm::Value *FAbsRHSr = EmitllvmFAbs(CGF, RHSr); // |c| + llvm::Value *FAbsRHSi = EmitllvmFAbs(CGF, RHSi); // |d| + // |c| >= |d| + llvm::Value *IsR = Builder.CreateFCmpUGT(FAbsRHSr, FAbsRHSi, "abs_cmp"); + + llvm::BasicBlock *TrueBB = + CGF.createBasicBlock("abs_rhsr_greater_or_equal_abs_rhsi"); + llvm::BasicBlock *FalseBB = + CGF.createBasicBlock("abs_rhsr_less_than_abs_rhsi"); + llvm::BasicBlock *ContBB = CGF.createBasicBlock("complex_div"); + Builder.CreateCondBr(IsR, TrueBB, FalseBB); + + CGF.EmitBlock(TrueBB); + // abs(c) >= abs(d) + // r = d/c + // tmp = c + rd + // e = (a + br)/tmp + // f = (b - ar)/tmp + llvm::Value *DdC = Builder.CreateFDiv(RHSi, RHSr); // r=d/c + + llvm::Value *RD = Builder.CreateFMul(DdC, RHSi); // rd + llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD); // tmp=c+rd + + llvm::Value *T3 = Builder.CreateFMul(LHSi, DdC); // br + llvm::Value *T4 = Builder.CreateFAdd(LHSr, T3); // a+br + llvm::Value *DSTTr = Builder.CreateFDiv(T4, CpRD); // (a+br)/tmp + + llvm::Value *T5 = Builder.CreateFMul(LHSr, DdC); // ar + llvm::Value *T6 = Builder.CreateFSub(LHSi, T5); // b-ar + llvm::Value *DSTTi = Builder.CreateFDiv(T6, CpRD); // (b-ar)/tmp + Builder.CreateBr(ContBB); + + CGF.EmitBlock(FalseBB); + // abs(c) < abs(d) + // r = c/d + // tmp = d + rc + // e = (ar + b)/tmp + // f = (br - a)/tmp + llvm::Value *CdD = Builder.CreateFDiv(RHSr, RHSi); // r=c/d + + llvm::Value *RC = Builder.CreateFMul(CdD, RHSr); // rc + llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC); // tmp=d+rc + + llvm::Value *T7 = Builder.CreateFMul(LHSr, RC); // ar + llvm::Value *T8 = Builder.CreateFAdd(T7, LHSi); // ar+b + llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC); // (ar+b)/tmp + + llvm::Value *T9 = Builder.CreateFMul(LHSi, CdD); // br + llvm::Value *T10 = Builder.CreateFSub(T9, LHSr); // br-a + llvm::Value *DSTFi = Builder.CreateFDiv(T10, DpRC); // (br-a)/tmp + Builder.CreateBr(ContBB); + + // Phi together the computation paths. + CGF.EmitBlock(ContBB); + llvm::PHINode *VALr = Builder.CreatePHI(DSTTr->getType(), 2); + VALr->addIncoming(DSTTr, TrueBB); + VALr->addIncoming(DSTFr, FalseBB); + llvm::PHINode *VALi = Builder.CreatePHI(DSTTi->getType(), 2); + VALi->addIncoming(DSTTi, TrueBB); + VALi->addIncoming(DSTFi, FalseBB); + return ComplexPairTy(VALr, VALi); +} + // See C11 Annex G.5.1 for the semantics of multiplicative operators on complex // typed values. ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second; llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second; - llvm::Value *DSTr, *DSTi; if (LHSr->getType()->isFloatingPointTy()) { - // If we have a complex operand on the RHS and FastMath is not allowed, we - // delegate to a libcall to handle all of the complexities and minimize - // underflow/overflow cases. When FastMath is allowed we construct the - // divide inline using the same algorithm as for integer operands. - // - // FIXME: We would be able to avoid the libcall in many places if we - // supported imaginary types in addition to complex types. CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures); - if (RHSi && !CGF.getLangOpts().FastMath) { + if (!RHSi) { + assert(LHSi && "Can have at most one non-complex operand!"); + + DSTr = Builder.CreateFDiv(LHSr, RHSr); + DSTi = Builder.CreateFDiv(LHSi, RHSr); + return ComplexPairTy(DSTr, DSTi); + } + llvm::Value *OrigLHSi = LHSi; + if (!LHSi) + LHSi = llvm::Constant::getNullValue(RHSi->getType()); + if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran) + return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi); + else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited) + return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi); + else if (!CGF.getLangOpts().FastMath) { + LHSi = OrigLHSi; + // If we have a complex operand on the RHS and FastMath is not allowed, we + // delegate to a libcall to handle all of the complexities and minimize + // underflow/overflow cases. When FastMath is allowed we construct the + // divide inline using the same algorithm as for integer operands. + // + // FIXME: We would be able to avoid the libcall in many places if we + // supported imaginary types in addition to complex types. BinOpInfo LibCallOp = Op; // If LHS was a real, supply a null imaginary part. if (!LHSi) @@ -884,30 +1008,8 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { case llvm::Type::FP128TyID: return EmitComplexBinOpLibCall("__divtc3", LibCallOp); } - } else if (RHSi) { - if (!LHSi) - LHSi = llvm::Constant::getNullValue(RHSi->getType()); - - // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) - llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c - llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d - llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd - - llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c - llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d - llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd - - llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c - llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d - llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad - - DSTr = Builder.CreateFDiv(ACpBD, CCpDD); - DSTi = Builder.CreateFDiv(BCmAD, CCpDD); } else { - assert(LHSi && "Can have at most one non-complex operand!"); - - DSTr = Builder.CreateFDiv(LHSr, RHSr); - DSTi = Builder.CreateFDiv(LHSi, RHSr); + return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi); } } else { assert(Op.LHS.second && Op.RHS.second && diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index eb26bfade47b7..f95f3227aba7d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2660,6 +2660,35 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } +static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) { + StringRef RangeStr = ""; + switch (Range) { + case LangOptions::ComplexRangeKind::CX_Limited: + return "-fcx-limited-range"; + break; + case LangOptions::ComplexRangeKind::CX_Fortran: + return "-fcx-fortran-rules"; + break; + default: + return RangeStr; + break; + } +} + +static void EmitComplexRangeDiag(const Driver &D, + LangOptions::ComplexRangeKind Range1, + LangOptions::ComplexRangeKind Range2) { + if (Range1 != LangOptions::ComplexRangeKind::CX_Full) + D.Diag(clang::diag::warn_drv_overriding_option) + << EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2); +} + +static std::string RenderComplexRangeOption(std::string Range) { + std::string ComplexRangeStr = "-complex-range="; + ComplexRangeStr += Range; + return ComplexRangeStr; +} + static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, bool OFastEnabled, const ArgList &Args, ArgStringList &CmdArgs, @@ -2706,6 +2735,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, bool StrictFPModel = false; StringRef Float16ExcessPrecision = ""; StringRef BFloat16ExcessPrecision = ""; + LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_Full; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2718,6 +2748,28 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, switch (optID) { default: break; + case options::OPT_fcx_limited_range: { + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Limited); + Range = LangOptions::ComplexRangeKind::CX_Limited; + std::string ComplexRangeStr = RenderComplexRangeOption("limited"); + if (!ComplexRangeStr.empty()) + CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr)); + break; + } + case options::OPT_fno_cx_limited_range: + Range = LangOptions::ComplexRangeKind::CX_Full; + break; + case options::OPT_fcx_fortran_rules: { + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran); + Range = LangOptions::ComplexRangeKind::CX_Fortran; + std::string ComplexRangeStr = RenderComplexRangeOption("fortran"); + if (!ComplexRangeStr.empty()) + CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr)); + break; + } + case options::OPT_fno_cx_fortran_rules: + Range = LangOptions::ComplexRangeKind::CX_Full; + break; case options::OPT_ffp_model_EQ: { // If -ffp-model= is seen, reset to fno-fast-math HonorINFs = true; @@ -2772,7 +2824,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, D.Diag(diag::err_drv_unsupported_option_argument) << A->getSpelling() << Val; break; - } + } } switch (optID) { @@ -2971,7 +3023,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!OFastEnabled) continue; [[fallthrough]]; - case options::OPT_ffast_math: + case options::OPT_ffast_math: { HonorINFs = false; HonorNaNs = false; MathErrno = false; @@ -2985,7 +3037,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // If fast-math is set then set the fp-contract mode to fast. FPContract = "fast"; SeenUnsafeMathModeOption = true; + // ffast-math enables fortran rules for complex multiplication and + // division. + std::string ComplexRangeStr = RenderComplexRangeOption("limited"); + if (!ComplexRangeStr.empty()) + CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr)); break; + } case options::OPT_fno_fast_math: HonorINFs = true; HonorNaNs = true; @@ -3139,6 +3197,15 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow, options::OPT_fstrict_float_cast_overflow, false)) CmdArgs.push_back("-fno-strict-float-cast-overflow"); + + if (const Arg *A = Args.getLastArg(options::OPT_fcx_limited_range)) + CmdArgs.push_back("-fcx-limited-range"); + if (const Arg *A = Args.getLastArg(options::OPT_fcx_fortran_rules)) + CmdArgs.push_back("-fcx-fortran-rules"); + if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_limited_range)) + CmdArgs.push_back("-fno-cx-limited-range"); + if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_fortran_rules)) + CmdArgs.push_back("-fno-cx-fortran-rules"); } static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index efdf7c90f977f..730ac1a0fee5c 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -137,7 +137,20 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { tok::OnOffSwitch OOS; - PP.LexOnOffSwitch(OOS); + if (PP.LexOnOffSwitch(OOS)) + return; + + MutableArrayRef Toks( + PP.getPreprocessorAllocator().Allocate(1), 1); + + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_cx_limited_range); + Toks[0].setLocation(Tok.getLocation()); + Toks[0].setAnnotationEndLoc(Tok.getLocation()); + Toks[0].setAnnotationValue( + reinterpret_cast(static_cast(OOS))); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } }; @@ -888,6 +901,31 @@ void Parser::HandlePragmaFEnvRound() { Actions.ActOnPragmaFEnvRound(PragmaLoc, RM); } +void Parser::HandlePragmaCXLimitedRange() { + assert(Tok.is(tok::annot_pragma_cx_limited_range)); + tok::OnOffSwitch OOS = static_cast( + reinterpret_cast(Tok.getAnnotationValue())); + + LangOptions::ComplexRangeKind Range; + switch (OOS) { + case tok::OOS_ON: + Range = LangOptions::CX_Limited; + break; + case tok::OOS_OFF: + Range = LangOptions::CX_Full; + break; + case tok::OOS_DEFAULT: + // According to ISO C99 standard chapter 7.3.4, the default value + // for the pragma is ``off'. -fcx-limited-range and -fcx-fortran-rules + // control the default value of these pragmas. + Range = getLangOpts().getComplexRange(); + break; + } + + SourceLocation PragmaLoc = ConsumeAnnotationToken(); + Actions.ActOnPragmaCXLimitedRange(PragmaLoc, Range); +} + StmtResult Parser::HandlePragmaCaptured() { assert(Tok.is(tok::annot_pragma_captured)); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 918afdc2baea3..d0ff33bd1379a 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -444,6 +444,14 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( ConsumeAnnotationToken(); return StmtError(); + case tok::annot_pragma_cx_limited_range: + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); + Diag(Tok, diag::err_pragma_file_or_compound_scope) + << "STDC CX_LIMITED_RANGE"; + ConsumeAnnotationToken(); + return StmtError(); + case tok::annot_pragma_float_control: ProhibitAttributes(CXX11Attrs); ProhibitAttributes(GNUAttrs); @@ -1066,6 +1074,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() { case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); break; + case tok::annot_pragma_cx_limited_range: + HandlePragmaCXLimitedRange(); + break; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); break; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 1baeb2aeb021f..ec67faf7dcaf8 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -844,6 +844,9 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); return nullptr; + case tok::annot_pragma_cx_limited_range: + HandlePragmaCXLimitedRange(); + return nullptr; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); return nullptr; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 79271c8726273..0dcf42e489971 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -1352,6 +1352,14 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) { CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); } +void Sema::ActOnPragmaCXLimitedRange(SourceLocation Loc, + LangOptions::ComplexRangeKind Range) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + NewFPFeatures.setComplexRangeOverride(Range); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); +} + void Sema::ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind FPE) { setExceptionMode(Loc, FPE); diff --git a/clang/test/CodeGen/complex-math.c b/clang/test/CodeGen/complex-math.c index c59baaa452369..a44aa0014a658 100644 --- a/clang/test/CodeGen/complex-math.c +++ b/clang/test/CodeGen/complex-math.c @@ -5,7 +5,7 @@ // RUN: %clang_cc1 %s -O0 -emit-llvm -triple armv7-none-linux-gnueabi -o - | FileCheck %s --check-prefix=ARM // RUN: %clang_cc1 %s -O0 -emit-llvm -triple armv7-none-linux-gnueabihf -o - | FileCheck %s --check-prefix=ARMHF // RUN: %clang_cc1 %s -O0 -emit-llvm -triple thumbv7k-apple-watchos2.0 -o - -target-abi aapcs16 | FileCheck %s --check-prefix=ARM7K -// RUN: %clang_cc1 %s -O0 -emit-llvm -triple aarch64-unknown-unknown -ffast-math -ffp-contract=fast -o - | FileCheck %s --check-prefix=AARCH64-FASTMATH +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple aarch64-unknown-unknown -ffast-math -ffp-contract=fast -complex-range=fortran -o - | FileCheck %s --check-prefix=AARCH64-FASTMATH // RUN: %clang_cc1 %s -O0 -emit-llvm -triple spir -o - | FileCheck %s --check-prefix=SPIR float _Complex add_float_rr(float a, float b) { @@ -135,24 +135,68 @@ float _Complex div_float_rc(float a, float _Complex b) { // SPIR: call spir_func {{.*}} @__divsc3( - // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD)) + // a / b = (A+iB) / (C+iD) = (E+iF) + // if (|C| >= |D|) + // DdC = D/C + // CpRD = C+DdC*D + // E = (A+B*DdC)/CpRD + // F = (B-A*DdC)/CpRD + // else + // CdD = C/D + // DpRC= D+CdD*C + // E = (A*CdD+B)/DpRC + // F = (B*CdD-A)/DpRC // AARCH64-FASTMATH-LABEL: @div_float_rc(float noundef nofpclass(nan inf) %a, [2 x float] noundef nofpclass(nan inf) alignstack(8) %b.coerce) - // A = a - // B = 0 - // - // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast float - // BD = 0 - // ACpBD = AC - // - // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast float - // - // BC = 0 - // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast float - // - // AARCH64-FASTMATH: fdiv fast float - // AARCH64-FASTMATH: fdiv fast float + // |C| + // AARCH64-FASTMATH: call {{.*}}float @llvm.fabs.f32(float {{.*}}) + // |D| + // AARCH64-FASTMATH-NEXT: call {{.*}}float @llvm.fabs.f32(float {{.*}}) + // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt float + // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label + // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi: + + // |C| >= |D| + // DdC=D/C + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // CpRD=C+CdC*D + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + + // A+BR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // B-AR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fsub {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi: + + // |C| < |D| + // CdD=C/D + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // DpRC=D+CdD*C + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + + // (A*CdD+B)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // (BCdD-A)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fsub {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: complex_div: + // AARCH64-FASTMATH-NEXT: phi {{.*}}float + // AARCH64-FASTMATH-NEXT: phi {{.*}}float // AARCH64-FASTMATH: ret return a / b; } @@ -164,24 +208,68 @@ float _Complex div_float_cc(float _Complex a, float _Complex b) { // SPIR: call spir_func {{.*}} @__divsc3( - // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD)) + // a / b = (A+iB) / (C+iD) = (E+iF) + // if (|C| >= |D|) + // DdC = D/C + // CpRD = C+DdC*D + // E = (A+B*DdC)/CpRD + // F = (B-A*DdC)/CpRD + // else + // CdD = C/D + // DpRC= D+CdD*C + // E = (A*CdD+B)/DpRC + // F = (B*CdD-A)/DpRC // AARCH64-FASTMATH-LABEL: @div_float_cc([2 x float] noundef nofpclass(nan inf) alignstack(8) %a.coerce, [2 x float] noundef nofpclass(nan inf) alignstack(8) %b.coerce) - // - // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[BD:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[ACpBD:%.*]] = fadd fast float - // - // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast float - // - // AARCH64-FASTMATH: [[BC:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast float - // AARCH64-FASTMATH: [[BCmAD:%.*]] = fsub fast float - // - // AARCH64-FASTMATH: fdiv fast float - // AARCH64-FASTMATH: fdiv fast float - // AARCH64-FASTMATH: ret + // |C| + // AARCH64-FASTMATH: call {{.*}}float @llvm.fabs.f32(float {{.*}}) + // |D| + // AARCH64-FASTMATH-NEXT: call {{.*}}float @llvm.fabs.f32(float {{.*}}) + // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt float + // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label + // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi: + + // |C| >= |D| + // DdC=D/C + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // CpRD=C+CdC*D + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + + // A+BR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // B-AR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fsub {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi: + + // |C| < |D| + // CdD=C/D + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // DpRC=D+CdD*C + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + + // (A*CdD+B)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fadd {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // (BCdD-A)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}float + // AARCH64-FASTMATH-NEXT: fsub {{.*}}float + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float + + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: complex_div: + // AARCH64-FASTMATH-NEXT: phi {{.*}}float + // AARCH64-FASTMATH-NEXT: phi {{.*}}float return a / b; } @@ -312,24 +400,68 @@ double _Complex div_double_rc(double a, double _Complex b) { // SPIR: call spir_func {{.*}} @__divdc3( - // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD)) + // a / b = (A+iB) / (C+iD) = (E+iF) + // if (|C| >= |D|) + // DdC = D/C + // CpRD = C+DdC*D + // E = (A+B*DdC)/CpRD + // F = (B-A*DdC)/CpRD + // else + // CdD = C/D + // DpRC= D+CdD*C + // E = (A*CdD+B)/DpRC + // F = (B*CdD-A)/DpRC // AARCH64-FASTMATH-LABEL: @div_double_rc(double noundef nofpclass(nan inf) %a, [2 x double] noundef nofpclass(nan inf) alignstack(8) %b.coerce) - // A = a - // B = 0 - // - // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast double - // BD = 0 - // ACpBD = AC - // - // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast double - // - // BC = 0 - // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast double - // - // AARCH64-FASTMATH: fdiv fast double - // AARCH64-FASTMATH: fdiv fast double + // |C| + // AARCH64-FASTMATH: call {{.*}}double @llvm.fabs.f64(double {{.*}}) + // |D| + // AARCH64-FASTMATH-NEXT: call {{.*}}double @llvm.fabs.f64(double {{.*}}) + // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt double + // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label + // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi: + + // |C| >= |D| + // DdC=D/C + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // CpRD=C+CdC*D + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + + // A+BR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // B-AR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fsub {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi: + + // |C| < |D| + // CdD=C/D + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // DpRC=D+CdD*C + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + + // (A*CdD+B)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // (BCdD-A)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fsub {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: complex_div: + // AARCH64-FASTMATH-NEXT: phi {{.*}}double + // AARCH64-FASTMATH-NEXT: phi {{.*}}double // AARCH64-FASTMATH: ret return a / b; } @@ -341,23 +473,68 @@ double _Complex div_double_cc(double _Complex a, double _Complex b) { // SPIR: call spir_func {{.*}} @__divdc3( - // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD)) + // a / b = (A+iB) / (C+iD) = (E+iF) + // if (|C| >= |D|) + // DdC = D/C + // CpRD = C+DdC*D + // E = (A+B*DdC)/CpRD + // F = (B-A*DdC)/CpRD + // else + // CdD = C/D + // DpRC= D+CdD*C + // E = (A*CdD+B)/DpRC + // F = (B*CdD-A)/DpRC // AARCH64-FASTMATH-LABEL: @div_double_cc([2 x double] noundef nofpclass(nan inf) alignstack(8) %a.coerce, [2 x double] noundef nofpclass(nan inf) alignstack(8) %b.coerce) - // - // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[BD:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[ACpBD:%.*]] = fadd fast double - // - // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast double - // - // AARCH64-FASTMATH: [[BC:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast double - // AARCH64-FASTMATH: [[BCmAD:%.*]] = fsub fast double - // - // AARCH64-FASTMATH: fdiv fast double - // AARCH64-FASTMATH: fdiv fast double + // |C| + // AARCH64-FASTMATH: call {{.*}}double @llvm.fabs.f64(double {{.*}}) + // |D| + // AARCH64-FASTMATH-NEXT: call {{.*}}double @llvm.fabs.f64(double {{.*}}) + // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt double + // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label + // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi: + + // |C| >= |D| + // DdC=D/C + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // CpRD=C+CdC*D + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + + // A+BR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // B-AR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fsub {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi: + + // |C| < |D| + // CdD=C/D + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // DpRC=D+CdD*C + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + + // (A*CdD+B)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fadd {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // (BCdD-A)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}double + // AARCH64-FASTMATH-NEXT: fsub {{.*}}double + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double + + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: complex_div: + // AARCH64-FASTMATH-NEXT: phi {{.*}}double + // AARCH64-FASTMATH-NEXT: phi {{.*}}double // AARCH64-FASTMATH: ret return a / b; } @@ -505,24 +682,68 @@ long double _Complex div_long_double_rc(long double a, long double _Complex b) { // PPC: ret // SPIR: call spir_func {{.*}} @__divdc3( - // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD)) + // a / b = (A+iB) / (C+iD) = (E+iF) + // if (|C| >= |D|) + // DdC = D/C + // CpRD = C+DdC*D + // E = (A+B*DdC)/CpRD + // F = (B-A*DdC)/CpRD + // else + // CdD = C/D + // DpRC= D+CdD*C + // E = (A*CdD+B)/DpRC + // F = (B*CdD-A)/DpRC // AARCH64-FASTMATH-LABEL: @div_long_double_rc(fp128 noundef nofpclass(nan inf) %a, [2 x fp128] noundef nofpclass(nan inf) alignstack(16) %b.coerce) - // A = a - // B = 0 - // - // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast fp128 - // BD = 0 - // ACpBD = AC - // - // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast fp128 - // - // BC = 0 - // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast fp128 - // - // AARCH64-FASTMATH: fdiv fast fp128 - // AARCH64-FASTMATH: fdiv fast fp128 + // |C| + // AARCH64-FASTMATH: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}}) + // |D| + // AARCH64-FASTMATH-NEXT: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}}) + // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt fp128 + // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label + // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi: + + // |C| >= |D| + // DdC=D/C + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // CpRD=C+CdC*D + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + + // A+BR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // B-AR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi: + + // |C| < |D| + // CdD=C/D + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // DpRC=D+CdD*C + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + + // (A*CdD+B)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // (BCdD-A)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: complex_div: + // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128 // AARCH64-FASTMATH: ret return a / b; } @@ -537,23 +758,68 @@ long double _Complex div_long_double_cc(long double _Complex a, long double _Com // PPC: ret // SPIR: call spir_func {{.*}} @__divdc3( - // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD)) + // a / b = (A+iB) / (C+iD) = (E+iF) + // if (|C| >= |D|) + // DdC = D/C + // CpRD = C+DdC*D + // E = (A+B*DdC)/CpRD + // F = (B-A*DdC)/CpRD + // else + // CdD = C/D + // DpRC= D+CdD*C + // E = (A*CdD+B)/DpRC + // F = (B*CdD-A)/DpRC // AARCH64-FASTMATH-LABEL: @div_long_double_cc([2 x fp128] noundef nofpclass(nan inf) alignstack(16) %a.coerce, [2 x fp128] noundef nofpclass(nan inf) alignstack(16) %b.coerce) - // - // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[BD:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[ACpBD:%.*]] = fadd fast fp128 - // - // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast fp128 - // - // AARCH64-FASTMATH: [[BC:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast fp128 - // AARCH64-FASTMATH: [[BCmAD:%.*]] = fsub fast fp128 - // - // AARCH64-FASTMATH: fdiv fast fp128 - // AARCH64-FASTMATH: fdiv fast fp128 + // |C| + // AARCH64-FASTMATH: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}}) + // |D| + // AARCH64-FASTMATH-NEXT: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}}) + // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt fp128 + // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label + // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi: + + // |C| >= |D| + // DdC=D/C + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // CpRD=C+CdC*D + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + + // A+BR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // B-AR/CpRD + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi: + + // |C| < |D| + // CdD=C/D + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // DpRC=D+CdD*C + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + + // (A*CdD+B)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // (BCdD-A)/DpRC + // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128 + + // AARCH64-FASTMATH-NEXT: br label + // AARCH64-FASTMATH: complex_div: + // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128 + // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128 // AARCH64-FASTMATH: ret return a / b; } diff --git a/clang/test/CodeGen/cx-complex-range.c b/clang/test/CodeGen/cx-complex-range.c new file mode 100644 index 0000000000000..8368fa611335c --- /dev/null +++ b/clang/test/CodeGen/cx-complex-range.c @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -o - | FileCheck %s --check-prefix=FULL + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -complex-range=limited -o - | FileCheck %s --check-prefix=LMTD + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -fno-cx-limited-range -o - | FileCheck %s --check-prefix=FULL + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -complex-range=fortran -o - | FileCheck %s --check-prefix=FRTRN + +// Fast math +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu \ +// RUN: -ffast-math -complex-range=limited -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=LMTD-FAST + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -fno-cx-fortran-rules -o - | FileCheck %s --check-prefix=FULL + +_Complex float div(_Complex float a, _Complex float b) { + // LABEL: define {{.*}} @div( + // FULL: call {{.*}} @__divsc3 + + // LMTD: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fadd float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fadd float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fsub float + // LMTD-NEXT: fdiv float + // LMTD-NEXT: fdiv float + + // FRTRN: call {{.*}}float @llvm.fabs.f32(float {{.*}}) + // FRTRN-NEXT: call {{.*}}float @llvm.fabs.f32(float {{.*}}) + // FRTRN-NEXT: fcmp {{.*}}ugt float + // FRTRN-NEXT: br i1 {{.*}}, label + // FRTRN: abs_rhsr_greater_or_equal_abs_rhsi: + // FRTRN-NEXT: fdiv {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fadd {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fadd {{.*}}float + // FRTRN-NEXT: fdiv {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fsub {{.*}}float + // FRTRN-NEXT: fdiv {{.*}}float + // FRTRN-NEXT: br label + // FRTRN: abs_rhsr_less_than_abs_rhsi: + // FRTRN-NEXT: fdiv {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fadd {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fadd {{.*}}float + // FRTRN-NEXT: fdiv {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fsub {{.*}}float + // FRTRN-NEXT: fdiv {{.*}}float + // FRTRN-NEXT: br label + // FRTRN: complex_div: + // FRTRN-NEXT: phi {{.*}}float + // FRTRN-NEXT: phi {{.*}}float + + // LMTD-FAST: fmul {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fadd {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fadd {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fsub {{.*}} float + // LMTD-FAST-NEXT: fdiv {{.*}} float + // LMTD-FAST-NEXT: fdiv {{.*}} float + + return a / b; +} + +_Complex float mul(_Complex float a, _Complex float b) { + // LABEL: define {{.*}} @mul( + // FULL: call {{.*}} @__mulsc3 + + // LMTD: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fsub float + // LMTD-NEXT: fadd float + + // FRTRN: fmul {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fmul {{.*}}float + // FRTRN-NEXT: fsub {{.*}}float + // FRTRN-NEXT: fadd {{.*}}float + + // LMTD-FAST: fmul {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fmul {{.*}} float + // LMTD-FAST-NEXT: fsub {{.*}} float + // LMTD-FAST-NEXT: fadd {{.*}} float + + return a * b; +} diff --git a/clang/test/CodeGen/pragma-cx-limited-range.c b/clang/test/CodeGen/pragma-cx-limited-range.c new file mode 100644 index 0000000000000..926da8afbee55 --- /dev/null +++ b/clang/test/CodeGen/pragma-cx-limited-range.c @@ -0,0 +1,107 @@ +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -o - | FileCheck %s --check-prefix=FULL + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -complex-range=limited -o - | FileCheck --check-prefix=LMTD %s + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -fno-cx-limited-range -o - | FileCheck %s --check-prefix=FULL + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -complex-range=fortran -o - | FileCheck --check-prefix=FRTRN %s + +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \ +// RUN: -fno-cx-fortran-rules -o - | FileCheck --check-prefix=FULL %s + +_Complex float pragma_on_mul(_Complex float a, _Complex float b) { +#pragma STDC CX_LIMITED_RANGE ON + // LABEL: define {{.*}} @pragma_on_mul( + // FULL: fmul float + // FULL-NEXT: fmul float + // FULL-NEXT: fmul float + // FULL-NEXT: fmul float + // FULL-NEXT: fsub float + // FULL-NEXT: fadd float + + // LMTD: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fsub float + // LMTD-NEXT: fadd float + + // FRTRN: fmul float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fsub float + // FRTRN-NEXT: fadd float + + return a * b; +} + +_Complex float pragma_off_mul(_Complex float a, _Complex float b) { +#pragma STDC CX_LIMITED_RANGE OFF + // LABEL: define {{.*}} @pragma_off_mul( + // FULL: call {{.*}} @__mulsc3 + + // LMTD: call {{.*}} @__mulsc3 + + // FRTRN: call {{.*}} @__mulsc3 + + return a * b; +} + +_Complex float pragma_on_div(_Complex float a, _Complex float b) { +#pragma STDC CX_LIMITED_RANGE ON + // LABEL: define {{.*}} @pragma_on_div( + // FULL: fmul float + // FULL-NEXT: fmul float + // FULL-NEXT: fadd float + // FULL-NEXT: fmul float + // FULL-NEXT: fmul float + // FULL-NEXT: fadd float + // FULL-NEXT: fmul float + // FULL-NEXT: fmul float + // FULL-NEXT: fsub float + // FULL-NEXT: fdiv float + // FULL: fdiv float + + // LMTD: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fadd float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fadd float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fmul float + // LMTD-NEXT: fsub float + // LMTD-NEXT: fdiv float + // LMTD-NEXT: fdiv float + + // FRTRN: fmul float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fadd float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fadd float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fmul float + // FRTRN-NEXT: fsub float + // FRTRN-NEXT: fdiv float + // FRTRN-NEXT: fdiv float + + return a / b; +} + +_Complex float pragma_off_div(_Complex float a, _Complex float b) { +#pragma STDC CX_LIMITED_RANGE OFF + // LABEL: define {{.*}} @pragma_off_div( + // FULL: call {{.*}} @__divsc3 + + // LMTD: call {{.*}} @__divsc3 + + // FRTRN: call {{.*}} @__divsc3 + + return a / b; +} diff --git a/clang/test/Driver/range.c b/clang/test/Driver/range.c new file mode 100644 index 0000000000000..8d456a997d696 --- /dev/null +++ b/clang/test/Driver/range.c @@ -0,0 +1,39 @@ +// Test range options for complex multiplication and division. + +// RUN: %clang -### -target x86_64 -fcx-limited-range -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=LMTD %s + +// RUN: %clang -### -target x86_64 -fno-cx-limited-range -c %s 2>&1 \ +// RUN: | FileCheck %s + +// RUN: %clang -### -target x86_64 -fcx-fortran-rules -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=FRTRN %s + +// RUN: %clang -### -target x86_64 -fno-cx-fortran-rules -c %s 2>&1 \ +// RUN: | FileCheck %s + +// RUN: %clang -### -target x86_64 -fcx-limited-range \ +// RUN: -fcx-fortran-rules -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN1 %s + +// RUN: %clang -### -target x86_64 -fcx-fortran-rules \ +// RUN: -fcx-limited-range -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN2 %s + +// RUN: %clang -### -target x86_64 -ffast-math -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=LMTD %s + +// RUN: %clang -### -target x86_64 -ffast-math -fcx-limited-range -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=LMTD %s + +// RUN: %clang -### -target x86_64 -fcx-limited-range -ffast-math -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=LMTD %s + +// LMTD: -complex-range=limited +// LMTD-NOT: -complex-range=fortran +// CHECK-NOT: -complex-range=limited +// FRTRN: -complex-range=fortran +// FRTRN-NOT: -complex-range=limited +// CHECK-NOT: -complex-range=fortran +// WARN1: warning: overriding '-fcx-limited-range' option with '-fcx-fortran-rules' [-Woverriding-option] +// WARN2: warning: overriding '-fcx-fortran-rules' option with '-fcx-limited-range' [-Woverriding-option] diff --git a/clang/test/Preprocessor/pragma_unknown.c b/clang/test/Preprocessor/pragma_unknown.c index a7c4829c279dd..1d39f8229eb53 100644 --- a/clang/test/Preprocessor/pragma_unknown.c +++ b/clang/test/Preprocessor/pragma_unknown.c @@ -27,6 +27,8 @@ #pragma STDC CX_LIMITED_RANGE // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}} #pragma STDC CX_LIMITED_RANGE ON FULL POWER // expected-warning {{expected end of directive in pragma}} +//expected-error@-1 {{unknown type name 'POWER'}} +//expected-error@-2 {{expected identifier or '('}} // CHECK: {{^}}#pragma STDC CX_LIMITED_RANGE{{$}} // CHECK: {{^}}#pragma STDC CX_LIMITED_RANGE ON FULL POWER{{$}}