Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -72,6 +72,8 @@ "in a constant expression">; def note_constexpr_float_arithmetic : Note< "floating point arithmetic produces %select{an infinity|a NaN}0">; +def note_constexpr_float_arithmetic_strict : Note< + "compile time floating point arithmetic suppressed in strict evaluation modes">; def note_constexpr_pointer_subtraction_not_same_array : Note< "subtracted pointers are not elements of the same array">; def note_constexpr_pointer_subtraction_zero_size : Note< Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1133,9 +1133,9 @@ // - #pragma stdc unknown def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, InGroup; -def warn_stdc_fenv_access_not_supported : - Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, - InGroup; +def err_pragma_stdc_fenv_access_scope : Error< + "'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of a " + "compound statement">; def warn_stdc_fenv_round_not_supported : Warning<"pragma STDC FENV_ROUND is not supported">, InGroup; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -4344,6 +4344,7 @@ void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef Elts, bool isStmtExpr); + void ActOnAfterCompoundStatementLeadingPragmas(); /// A RAII object to enter scope of a compound statement. class CompoundScopeRAII { Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -2435,11 +2435,17 @@ } static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, + const FPOptions fpOptions, QualType SrcType, const APSInt &Value, QualType DestType, APFloat &Result) { Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1); - Result.convertFromAPInt(Value, Value.isSigned(), - APFloat::rmNearestTiesToEven); + if (llvm::APFloatBase::opOK != Result.convertFromAPInt(Value, + Value.isSigned(), + APFloat::rmNearestTiesToEven) && + fpOptions.isFPConstrained()) { + Info.CCEDiag(E, diag::note_constexpr_float_arithmetic_strict); + return false; + } return true; } @@ -2640,31 +2646,38 @@ } /// Perform the given binary floating-point operation, in-place, on LHS. -static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, +static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E, APFloat &LHS, BinaryOperatorKind Opcode, const APFloat &RHS) { + assert(E != nullptr); + llvm::APFloatBase::opStatus status; switch (Opcode) { default: Info.FFDiag(E); return false; case BO_Mul: - LHS.multiply(RHS, APFloat::rmNearestTiesToEven); + status = LHS.multiply(RHS, APFloat::rmNearestTiesToEven); break; case BO_Add: - LHS.add(RHS, APFloat::rmNearestTiesToEven); + status = LHS.add(RHS, APFloat::rmNearestTiesToEven); break; case BO_Sub: - LHS.subtract(RHS, APFloat::rmNearestTiesToEven); + status = LHS.subtract(RHS, APFloat::rmNearestTiesToEven); break; case BO_Div: // [expr.mul]p4: // If the second operand of / or % is zero the behavior is undefined. if (RHS.isZero()) Info.CCEDiag(E, diag::note_expr_divide_by_zero); - LHS.divide(RHS, APFloat::rmNearestTiesToEven); + status = LHS.divide(RHS, APFloat::rmNearestTiesToEven); break; } + if (E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained() && + llvm::APFloatBase::opOK != status) { + Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict); + return false; + } // [expr.pre]p4: // If during the evaluation of an expression, the result is not // mathematically defined [...], the behavior is undefined. @@ -2811,8 +2824,8 @@ "Mismatched LHS/RHS/Result Type"); APFloat LHSFloat = LHSElt.getFloat(); - if (!handleFloatFloatBinOp(Info, E, LHSFloat, Opcode, - RHSElt.getFloat())) { + if (!handleFloatFloatBinOp(Info, dyn_cast(E), LHSFloat, + Opcode, RHSElt.getFloat())) { Info.FFDiag(E); return false; } @@ -4142,10 +4155,13 @@ Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS); return true; } else if (RHS.isFloat()) { + const BinaryOperator *BE = dyn_cast(E); + const FPOptions fpOptions = BE->getFPFeaturesInEffect( + Info.Ctx.getLangOpts()); APFloat FValue(0.0); - return HandleIntToFloatCast(Info, E, SubobjType, Value, PromotedLHSType, - FValue) && - handleFloatFloatBinOp(Info, E, FValue, Opcode, RHS.getFloat()) && + return HandleIntToFloatCast(Info, E, fpOptions, SubobjType, Value, + PromotedLHSType, FValue) && + handleFloatFloatBinOp(Info, BE, FValue, Opcode, RHS.getFloat()) && HandleFloatToIntCast(Info, E, PromotedLHSType, FValue, SubobjType, Value); } @@ -4157,7 +4173,8 @@ return checkConst(SubobjType) && HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType, Value) && - handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) && + handleFloatFloatBinOp(Info, dyn_cast(E), Value, + Opcode, RHS.getFloat()) && HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value); } bool foundPointer(APValue &Subobj, QualType SubobjType) { @@ -12220,6 +12237,10 @@ if (LHSTy->isRealFloatingType() && RHSTy->isRealFloatingType()) { + // Note: Compares may raise invalid in some cases involving NaN or sNaN. + // but this doesn't affect constant folding since NaN are + // not constant expressions. + APFloat RHS(0.0), LHS(0.0); bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info); @@ -13266,6 +13287,10 @@ case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: case Builtin::BI__builtin_fabsf128: + // The c lang ref says that "fabs raises no floating-point exceptions, + // even if x is a signaling NaN. The returned value is independent of + // the current rounding direction mode." Therefore constant folding can + // proceed without regard to the floating point settings. if (!EvaluateFloat(E->getArg(0), Result, Info)) return false; @@ -13319,6 +13344,8 @@ } bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + // In C lang ref, the unary - raises no floating point exceptions, + // even if the operand is signalling. switch (E->getOpcode()) { default: return Error(E); case UO_Plus: @@ -13348,6 +13375,14 @@ return true; } +static bool isWideningFPConversion(const QualType DestType, + const QualType SourceType) { + const BuiltinType *ST = dyn_cast(SourceType); + const BuiltinType *DT = dyn_cast(DestType); + return ST && DT && DT->isRealFloatingType() && ST->isRealFloatingType() && + ST->getKind() <= DT->getKind(); +} + bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) { const Expr* SubExpr = E->getSubExpr(); @@ -13357,14 +13392,24 @@ case CK_IntegralToFloating: { APSInt IntResult; + const FPOptions fpOptions = E->getFPFeaturesInEffect( + Info.Ctx.getLangOpts()); return EvaluateInteger(SubExpr, IntResult, Info) && - HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult, - E->getType(), Result); + HandleIntToFloatCast(Info, E, fpOptions, SubExpr->getType(), + IntResult, E->getType(), Result); } case CK_FloatingCast: { if (!Visit(SubExpr)) return false; + if (E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained() && + !isWideningFPConversion(E->getType(), SubExpr->getType())) { + // In C lang ref, footnote, cast may raise inexact exception. + // Cast may also raise invalid. + // Widening conversions do not raise FP exceptions. + Info.CCEDiag(E, diag::note_constexpr_float_arithmetic_strict); + return false; + } return HandleFloatToFloatCast(Info, E, SubExpr->getType(), E->getType(), Result); } @@ -13587,13 +13632,15 @@ if (!Visit(E->getSubExpr())) return false; + const FPOptions fpOptions = E->getFPFeaturesInEffect( + Info.Ctx.getLangOpts()); QualType To = E->getType()->castAs()->getElementType(); QualType From = E->getSubExpr()->getType()->castAs()->getElementType(); Result.makeComplexFloat(); - return HandleIntToFloatCast(Info, E, From, Result.IntReal, + return HandleIntToFloatCast(Info, E, fpOptions, From, Result.IntReal, To, Result.FloatReal) && - HandleIntToFloatCast(Info, E, From, Result.IntImag, + HandleIntToFloatCast(Info, E, fpOptions, From, Result.IntImag, To, Result.FloatImag); } } Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1137,6 +1137,10 @@ /// definition. void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F); + /// Set the LLVM function attributes that represent floating point + /// environment. + void setLLVMFunctionFEnvAttributes(const FunctionDecl *D, llvm::Function *F); + /// Return true iff the given type uses 'sret' when used as a return type. bool ReturnTypeUsesSRet(const CGFunctionInfo &FI); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -1725,6 +1725,15 @@ } } +void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D, + llvm::Function *F) { + if (D->usesFPIntrin()) { + llvm::AttrBuilder FuncAttrs; + FuncAttrs.addAttribute("strictfp"); + F->addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs); + } +} + void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) { const Decl *D = GD.getDecl(); if (dyn_cast_or_null(D)) @@ -4554,9 +4563,11 @@ MaybeHandleStaticInExternC(D, Fn); - maybeSetTrivialComdat(*D, *Fn); + // Set CodeGen attributes that represent floating point environment. + setLLVMFunctionFEnvAttributes(D, Fn); + CodeGenFunction(*this).GenerateCode(GD, Fn, FI); setNonAliasAttributes(GD, Fn); Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -106,10 +106,6 @@ tok::OnOffSwitch OOS; if (PP.LexOnOffSwitch(OOS)) return; - if (OOS == tok::OOS_ON) { - PP.Diag(Tok, diag::warn_stdc_fenv_access_not_supported); - return; - } MutableArrayRef Toks(PP.getPreprocessorAllocator().Allocate(1), 1); Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -366,7 +366,8 @@ case tok::annot_pragma_fenv_access: ProhibitAttributes(Attrs); - HandlePragmaFEnvAccess(); + Diag(Tok, diag::err_pragma_stdc_fenv_access_scope); + ConsumeAnnotationToken(); return StmtEmpty(); case tok::annot_pragma_fenv_round: @@ -1033,9 +1034,9 @@ Tok.getLocation(), "in compound statement ('{}')"); - // Record the state of the FPFeatures, restore on leaving the + // Record the current FPFeatures, restore on leaving the // compound statement. - Sema::FPFeaturesStateRAII SaveFPContractState(Actions); + Sema::FPFeaturesStateRAII SaveFPFeatures(Actions); InMessageExpressionRAIIObject InMessage(*this, false); BalancedDelimiterTracker T(*this, tok::l_brace); @@ -1046,6 +1047,7 @@ // Parse any pragmas at the beginning of the compound statement. ParseCompoundStatementLeadingPragmas(); + Actions.ActOnAfterCompoundStatementLeadingPragmas(); StmtVector Stmts; Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -389,6 +389,13 @@ PopCompoundScope(); } +void Sema::ActOnAfterCompoundStatementLeadingPragmas() { + if (getCurFPFeatures().getAllowFEnvAccess()) { + FunctionDecl *F = getCurFunctionDecl(); + F->setUsesFPIntrin(true); + } +} + sema::CompoundScopeInfo &Sema::getCurCompoundScope() const { return getCurFunction()->CompoundScopes.back(); } Index: clang/test/CXX/expr/expr.const/p2-0x.cpp =================================================================== --- clang/test/CXX/expr/expr.const/p2-0x.cpp +++ clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -280,6 +280,16 @@ constexpr float f10 = f2 - f2; // expected-error {{constant expression}} expected-note {{produces a NaN}} constexpr float f11 = f2 + f4; // expected-error {{constant expression}} expected-note {{produces a NaN}} constexpr float f12 = f2 / f2; // expected-error {{constant expression}} expected-note {{produces a NaN}} +#pragma float_control(push) +#pragma float_control(except, on) +constexpr float pi = 3.14f; +constexpr unsigned ubig = 0xFFFFFFFF; +constexpr float ce = 1.0 / 3.0; // expected-error {{constant expression}} expected-note {{floating point arithmetic suppressed in strict evaluation modes}} +constexpr int ci = (int) pi; +constexpr float fbig = (float) ubig; // expected-error {{constant expression}} expected-note {{floating point arithmetic suppressed in strict evaluation modes}} +constexpr float fabspi = __builtin_fabs(pi); // expected-error {{constant expression}} expected-note {{floating point arithmetic suppressed in strict evaluation modes}} +constexpr float negpi = -pi; // expect no error on unary operator +#pragma float_control(pop) static_assert(!isinf(f1), ""); static_assert(isinf(f2), ""); static_assert(!isinf(f3), ""); Index: clang/test/CodeGen/fp-floatcontrol-pragma.cpp =================================================================== --- clang/test/CodeGen/fp-floatcontrol-pragma.cpp +++ clang/test/CodeGen/fp-floatcontrol-pragma.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -verify -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s // RUN: %clang_cc1 -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s // Verify float_control(precise, off) enables fast math flags on fp operations. @@ -138,7 +138,6 @@ // CHECK-LABEL define float {{.*}}test_OperatorCall{{.*}} #if FENV_ON -// expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} #pragma STDC FENV_ACCESS ON #endif // CHECK-LABEL: define {{.*}}callt{{.*}} @@ -146,7 +145,21 @@ void callt() { volatile float z; z = z * z; -//CHECK: = fmul float + //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}} +} + +// CHECK-LABEL: define {{.*}}myAdd{{.*}} +float myAdd(int i, float f) { + if (i<0) + return 1.0 + 2.0; + // Check that floating point constant folding doesn't occur if + // #pragma STC FENV_ACCESS is enabled. + //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}} + //CHECK: store float 3.0{{.*}}retval{{.*}} + static double v = 1.0 / 3.0; + //CHECK-FENV: llvm.experimental.constrained.fdiv{{.*}}double 1.0{{.*}}double 3.0{{.*}} + //CHECK-NOT: fdiv + return v; } #if EXCEPT Index: clang/test/CodeGen/pragma-fenv_access.c =================================================================== --- /dev/null +++ clang/test/CodeGen/pragma-fenv_access.c @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s + +#pragma STDC FENV_ACCESS ON + +float func_01(float x, float y) { + return x + y; +} +// CHECK-LABEL: @func_01 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") + + +float func_02(float x, float y) { + #pragma float_control(except, off) + #pragma STDC FENV_ACCESS OFF + return x + y; +} +// CHECK-LABEL: @func_02 +// CHECK: fadd float {{.*}} + + +float func_03(float x, float y) { + return x + y; +} +// CHECK-LABEL: @func_03 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") + + +#pragma STDC FENV_ACCESS OFF + +float func_04(float x, float y) { + #pragma float_control(except, off) + return x + y; +} +// CHECK-LABEL: @func_04 +// CHECK: fadd float {{.*}} + + +float func_05(float x, float y) { + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_05 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") + + +float func_06(float x, float y) { + #pragma float_control(except, off) + return x + y; +} +// CHECK-LABEL: @func_06 +// CHECK: fadd float {{.*}} + + +float func_07(float x, float y) { + x -= y; + if (x) { + #pragma STDC FENV_ACCESS ON + y *= 2; + } + return y + 4; +} +// CHECK-LABEL: @func_07 +// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") Index: clang/test/Parser/fp-floatcontrol-syntax.cpp =================================================================== --- clang/test/Parser/fp-floatcontrol-syntax.cpp +++ clang/test/Parser/fp-floatcontrol-syntax.cpp @@ -26,19 +26,14 @@ double a = 0.0; double b = 1.0; -//FIXME At some point this warning will be removed, until then -// document the warning -#ifdef FAST -// expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} -#pragma STDC FENV_ACCESS ON -#else -#pragma STDC FENV_ACCESS ON // expected-warning{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} -#endif #ifdef STRICT #pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}} #else +#ifndef FAST // Currently FENV_ACCESS cannot be enabled by pragma, skip error check -#pragma float_control(precise, off) // not-expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}} +#pragma STDC FENV_ACCESS ON +#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}} +#endif #endif #pragma float_control(precise, on) Index: clang/test/Parser/pragma-fenv_access.c =================================================================== --- /dev/null +++ clang/test/Parser/pragma-fenv_access.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -ffp-exception-behavior=strict -DSTRICT -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++ -DCPP -DSTRICT -ffp-exception-behavior=strict -fsyntax-only -verify %s +#ifdef CPP +#define CONST constexpr +#else +#define CONST const +#endif + +#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}} + +#pragma STDC FENV_ACCESS OFF + +float func_04(int x, float y) { + if (x) + return y + 2; + #pragma STDC FENV_ACCESS ON // expected-error{{'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of a compound statement}} + return x + y; +} + +int main() { + CONST float one = 1.0F ; + CONST float three = 3.0F ; + CONST float four = 4.0F ; + CONST float frac_ok = one/four; +#if defined(CPP) & defined(STRICT) +//expected-error@+3 {{constexpr variable 'frac' must be initialized by a constant expression}} +//expected-note@+2 {{compile time floating point arithmetic suppressed in strict evaluation modes}} +#endif + CONST float frac = one/three; // rounding + CONST double d = one; + CONST int not_too_big = 255; + CONST float fnot_too_big = not_too_big; + CONST int too_big = 0x7ffffff0; +#if defined(CPP) & defined(STRICT) +//expected-error@+6 {{constexpr variable 'fbig' must be initialized by a constant expression}} +//expected-note@+5 {{compile time floating point arithmetic suppressed in strict evaluation modes}} +#endif +#if defined(CPP) +//expected-warning@+2{{implicit conversion}} +#endif + CONST float fbig = too_big; // inexact + if (one <= four) return 0; + return -1; +} Index: clang/test/Preprocessor/pragma_unknown.c =================================================================== --- clang/test/Preprocessor/pragma_unknown.c +++ clang/test/Preprocessor/pragma_unknown.c @@ -16,15 +16,6 @@ // CHECK: {{^}}#pragma STDC FP_CONTRACT DEFAULT{{$}} // CHECK: {{^}}#pragma STDC FP_CONTRACT IN_BETWEEN{{$}} -#pragma STDC FENV_ACCESS ON // expected-warning {{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} -#pragma STDC FENV_ACCESS OFF -#pragma STDC FENV_ACCESS DEFAULT -#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS ON{{$}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS OFF{{$}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS DEFAULT{{$}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS IN_BETWEEN{{$}} - #pragma STDC CX_LIMITED_RANGE ON #pragma STDC CX_LIMITED_RANGE OFF #pragma STDC CX_LIMITED_RANGE DEFAULT