[clang] c355bec - Add support for #pragma clang fp reassociate(on|off)
Melanie Blower via cfe-commits
cfe-commits at lists.llvm.org
Wed May 6 08:06:02 PDT 2020
Author: Melanie Blower
Date: 2020-05-06T08:05:44-07:00
New Revision: c355bec749e94c601a42e435f6c98b956f3965ac
URL: https://github.com/llvm/llvm-project/commit/c355bec749e94c601a42e435f6c98b956f3965ac
DIFF: https://github.com/llvm/llvm-project/commit/c355bec749e94c601a42e435f6c98b956f3965ac.diff
LOG: Add support for #pragma clang fp reassociate(on|off)
Reviewers: rjmccall, erichkeane, sepavloff
Differential Revision: https://reviews.llvm.org/D78827
Added:
clang/test/CodeGen/fp-reassoc-pragma.cpp
Modified:
clang/docs/LanguageExtensions.rst
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Sema/Sema.h
clang/lib/CodeGen/BackendUtil.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Parse/ParsePragma.cpp
clang/lib/Sema/SemaAttr.cpp
clang/test/Parser/pragma-fp-contract.c
clang/test/Parser/pragma-fp.cpp
Removed:
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 1c753ea0e569..2fbf5ea5eb01 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3173,16 +3173,36 @@ at the start of a compound statement (excluding comments). When using within a
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
index 9400a87c0ef3..552c9187e705 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1332,10 +1332,12 @@ def err_pragma_loop_invalid_option : Error<
"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.def b/clang/include/clang/Basic/LangOptions.def
index 289f9c3f50e2..02f67636d03d 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -268,7 +268,7 @@ BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
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/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index f69553e5d13e..bee463a0f890 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -174,22 +174,15 @@ class LangOptions : public LangOptionsBase {
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 @@ class FPOptions {
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 @@ class FPOptions {
explicit FPOptions(const LangOptions &LangOpts)
: fp_contract(LangOpts.getDefaultFPContractMode()),
- fenv_access(LangOptions::FEA_Off),
+ fenv_access(LangOptions::FPM_Off),
rounding(static_cast<unsigned>(LangOpts.getFPRoundingMode())),
exceptions(LangOpts.getFPExceptionMode()),
allow_reassoc(LangOpts.FastMath || LangOpts.AllowFPReassoc),
@@ -413,30 +406,26 @@ class FPOptions {
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 @@ class FPOptions {
}
}
- void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; }
+ void setDisallowFEnvAccess() { fenv_access = LangOptions::FPM_Off; }
RoundingMode getRoundingMode() const {
return static_cast<RoundingMode>(rounding);
@@ -500,8 +489,8 @@ class FPOptions {
/// Used with getAsOpaqueInt() to manage the float_control pragma stack.
void getFromOpaqueInt(unsigned I) {
- fp_contract = (static_cast<LangOptions::FPContractModeKind>(I & 3));
- fenv_access = (static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1));
+ fp_contract = (static_cast<LangOptions::FPModeKind>(I & 3));
+ fenv_access = ((I >> 2) & 1);
rounding = static_cast<unsigned>(static_cast<RoundingMode>((I >> 3) & 7));
exceptions = (static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3));
allow_reassoc = ((I >> 8) & 1);
@@ -520,7 +509,8 @@ class FPOptions {
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/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index eee86dcdea36..4d6e94df0b4d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9617,12 +9617,15 @@ class Sema final {
/// 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
index 87d5ebe853d8..1abd36080910 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -450,15 +450,15 @@ static void initTargetOptions(llvm::TargetOptions &Options,
// 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
index 35c58da53a55..18872f9586ab 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2318,7 +2318,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
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 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
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 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
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
index 5741c9ff1e11..8adf978a8e13 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -640,13 +640,13 @@ void Parser::HandlePragmaFPContract() {
static_cast<tok::OnOffSwitch>(
reinterpret_cast<uintptr_t>(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 @@ void Parser::HandlePragmaFEnvAccess() {
static_cast<tok::OnOffSwitch>(
reinterpret_cast<uintptr_t>(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 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
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 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>(
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 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
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 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
.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 @@ void Parser::HandlePragmaFP() {
auto *AnnotValue =
reinterpret_cast<TokFPAnnotValue *>(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
index 518ac0f070c1..50089dea7759 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -985,20 +985,24 @@ void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
}
}
-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 @@ void Sema::setExceptionMode(LangOptions::FPExceptionModeKind FPE) {
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 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc,
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
index 000000000000..0cf2f812e66e
--- /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 <typename T>
+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<float>(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
index aa25dcdf538e..3230a23792af 100644
--- a/clang/test/Parser/pragma-fp-contract.c
+++ b/clang/test/Parser/pragma-fp-contract.c
@@ -23,3 +23,18 @@ union U1 {
// expected-error at +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 at +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 at +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
index 00547bfb546a..400cafb29de8 100644
--- 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 at +1 {{missing option; expected contract}} */
+/* expected-error at +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 at +1 {{invalid option 'blah'; expected contract}} */
+/* expected-error at +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_3(int *List, int Length) {
}
void test_4(int *List, int Length) {
-/* expected-error at +1 {{unexpected argument 'while' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+/* expected-error at +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_4(int *List, int Length) {
}
void test_5(int *List, int Length) {
-/* expected-error at +1 {{unexpected argument 'maybe' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+/* expected-error at +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;
More information about the cfe-commits
mailing list