diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -3173,16 +3173,36 @@ compound statement, the pragma is active within the scope of the compound statement. -Currently, only FP contraction can be controlled with the pragma. ``#pragma -clang fp contract`` specifies whether the compiler should contract a multiply -and an addition (or subtraction) into a fused FMA operation when supported by -the target. +Currently, the following settings can be controlled with this pragma: + +``#pragma clang fp reassociate`` allows control over the reassociation +of floating point expressions. When enabled, this pragma allows the expression +``x + (y + z)`` to be reassociated as ``(x + y) + z``. +Reassociation can also occur across multiple statements. +This pragma can be used to disable reassociation when it is otherwise +enabled for the translation unit with the ``-fassociative-math`` flag. +The pragma can take two values: ``on`` and ``off``. + +.. code-block:: c++ + + float f(float x, float y, float z) + { + // Enable floating point reassociation across statements + #pragma fp reassociate(on) + float t = x + y; + float v = t + z; + } + + +``#pragma clang fp contract`` specifies whether the compiler should +contract a multiply and an addition (or subtraction) into a fused FMA +operation when supported by the target. The pragma can take three values: ``on``, ``fast`` and ``off``. The ``on`` option is identical to using ``#pragma STDC FP_CONTRACT(ON)`` and it allows -fusion as specified the language standard. The ``fast`` option allows fusiong +fusion as specified the language standard. The ``fast`` option allows fusion in cases when the language standard does not make this possible (e.g. across -statements in C) +statements in C). .. code-block:: c++ diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1332,10 +1332,12 @@ "pipeline, pipeline_initiation_interval, vectorize_predicate, or distribute">; def err_pragma_fp_invalid_option : Error< - "%select{invalid|missing}0 option%select{ %1|}0; expected contract">; + "%select{invalid|missing}0 option%select{ %1|}0; expected 'contract' or 'reassociate'">; def err_pragma_fp_invalid_argument : Error< "unexpected argument '%0' to '#pragma clang fp %1'; " - "expected 'on', 'fast' or 'off'">; + "%select{" + "expected 'fast' or 'on' or 'off'|" + "expected 'on' or 'off'}2">; def err_pragma_invalid_keyword : Error< "invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -174,22 +174,15 @@ Swift4_1, }; - enum FPContractModeKind { - // Form fused FP ops only where result will not be affected. - FPC_Off, + enum FPModeKind { + // Disable the floating point pragma + FPM_Off, - // Form fused FP ops according to FP_CONTRACT rules. - FPC_On, + // Enable the floating point pragma + FPM_On, // Aggressively fuse FP ops (E.g. FMA). - FPC_Fast - }; - - // TODO: merge FEnvAccessModeKind and FPContractModeKind - enum FEnvAccessModeKind { - FEA_Off, - - FEA_On + FPM_Fast }; /// Alias for RoundingMode::NearestTiesToEven. @@ -378,7 +371,7 @@ public: FPOptions() - : fp_contract(LangOptions::FPC_Off), fenv_access(LangOptions::FEA_Off), + : fp_contract(LangOptions::FPM_Off), fenv_access(LangOptions::FPM_Off), rounding(LangOptions::FPR_ToNearest), exceptions(LangOptions::FPE_Ignore), allow_reassoc(0), no_nans(0), no_infs(0), no_signed_zeros(0), allow_reciprocal(0), approx_func(0) {} @@ -388,7 +381,7 @@ explicit FPOptions(const LangOptions &LangOpts) : fp_contract(LangOpts.getDefaultFPContractMode()), - fenv_access(LangOptions::FEA_Off), + fenv_access(LangOptions::FPM_Off), rounding(static_cast(LangOpts.getFPRoundingMode())), exceptions(LangOpts.getFPExceptionMode()), allow_reassoc(LangOpts.FastMath || LangOpts.AllowFPReassoc), @@ -413,30 +406,26 @@ bool requiresTrailingStorage(const LangOptions &LO); bool allowFPContractWithinStatement() const { - return fp_contract == LangOptions::FPC_On; + return fp_contract == LangOptions::FPM_On; } bool allowFPContractAcrossStatement() const { - return fp_contract == LangOptions::FPC_Fast; + return fp_contract == LangOptions::FPM_Fast; } void setAllowFPContractWithinStatement() { - fp_contract = LangOptions::FPC_On; + fp_contract = LangOptions::FPM_On; } void setAllowFPContractAcrossStatement() { - fp_contract = LangOptions::FPC_Fast; + fp_contract = LangOptions::FPM_Fast; } - void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; } + void setDisallowFPContract() { fp_contract = LangOptions::FPM_Off; } - bool allowFEnvAccess() const { - return fenv_access == LangOptions::FEA_On; - } + bool allowFEnvAccess() const { return fenv_access == LangOptions::FPM_On; } - void setAllowFEnvAccess() { - fenv_access = LangOptions::FEA_On; - } + void setAllowFEnvAccess() { fenv_access = LangOptions::FPM_On; } void setFPPreciseEnabled(bool Value) { if (Value) { @@ -450,7 +439,7 @@ } } - void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; } + void setDisallowFEnvAccess() { fenv_access = LangOptions::FPM_Off; } RoundingMode getRoundingMode() const { return static_cast(rounding); @@ -500,8 +489,8 @@ /// Used with getAsOpaqueInt() to manage the float_control pragma stack. void getFromOpaqueInt(unsigned I) { - fp_contract = (static_cast(I & 3)); - fenv_access = (static_cast((I >> 2) & 1)); + fp_contract = (static_cast(I & 3)); + fenv_access = ((I >> 2) & 1); rounding = static_cast(static_cast((I >> 3) & 7)); exceptions = (static_cast((I >> 6) & 3)); allow_reassoc = ((I >> 8) & 1); @@ -520,7 +509,8 @@ unsigned fenv_access : 1; unsigned rounding : 3; unsigned exceptions : 2; - /// Allow reassociation transformations for floating-point instructions. + /// Allow reassociation transformations for floating-point instructions + /// across multiple statements. unsigned allow_reassoc : 1; /// No NaNs - Allow optimizations to assume the arguments and result /// are not NaN. If an argument is a nan, or the result would be a nan, diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -268,7 +268,7 @@ LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants") LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math") /// FP_CONTRACT mode (on/off/fast). -ENUM_LANGOPT(DefaultFPContractMode, FPContractModeKind, 2, FPC_Off, "FP contraction type") +ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type") ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type") ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9617,12 +9617,15 @@ /// ActOnPragmaFPContract - Called on well formed /// \#pragma {STDC,OPENCL} FP_CONTRACT and /// \#pragma clang fp contract - void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC); + void ActOnPragmaFPContract(LangOptions::FPModeKind FPC); + + /// Called on well formed + /// \#pragma clang fp reassociate + void ActOnPragmaFPReassociate(bool IsEnabled); /// ActOnPragmaFenvAccess - Called on well formed /// \#pragma STDC FENV_ACCESS - void ActOnPragmaFEnvAccess(SourceLocation Loc, - LangOptions::FEnvAccessModeKind FPC); + void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled); /// Called to set rounding mode for floating point operations. void setRoundingMode(llvm::RoundingMode); diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -450,15 +450,15 @@ // Set FP fusion mode. switch (LangOpts.getDefaultFPContractMode()) { - case LangOptions::FPC_Off: + case LangOptions::FPM_Off: // Preserve any contraction performed by the front-end. (Strict performs // splitting of the muladd intrinsic in the backend.) Options.AllowFPOpFusion = llvm::FPOpFusion::Standard; break; - case LangOptions::FPC_On: + case LangOptions::FPM_On: Options.AllowFPOpFusion = llvm::FPOpFusion::Standard; break; - case LangOptions::FPC_Fast: + case LangOptions::FPM_Fast: Options.AllowFPOpFusion = llvm::FPOpFusion::Fast; break; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2318,7 +2318,7 @@ Opts.AltiVec = 0; Opts.ZVector = 0; Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::None); - Opts.setDefaultFPContractMode(LangOptions::FPC_On); + Opts.setDefaultFPContractMode(LangOptions::FPM_On); Opts.NativeHalfType = 1; Opts.NativeHalfArgsAndReturns = 1; Opts.OpenCLCPlusPlus = Opts.CPlusPlus; @@ -2338,7 +2338,7 @@ Opts.CUDA = IK.getLanguage() == Language::CUDA || Opts.HIP; if (Opts.CUDA) // Set default FP_CONTRACT to FAST. - Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); + Opts.setDefaultFPContractMode(LangOptions::FPM_Fast); Opts.RenderScript = IK.getLanguage() == Language::RenderScript; if (Opts.RenderScript) { @@ -3200,11 +3200,11 @@ if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { StringRef Val = A->getValue(); if (Val == "fast") - Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); + Opts.setDefaultFPContractMode(LangOptions::FPM_Fast); else if (Val == "on") - Opts.setDefaultFPContractMode(LangOptions::FPC_On); + Opts.setDefaultFPContractMode(LangOptions::FPM_On); else if (Val == "off") - Opts.setDefaultFPContractMode(LangOptions::FPC_Off); + Opts.setDefaultFPContractMode(LangOptions::FPM_Off); else Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -640,13 +640,13 @@ static_cast( reinterpret_cast(Tok.getAnnotationValue())); - LangOptions::FPContractModeKind FPC; + LangOptions::FPModeKind FPC; switch (OOS) { case tok::OOS_ON: - FPC = LangOptions::FPC_On; + FPC = LangOptions::FPM_On; break; case tok::OOS_OFF: - FPC = LangOptions::FPC_Off; + FPC = LangOptions::FPM_Off; break; case tok::OOS_DEFAULT: FPC = getLangOpts().getDefaultFPContractMode(); @@ -679,21 +679,21 @@ static_cast( reinterpret_cast(Tok.getAnnotationValue())); - LangOptions::FEnvAccessModeKind FPC; + bool IsEnabled; switch (OOS) { case tok::OOS_ON: - FPC = LangOptions::FEA_On; + IsEnabled = true; break; case tok::OOS_OFF: - FPC = LangOptions::FEA_Off; + IsEnabled = false; break; case tok::OOS_DEFAULT: // FIXME: Add this cli option when it makes sense. - FPC = LangOptions::FEA_Off; + IsEnabled = false; break; } SourceLocation PragmaLoc = ConsumeAnnotationToken(); - Actions.ActOnPragmaFEnvAccess(PragmaLoc, FPC); + Actions.ActOnPragmaFEnvAccess(PragmaLoc, IsEnabled); } @@ -2825,7 +2825,7 @@ namespace { /// Used as the annotation value for tok::annot_pragma_fp. struct TokFPAnnotValue { - enum FlagKinds { Contract }; + enum FlagKinds { Contract, Reassociate }; enum FlagValues { On, Off, Fast }; FlagKinds FlagKind; @@ -2853,6 +2853,7 @@ llvm::StringSwitch>( OptionInfo->getName()) .Case("contract", TokFPAnnotValue::Contract) + .Case("reassociate", TokFPAnnotValue::Reassociate) .Default(None); if (!FlagKind) { PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option) @@ -2870,7 +2871,8 @@ if (Tok.isNot(tok::identifier)) { PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) - << PP.getSpelling(Tok) << OptionInfo->getName(); + << PP.getSpelling(Tok) << OptionInfo->getName() + << (FlagKind == TokFPAnnotValue::Reassociate); return; } const IdentifierInfo *II = Tok.getIdentifierInfo(); @@ -2883,9 +2885,11 @@ .Case("fast", TokFPAnnotValue::Fast) .Default(llvm::None); - if (!FlagValue) { + if (!FlagValue || (FlagKind == TokFPAnnotValue::Reassociate && + FlagValue == TokFPAnnotValue::Fast)) { PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) - << PP.getSpelling(Tok) << OptionInfo->getName(); + << PP.getSpelling(Tok) << OptionInfo->getName() + << (FlagKind == TokFPAnnotValue::Reassociate); return; } PP.Lex(Tok); @@ -2927,20 +2931,24 @@ auto *AnnotValue = reinterpret_cast(Tok.getAnnotationValue()); - LangOptions::FPContractModeKind FPC; - switch (AnnotValue->FlagValue) { - case TokFPAnnotValue::On: - FPC = LangOptions::FPC_On; - break; - case TokFPAnnotValue::Fast: - FPC = LangOptions::FPC_Fast; - break; - case TokFPAnnotValue::Off: - FPC = LangOptions::FPC_Off; - break; + if (AnnotValue->FlagKind == TokFPAnnotValue::Reassociate) + Actions.ActOnPragmaFPReassociate(AnnotValue->FlagValue == + TokFPAnnotValue::On); + else { + LangOptions::FPModeKind FPC; + switch (AnnotValue->FlagValue) { + case TokFPAnnotValue::Off: + FPC = LangOptions::FPM_Off; + break; + case TokFPAnnotValue::On: + FPC = LangOptions::FPM_On; + break; + case TokFPAnnotValue::Fast: + FPC = LangOptions::FPM_Fast; + break; + } + Actions.ActOnPragmaFPContract(FPC); } - - Actions.ActOnPragmaFPContract(FPC); ConsumeAnnotationToken(); } diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -985,20 +985,24 @@ } } -void Sema::ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC) { +void Sema::ActOnPragmaFPContract(LangOptions::FPModeKind FPC) { switch (FPC) { - case LangOptions::FPC_On: + case LangOptions::FPM_On: CurFPFeatures.setAllowFPContractWithinStatement(); break; - case LangOptions::FPC_Fast: + case LangOptions::FPM_Fast: CurFPFeatures.setAllowFPContractAcrossStatement(); break; - case LangOptions::FPC_Off: + case LangOptions::FPM_Off: CurFPFeatures.setDisallowFPContract(); break; } } +void Sema::ActOnPragmaFPReassociate(bool IsEnabled) { + CurFPFeatures.setAllowAssociativeMath(IsEnabled); +} + void Sema::setRoundingMode(llvm::RoundingMode FPR) { CurFPFeatures.setRoundingMode(FPR); } @@ -1007,10 +1011,8 @@ CurFPFeatures.setExceptionMode(FPE); } -void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, - LangOptions::FEnvAccessModeKind FPC) { - switch (FPC) { - case LangOptions::FEA_On: +void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) { + if (IsEnabled) { // Verify Microsoft restriction: // You can't enable fenv_access unless precise semantics are enabled. // Precise semantics can be enabled either by the float_control @@ -1018,11 +1020,8 @@ if (!isPreciseFPEnabled()) Diag(Loc, diag::err_pragma_fenv_requires_precise); CurFPFeatures.setAllowFEnvAccess(); - break; - case LangOptions::FEA_Off: + } else CurFPFeatures.setDisallowFEnvAccess(); - break; - } } void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, diff --git a/clang/test/CodeGen/fp-reassoc-pragma.cpp b/clang/test/CodeGen/fp-reassoc-pragma.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/fp-reassoc-pragma.cpp @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s +// Simple case +float fp_reassoc_simple(float a, float b, float c) { +// CHECK: _Z17fp_reassoc_simplefff +// CHECK: %[[A:.+]] = fadd reassoc float %b, %c +// CHECK: %[[M:.+]] = fmul reassoc float %[[A]], %b +// CHECK-NEXT: fadd reassoc float %[[M]], %c +#pragma clang fp reassociate(on) + a = b + c; + return a * b + c; +} + +// Reassoc pragma should only apply to its scope +float fp_reassoc_scoped(float a, float b, float c) { + // CHECK: _Z17fp_reassoc_scopedfff + // CHECK: %[[M:.+]] = fmul float %a, %b + // CHECK-NEXT: fadd float %[[M]], %c + { +#pragma clang fp reassociate(on) + } + return a * b + c; +} + +// Reassoc pragma should apply to templates as well +class Foo {}; +Foo operator+(Foo, Foo); +template +T template_reassoc(T a, T b, T c) { +#pragma clang fp reassociate(on) + return ((a + b) - c) + c; +} + +float fp_reassoc_template(float a, float b, float c) { + // CHECK: _Z19fp_reassoc_templatefff + // CHECK: %[[A1:.+]] = fadd reassoc float %a, %b + // CHECK-NEXT: %[[A2:.+]] = fsub reassoc float %[[A1]], %c + // CHECK-NEXT: fadd reassoc float %[[A2]], %c + return template_reassoc(a, b, c); +} + +// File Scoping should work across functions +#pragma clang fp reassociate(on) +float fp_file_scope_on(float a, float b, float c) { + // CHECK: _Z16fp_file_scope_onfff + // CHECK: %[[M1:.+]] = fmul reassoc float %a, %c + // CHECK-NEXT: %[[M2:.+]] = fmul reassoc float %b, %c + // CHECK-NEXT: fadd reassoc float %[[M1]], %[[M2]] + return (a * c) + (b * c); +} + +// Inner pragma has precedence +float fp_file_scope_stop(float a, float b, float c) { + // CHECK: _Z18fp_file_scope_stopfff + // CHECK: %[[A:.+]] = fadd reassoc float %a, %a + // CHECK: %[[M1:.+]] = fmul float %[[A]], %c + // CHECK-NEXT: %[[M2:.+]] = fmul float %b, %c + // CHECK-NEXT: fsub float %[[M1]], %[[M2]] + a = a + a; + { +#pragma clang fp reassociate(off) + return (a * c) - (b * c); + } +} + +#pragma clang fp reassociate(off) +float fp_reassoc_off(float a, float b, float c) { + // CHECK: _Z14fp_reassoc_offfff + // CHECK: %[[D1:.+]] = fdiv float %a, %c + // CHECK-NEXT: %[[D2:.+]] = fdiv float %b, %c + // CHECK-NEXT: fadd float %[[D1]], %[[D2]] + return (a / c) + (b / c); +} + +// Takes latest flag +float fp_reassoc_many(float a, float b, float c) { +// CHECK: _Z15fp_reassoc_manyfff +// CHECK: %[[D1:.+]] = fdiv reassoc float %a, %c +// CHECK-NEXT: %[[D2:.+]] = fdiv reassoc float %b, %c +// CHECK-NEXT: fadd reassoc float %[[D1]], %[[D2]] +#pragma clang fp reassociate(off) reassociate(on) + return (a / c) + (b / c); +} + +// Pragma does not propagate through called functions +float helper_func(float a, float b, float c) { return a + b + c; } +float fp_reassoc_call_helper(float a, float b, float c) { +// CHECK: _Z22fp_reassoc_call_helperfff +// CHECK: %[[S1:.+]] = fadd float %a, %b +// CHECK-NEXT: fadd float %[[S1]], %c +#pragma clang fp reassociate(on) + return helper_func(a, b, c); +} diff --git a/clang/test/Parser/pragma-fp-contract.c b/clang/test/Parser/pragma-fp-contract.c --- a/clang/test/Parser/pragma-fp-contract.c +++ b/clang/test/Parser/pragma-fp-contract.c @@ -23,3 +23,18 @@ // expected-error@+1 {{this pragma cannot appear in union declaration}} #pragma STDC FP_CONTRACT ON }; + +float fp_reassoc_fail(float a, float b) { + // CHECK-LABEL: fp_reassoc_fail + // expected-error@+2{{'#pragma clang fp' can only appear at file scope or at the start of a compound statement}} + float c = a + b; +#pragma clang fp reassociate(off) + return c - b; +} + +float fp_reassoc_no_fast(float a, float b) { +// CHECK-LABEL: fp_reassoc_no_fast +// expected-error@+1{{unexpected argument 'fast' to '#pragma clang fp reassociate'; expected 'on' or 'off'}} +#pragma clang fp reassociate(fast) + return a - b; +} diff --git a/clang/test/Parser/pragma-fp.cpp b/clang/test/Parser/pragma-fp.cpp --- a/clang/test/Parser/pragma-fp.cpp +++ b/clang/test/Parser/pragma-fp.cpp @@ -1,14 +1,14 @@ // RUN: %clang_cc1 -std=c++11 -verify %s void test_0(int *List, int Length) { -/* expected-error@+1 {{missing option; expected contract}} */ +/* expected-error@+1 {{missing option; expected 'contract' or 'reassociate'}} */ #pragma clang fp for (int i = 0; i < Length; i++) { List[i] = i; } } void test_1(int *List, int Length) { -/* expected-error@+1 {{invalid option 'blah'; expected contract}} */ +/* expected-error@+1 {{invalid option 'blah'; expected 'contract' or 'reassociate'}} */ #pragma clang fp blah for (int i = 0; i < Length; i++) { List[i] = i; @@ -24,7 +24,7 @@ } void test_4(int *List, int Length) { -/* expected-error@+1 {{unexpected argument 'while' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */ +/* expected-error@+1 {{unexpected argument 'while' to '#pragma clang fp contract'; expected 'fast' or 'on' or 'off'}} */ #pragma clang fp contract(while) for (int i = 0; i < Length; i++) { List[i] = i; @@ -32,7 +32,7 @@ } void test_5(int *List, int Length) { -/* expected-error@+1 {{unexpected argument 'maybe' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */ +/* expected-error@+1 {{unexpected argument 'maybe' to '#pragma clang fp contract'; expected 'fast' or 'on' or 'off'}} */ #pragma clang fp contract(maybe) for (int i = 0; i < Length; i++) { List[i] = i;