Re: [PATCH] c-family: implement -ffp-contract=on
> Am 19.06.2023 um 19:03 schrieb Alexander Monakov : > > > Ping. OK for trunk? Ok if the FE maintainers do not object within 48h. Thanks, Richard >> On Mon, 5 Jun 2023, Alexander Monakov wrote: >> >> Ping for the front-end maintainers' input. >> >>> On Mon, 22 May 2023, Richard Biener wrote: >>> >>> On Thu, May 18, 2023 at 11:04 PM Alexander Monakov via Gcc-patches >>> wrote: Implement -ffp-contract=on for C and C++ without changing default behavior (=off for -std=cNN, =fast for C++ and -std=gnuNN). >>> >>> The documentation changes mention the defaults are changed for >>> standard modes, I suppose you want to remove that hunk. >>> gcc/c-family/ChangeLog: * c-gimplify.cc (fma_supported_p): New helper. (c_gimplify_expr) [PLUS_EXPR, MINUS_EXPR]: Implement FMA contraction. gcc/ChangeLog: * common.opt (fp_contract_mode) [on]: Remove fallback. * config/sh/sh.md (*fmasf4): Correct flag_fp_contract_mode test. * doc/invoke.texi (-ffp-contract): Update. * trans-mem.cc (diagnose_tm_1): Skip internal function calls. --- gcc/c-family/c-gimplify.cc | 78 ++ gcc/common.opt | 3 +- gcc/config/sh/sh.md| 2 +- gcc/doc/invoke.texi| 8 ++-- gcc/trans-mem.cc | 3 ++ 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc index ef5c7d919f..f7635d3b0c 100644 --- a/gcc/c-family/c-gimplify.cc +++ b/gcc/c-family/c-gimplify.cc @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see #include "c-ubsan.h" #include "tree-nested.h" #include "context.h" +#include "tree-pass.h" +#include "internal-fn.h" /* The gimplification pass converts the language-dependent trees (ld-trees) emitted by the parser into language-independent trees @@ -686,6 +688,14 @@ c_build_bind_expr (location_t loc, tree block, tree body) return bind; } +/* Helper for c_gimplify_expr: test if target supports fma-like FN. */ + +static bool +fma_supported_p (enum internal_fn fn, tree type) +{ + return direct_internal_fn_supported_p (fn, type, OPTIMIZE_FOR_BOTH); +} + /* Gimplification of expression trees. */ /* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in @@ -739,6 +749,74 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED, break; } +case PLUS_EXPR: +case MINUS_EXPR: + { + tree type = TREE_TYPE (*expr_p); + /* For -ffp-contract=on we need to attempt FMA contraction only + during initial gimplification. Late contraction across statement + boundaries would violate language semantics. */ + if (SCALAR_FLOAT_TYPE_P (type) + && flag_fp_contract_mode == FP_CONTRACT_ON + && cfun && !(cfun->curr_properties & PROP_gimple_any) + && fma_supported_p (IFN_FMA, type)) + { + bool neg_mul = false, neg_add = code == MINUS_EXPR; + + tree *op0_p = &TREE_OPERAND (*expr_p, 0); + tree *op1_p = &TREE_OPERAND (*expr_p, 1); + + /* Look for ±(x * y) ± z, swapping operands if necessary. */ + if (TREE_CODE (*op0_p) == NEGATE_EXPR + && TREE_CODE (TREE_OPERAND (*op0_p, 0)) == MULT_EXPR) + /* '*EXPR_P' is '-(x * y) ± z'. This is fine. */; + else if (TREE_CODE (*op0_p) != MULT_EXPR) + { + std::swap (op0_p, op1_p); + std::swap (neg_mul, neg_add); + } + if (TREE_CODE (*op0_p) == NEGATE_EXPR) + { + op0_p = &TREE_OPERAND (*op0_p, 0); + neg_mul = !neg_mul; + } + if (TREE_CODE (*op0_p) != MULT_EXPR) + break; + auto_vec ops (3); + ops.quick_push (TREE_OPERAND (*op0_p, 0)); + ops.quick_push (TREE_OPERAND (*op0_p, 1)); + ops.quick_push (*op1_p); + + enum internal_fn ifn = IFN_FMA; + if (neg_mul) + { + if (fma_supported_p (IFN_FNMA, type)) + ifn = IFN_FNMA; + else + ops[0] = build1 (NEGATE_EXPR, type, ops[0]); + } + if (neg_add) + { + enum internal_fn ifn2 = ifn == IFN_FMA ? IFN_FMS : IFN_FNMS; + if (fma_supported_p (ifn2, type)) + ifn = ifn2; + else
Re: [PATCH] c-family: implement -ffp-contract=on
Ping. OK for trunk? On Mon, 5 Jun 2023, Alexander Monakov wrote: > Ping for the front-end maintainers' input. > > On Mon, 22 May 2023, Richard Biener wrote: > > > On Thu, May 18, 2023 at 11:04 PM Alexander Monakov via Gcc-patches > > wrote: > > > > > > Implement -ffp-contract=on for C and C++ without changing default > > > behavior (=off for -std=cNN, =fast for C++ and -std=gnuNN). > > > > The documentation changes mention the defaults are changed for > > standard modes, I suppose you want to remove that hunk. > > > > > gcc/c-family/ChangeLog: > > > > > > * c-gimplify.cc (fma_supported_p): New helper. > > > (c_gimplify_expr) [PLUS_EXPR, MINUS_EXPR]: Implement FMA > > > contraction. > > > > > > gcc/ChangeLog: > > > > > > * common.opt (fp_contract_mode) [on]: Remove fallback. > > > * config/sh/sh.md (*fmasf4): Correct flag_fp_contract_mode test. > > > * doc/invoke.texi (-ffp-contract): Update. > > > * trans-mem.cc (diagnose_tm_1): Skip internal function calls. > > > --- > > > gcc/c-family/c-gimplify.cc | 78 ++ > > > gcc/common.opt | 3 +- > > > gcc/config/sh/sh.md| 2 +- > > > gcc/doc/invoke.texi| 8 ++-- > > > gcc/trans-mem.cc | 3 ++ > > > 5 files changed, 88 insertions(+), 6 deletions(-) > > > > > > diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc > > > index ef5c7d919f..f7635d3b0c 100644 > > > --- a/gcc/c-family/c-gimplify.cc > > > +++ b/gcc/c-family/c-gimplify.cc > > > @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see > > > #include "c-ubsan.h" > > > #include "tree-nested.h" > > > #include "context.h" > > > +#include "tree-pass.h" > > > +#include "internal-fn.h" > > > > > > /* The gimplification pass converts the language-dependent trees > > > (ld-trees) emitted by the parser into language-independent trees > > > @@ -686,6 +688,14 @@ c_build_bind_expr (location_t loc, tree block, tree > > > body) > > >return bind; > > > } > > > > > > +/* Helper for c_gimplify_expr: test if target supports fma-like FN. */ > > > + > > > +static bool > > > +fma_supported_p (enum internal_fn fn, tree type) > > > +{ > > > + return direct_internal_fn_supported_p (fn, type, OPTIMIZE_FOR_BOTH); > > > +} > > > + > > > /* Gimplification of expression trees. */ > > > > > > /* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in > > > @@ -739,6 +749,74 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p > > > ATTRIBUTE_UNUSED, > > > break; > > >} > > > > > > +case PLUS_EXPR: > > > +case MINUS_EXPR: > > > + { > > > + tree type = TREE_TYPE (*expr_p); > > > + /* For -ffp-contract=on we need to attempt FMA contraction only > > > + during initial gimplification. Late contraction across > > > statement > > > + boundaries would violate language semantics. */ > > > + if (SCALAR_FLOAT_TYPE_P (type) > > > + && flag_fp_contract_mode == FP_CONTRACT_ON > > > + && cfun && !(cfun->curr_properties & PROP_gimple_any) > > > + && fma_supported_p (IFN_FMA, type)) > > > + { > > > + bool neg_mul = false, neg_add = code == MINUS_EXPR; > > > + > > > + tree *op0_p = &TREE_OPERAND (*expr_p, 0); > > > + tree *op1_p = &TREE_OPERAND (*expr_p, 1); > > > + > > > + /* Look for ±(x * y) ± z, swapping operands if necessary. */ > > > + if (TREE_CODE (*op0_p) == NEGATE_EXPR > > > + && TREE_CODE (TREE_OPERAND (*op0_p, 0)) == MULT_EXPR) > > > + /* '*EXPR_P' is '-(x * y) ± z'. This is fine. */; > > > + else if (TREE_CODE (*op0_p) != MULT_EXPR) > > > + { > > > + std::swap (op0_p, op1_p); > > > + std::swap (neg_mul, neg_add); > > > + } > > > + if (TREE_CODE (*op0_p) == NEGATE_EXPR) > > > + { > > > + op0_p = &TREE_OPERAND (*op0_p, 0); > > > + neg_mul = !neg_mul; > > > + } > > > + if (TREE_CODE (*op0_p) != MULT_EXPR) > > > + break; > > > + auto_vec ops (3); > > > + ops.quick_push (TREE_OPERAND (*op0_p, 0)); > > > + ops.quick_push (TREE_OPERAND (*op0_p, 1)); > > > + ops.quick_push (*op1_p); > > > + > > > + enum internal_fn ifn = IFN_FMA; > > > + if (neg_mul) > > > + { > > > + if (fma_supported_p (IFN_FNMA, type)) > > > + ifn = IFN_FNMA; > > > + else > > > + ops[0] = build1 (NEGATE_EXPR, type, ops[0]); > > > + } > > > + if (neg_add) > > > + { > > > + enum internal_fn ifn2 = ifn == IFN_FMA ? IFN_FMS : > > > IFN_FNMS; > > > + if (fma_supported_p (ifn2, type)) > > > + ifn = ifn2; > > > + else > > > +
Re: [PATCH] c-family: implement -ffp-contract=on
Ping for the front-end maintainers' input. On Mon, 22 May 2023, Richard Biener wrote: > On Thu, May 18, 2023 at 11:04 PM Alexander Monakov via Gcc-patches > wrote: > > > > Implement -ffp-contract=on for C and C++ without changing default > > behavior (=off for -std=cNN, =fast for C++ and -std=gnuNN). > > The documentation changes mention the defaults are changed for > standard modes, I suppose you want to remove that hunk. > > > gcc/c-family/ChangeLog: > > > > * c-gimplify.cc (fma_supported_p): New helper. > > (c_gimplify_expr) [PLUS_EXPR, MINUS_EXPR]: Implement FMA > > contraction. > > > > gcc/ChangeLog: > > > > * common.opt (fp_contract_mode) [on]: Remove fallback. > > * config/sh/sh.md (*fmasf4): Correct flag_fp_contract_mode test. > > * doc/invoke.texi (-ffp-contract): Update. > > * trans-mem.cc (diagnose_tm_1): Skip internal function calls. > > --- > > gcc/c-family/c-gimplify.cc | 78 ++ > > gcc/common.opt | 3 +- > > gcc/config/sh/sh.md| 2 +- > > gcc/doc/invoke.texi| 8 ++-- > > gcc/trans-mem.cc | 3 ++ > > 5 files changed, 88 insertions(+), 6 deletions(-) > > > > diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc > > index ef5c7d919f..f7635d3b0c 100644 > > --- a/gcc/c-family/c-gimplify.cc > > +++ b/gcc/c-family/c-gimplify.cc > > @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see > > #include "c-ubsan.h" > > #include "tree-nested.h" > > #include "context.h" > > +#include "tree-pass.h" > > +#include "internal-fn.h" > > > > /* The gimplification pass converts the language-dependent trees > > (ld-trees) emitted by the parser into language-independent trees > > @@ -686,6 +688,14 @@ c_build_bind_expr (location_t loc, tree block, tree > > body) > >return bind; > > } > > > > +/* Helper for c_gimplify_expr: test if target supports fma-like FN. */ > > + > > +static bool > > +fma_supported_p (enum internal_fn fn, tree type) > > +{ > > + return direct_internal_fn_supported_p (fn, type, OPTIMIZE_FOR_BOTH); > > +} > > + > > /* Gimplification of expression trees. */ > > > > /* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in > > @@ -739,6 +749,74 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p > > ATTRIBUTE_UNUSED, > > break; > >} > > > > +case PLUS_EXPR: > > +case MINUS_EXPR: > > + { > > + tree type = TREE_TYPE (*expr_p); > > + /* For -ffp-contract=on we need to attempt FMA contraction only > > + during initial gimplification. Late contraction across statement > > + boundaries would violate language semantics. */ > > + if (SCALAR_FLOAT_TYPE_P (type) > > + && flag_fp_contract_mode == FP_CONTRACT_ON > > + && cfun && !(cfun->curr_properties & PROP_gimple_any) > > + && fma_supported_p (IFN_FMA, type)) > > + { > > + bool neg_mul = false, neg_add = code == MINUS_EXPR; > > + > > + tree *op0_p = &TREE_OPERAND (*expr_p, 0); > > + tree *op1_p = &TREE_OPERAND (*expr_p, 1); > > + > > + /* Look for ±(x * y) ± z, swapping operands if necessary. */ > > + if (TREE_CODE (*op0_p) == NEGATE_EXPR > > + && TREE_CODE (TREE_OPERAND (*op0_p, 0)) == MULT_EXPR) > > + /* '*EXPR_P' is '-(x * y) ± z'. This is fine. */; > > + else if (TREE_CODE (*op0_p) != MULT_EXPR) > > + { > > + std::swap (op0_p, op1_p); > > + std::swap (neg_mul, neg_add); > > + } > > + if (TREE_CODE (*op0_p) == NEGATE_EXPR) > > + { > > + op0_p = &TREE_OPERAND (*op0_p, 0); > > + neg_mul = !neg_mul; > > + } > > + if (TREE_CODE (*op0_p) != MULT_EXPR) > > + break; > > + auto_vec ops (3); > > + ops.quick_push (TREE_OPERAND (*op0_p, 0)); > > + ops.quick_push (TREE_OPERAND (*op0_p, 1)); > > + ops.quick_push (*op1_p); > > + > > + enum internal_fn ifn = IFN_FMA; > > + if (neg_mul) > > + { > > + if (fma_supported_p (IFN_FNMA, type)) > > + ifn = IFN_FNMA; > > + else > > + ops[0] = build1 (NEGATE_EXPR, type, ops[0]); > > + } > > + if (neg_add) > > + { > > + enum internal_fn ifn2 = ifn == IFN_FMA ? IFN_FMS : IFN_FNMS; > > + if (fma_supported_p (ifn2, type)) > > + ifn = ifn2; > > + else > > + ops[2] = build1 (NEGATE_EXPR, type, ops[2]); > > + } > > + for (auto &&op : ops) > > + if (gimplify_expr (&op, pre_p, post_p, is_gimple_val, > > fb_rvalue) > > + == GS_ERROR) > > + return GS_ERROR; > > + > > + gcall *call = gimple_build_call_inter
Re: [PATCH] c-family: implement -ffp-contract=on
On Tue, 23 May 2023, Richard Biener wrote: > > Ah, no, I deliberately decided against that, because that way we would go > > via gimplify_arg, which would emit all side effects in *pre_p. That seems > > wrong if arguments had side-effects that should go in *post_p. > > Ah, true - that warrants a comment though. Incrementally fixed up in my tree like this: diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc index f7635d3b0c..17b0610a89 100644 --- a/gcc/c-family/c-gimplify.cc +++ b/gcc/c-family/c-gimplify.cc @@ -803,6 +803,7 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED, else ops[2] = build1 (NEGATE_EXPR, type, ops[2]); } + /* Avoid gimplify_arg: it emits all side effects into *PRE_P. */ for (auto &&op : ops) if (gimplify_expr (&op, pre_p, post_p, is_gimple_val, fb_rvalue) == GS_ERROR) Alexander
Re: [PATCH] c-family: implement -ffp-contract=on
On Mon, May 22, 2023 at 5:16 PM Alexander Monakov wrote: > > > On Mon, 22 May 2023, Richard Biener wrote: > > > On Thu, May 18, 2023 at 11:04 PM Alexander Monakov via Gcc-patches > > wrote: > > > > > > Implement -ffp-contract=on for C and C++ without changing default > > > behavior (=off for -std=cNN, =fast for C++ and -std=gnuNN). > > > > The documentation changes mention the defaults are changed for > > standard modes, I suppose you want to remove that hunk. > > No, the current documentation is incomplete, and that hunk extends it > to match the current GCC behavior. Should I break it out to a separate > patch? I see this drive-by fix could look confusing — sorry about that. > > > it would be possible to do > > > > *expr_p = build_call_expr_internal (ifn, type, ops[0], ops[1]. ops[2]); > > return GS_OK; > > > > and not worry about temporary creation and gimplifying of the operands. > > That would in theory also leave the possibility to do this during > > genericization instead (and avoid the guard against late invocation of > > the hook). > > Ah, no, I deliberately decided against that, because that way we would go > via gimplify_arg, which would emit all side effects in *pre_p. That seems > wrong if arguments had side-effects that should go in *post_p. Ah, true - that warrants a comment though. Richard. > > Thanks. > Alexander > > > Otherwise it looks OK, but I'll let frontend maintainers have a chance to > > look > > as well. > > > > Thanks for tackling this long-standing issue. > > Richard.
Re: [PATCH] c-family: implement -ffp-contract=on
On Mon, 22 May 2023, Richard Biener wrote: > On Thu, May 18, 2023 at 11:04 PM Alexander Monakov via Gcc-patches > wrote: > > > > Implement -ffp-contract=on for C and C++ without changing default > > behavior (=off for -std=cNN, =fast for C++ and -std=gnuNN). > > The documentation changes mention the defaults are changed for > standard modes, I suppose you want to remove that hunk. No, the current documentation is incomplete, and that hunk extends it to match the current GCC behavior. Should I break it out to a separate patch? I see this drive-by fix could look confusing — sorry about that. > it would be possible to do > > *expr_p = build_call_expr_internal (ifn, type, ops[0], ops[1]. ops[2]); > return GS_OK; > > and not worry about temporary creation and gimplifying of the operands. > That would in theory also leave the possibility to do this during > genericization instead (and avoid the guard against late invocation of > the hook). Ah, no, I deliberately decided against that, because that way we would go via gimplify_arg, which would emit all side effects in *pre_p. That seems wrong if arguments had side-effects that should go in *post_p. Thanks. Alexander > Otherwise it looks OK, but I'll let frontend maintainers have a chance to look > as well. > > Thanks for tackling this long-standing issue. > Richard.
Re: [PATCH] c-family: implement -ffp-contract=on
On Thu, May 18, 2023 at 11:04 PM Alexander Monakov via Gcc-patches wrote: > > Implement -ffp-contract=on for C and C++ without changing default > behavior (=off for -std=cNN, =fast for C++ and -std=gnuNN). The documentation changes mention the defaults are changed for standard modes, I suppose you want to remove that hunk. > gcc/c-family/ChangeLog: > > * c-gimplify.cc (fma_supported_p): New helper. > (c_gimplify_expr) [PLUS_EXPR, MINUS_EXPR]: Implement FMA > contraction. > > gcc/ChangeLog: > > * common.opt (fp_contract_mode) [on]: Remove fallback. > * config/sh/sh.md (*fmasf4): Correct flag_fp_contract_mode test. > * doc/invoke.texi (-ffp-contract): Update. > * trans-mem.cc (diagnose_tm_1): Skip internal function calls. > --- > gcc/c-family/c-gimplify.cc | 78 ++ > gcc/common.opt | 3 +- > gcc/config/sh/sh.md| 2 +- > gcc/doc/invoke.texi| 8 ++-- > gcc/trans-mem.cc | 3 ++ > 5 files changed, 88 insertions(+), 6 deletions(-) > > diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc > index ef5c7d919f..f7635d3b0c 100644 > --- a/gcc/c-family/c-gimplify.cc > +++ b/gcc/c-family/c-gimplify.cc > @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see > #include "c-ubsan.h" > #include "tree-nested.h" > #include "context.h" > +#include "tree-pass.h" > +#include "internal-fn.h" > > /* The gimplification pass converts the language-dependent trees > (ld-trees) emitted by the parser into language-independent trees > @@ -686,6 +688,14 @@ c_build_bind_expr (location_t loc, tree block, tree body) >return bind; > } > > +/* Helper for c_gimplify_expr: test if target supports fma-like FN. */ > + > +static bool > +fma_supported_p (enum internal_fn fn, tree type) > +{ > + return direct_internal_fn_supported_p (fn, type, OPTIMIZE_FOR_BOTH); > +} > + > /* Gimplification of expression trees. */ > > /* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in > @@ -739,6 +749,74 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p > ATTRIBUTE_UNUSED, > break; >} > > +case PLUS_EXPR: > +case MINUS_EXPR: > + { > + tree type = TREE_TYPE (*expr_p); > + /* For -ffp-contract=on we need to attempt FMA contraction only > + during initial gimplification. Late contraction across statement > + boundaries would violate language semantics. */ > + if (SCALAR_FLOAT_TYPE_P (type) > + && flag_fp_contract_mode == FP_CONTRACT_ON > + && cfun && !(cfun->curr_properties & PROP_gimple_any) > + && fma_supported_p (IFN_FMA, type)) > + { > + bool neg_mul = false, neg_add = code == MINUS_EXPR; > + > + tree *op0_p = &TREE_OPERAND (*expr_p, 0); > + tree *op1_p = &TREE_OPERAND (*expr_p, 1); > + > + /* Look for ±(x * y) ± z, swapping operands if necessary. */ > + if (TREE_CODE (*op0_p) == NEGATE_EXPR > + && TREE_CODE (TREE_OPERAND (*op0_p, 0)) == MULT_EXPR) > + /* '*EXPR_P' is '-(x * y) ± z'. This is fine. */; > + else if (TREE_CODE (*op0_p) != MULT_EXPR) > + { > + std::swap (op0_p, op1_p); > + std::swap (neg_mul, neg_add); > + } > + if (TREE_CODE (*op0_p) == NEGATE_EXPR) > + { > + op0_p = &TREE_OPERAND (*op0_p, 0); > + neg_mul = !neg_mul; > + } > + if (TREE_CODE (*op0_p) != MULT_EXPR) > + break; > + auto_vec ops (3); > + ops.quick_push (TREE_OPERAND (*op0_p, 0)); > + ops.quick_push (TREE_OPERAND (*op0_p, 1)); > + ops.quick_push (*op1_p); > + > + enum internal_fn ifn = IFN_FMA; > + if (neg_mul) > + { > + if (fma_supported_p (IFN_FNMA, type)) > + ifn = IFN_FNMA; > + else > + ops[0] = build1 (NEGATE_EXPR, type, ops[0]); > + } > + if (neg_add) > + { > + enum internal_fn ifn2 = ifn == IFN_FMA ? IFN_FMS : IFN_FNMS; > + if (fma_supported_p (ifn2, type)) > + ifn = ifn2; > + else > + ops[2] = build1 (NEGATE_EXPR, type, ops[2]); > + } > + for (auto &&op : ops) > + if (gimplify_expr (&op, pre_p, post_p, is_gimple_val, fb_rvalue) > + == GS_ERROR) > + return GS_ERROR; > + > + gcall *call = gimple_build_call_internal_vec (ifn, ops); > + gimple_seq_add_stmt_without_update (pre_p, call); > + *expr_p = create_tmp_var (type); > + gimple_call_set_lhs (call, *expr_p); it would be possible to do *expr_p = build_call_expr_internal (ifn, type, ops[0], ops[1]. ops[2]); return GS_OK; and not worry about temporary creation a
[PATCH] c-family: implement -ffp-contract=on
Implement -ffp-contract=on for C and C++ without changing default behavior (=off for -std=cNN, =fast for C++ and -std=gnuNN). gcc/c-family/ChangeLog: * c-gimplify.cc (fma_supported_p): New helper. (c_gimplify_expr) [PLUS_EXPR, MINUS_EXPR]: Implement FMA contraction. gcc/ChangeLog: * common.opt (fp_contract_mode) [on]: Remove fallback. * config/sh/sh.md (*fmasf4): Correct flag_fp_contract_mode test. * doc/invoke.texi (-ffp-contract): Update. * trans-mem.cc (diagnose_tm_1): Skip internal function calls. --- gcc/c-family/c-gimplify.cc | 78 ++ gcc/common.opt | 3 +- gcc/config/sh/sh.md| 2 +- gcc/doc/invoke.texi| 8 ++-- gcc/trans-mem.cc | 3 ++ 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc index ef5c7d919f..f7635d3b0c 100644 --- a/gcc/c-family/c-gimplify.cc +++ b/gcc/c-family/c-gimplify.cc @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see #include "c-ubsan.h" #include "tree-nested.h" #include "context.h" +#include "tree-pass.h" +#include "internal-fn.h" /* The gimplification pass converts the language-dependent trees (ld-trees) emitted by the parser into language-independent trees @@ -686,6 +688,14 @@ c_build_bind_expr (location_t loc, tree block, tree body) return bind; } +/* Helper for c_gimplify_expr: test if target supports fma-like FN. */ + +static bool +fma_supported_p (enum internal_fn fn, tree type) +{ + return direct_internal_fn_supported_p (fn, type, OPTIMIZE_FOR_BOTH); +} + /* Gimplification of expression trees. */ /* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in @@ -739,6 +749,74 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED, break; } +case PLUS_EXPR: +case MINUS_EXPR: + { + tree type = TREE_TYPE (*expr_p); + /* For -ffp-contract=on we need to attempt FMA contraction only + during initial gimplification. Late contraction across statement + boundaries would violate language semantics. */ + if (SCALAR_FLOAT_TYPE_P (type) + && flag_fp_contract_mode == FP_CONTRACT_ON + && cfun && !(cfun->curr_properties & PROP_gimple_any) + && fma_supported_p (IFN_FMA, type)) + { + bool neg_mul = false, neg_add = code == MINUS_EXPR; + + tree *op0_p = &TREE_OPERAND (*expr_p, 0); + tree *op1_p = &TREE_OPERAND (*expr_p, 1); + + /* Look for ±(x * y) ± z, swapping operands if necessary. */ + if (TREE_CODE (*op0_p) == NEGATE_EXPR + && TREE_CODE (TREE_OPERAND (*op0_p, 0)) == MULT_EXPR) + /* '*EXPR_P' is '-(x * y) ± z'. This is fine. */; + else if (TREE_CODE (*op0_p) != MULT_EXPR) + { + std::swap (op0_p, op1_p); + std::swap (neg_mul, neg_add); + } + if (TREE_CODE (*op0_p) == NEGATE_EXPR) + { + op0_p = &TREE_OPERAND (*op0_p, 0); + neg_mul = !neg_mul; + } + if (TREE_CODE (*op0_p) != MULT_EXPR) + break; + auto_vec ops (3); + ops.quick_push (TREE_OPERAND (*op0_p, 0)); + ops.quick_push (TREE_OPERAND (*op0_p, 1)); + ops.quick_push (*op1_p); + + enum internal_fn ifn = IFN_FMA; + if (neg_mul) + { + if (fma_supported_p (IFN_FNMA, type)) + ifn = IFN_FNMA; + else + ops[0] = build1 (NEGATE_EXPR, type, ops[0]); + } + if (neg_add) + { + enum internal_fn ifn2 = ifn == IFN_FMA ? IFN_FMS : IFN_FNMS; + if (fma_supported_p (ifn2, type)) + ifn = ifn2; + else + ops[2] = build1 (NEGATE_EXPR, type, ops[2]); + } + for (auto &&op : ops) + if (gimplify_expr (&op, pre_p, post_p, is_gimple_val, fb_rvalue) + == GS_ERROR) + return GS_ERROR; + + gcall *call = gimple_build_call_internal_vec (ifn, ops); + gimple_seq_add_stmt_without_update (pre_p, call); + *expr_p = create_tmp_var (type); + gimple_call_set_lhs (call, *expr_p); + return GS_ALL_DONE; + } + break; + } + default:; } diff --git a/gcc/common.opt b/gcc/common.opt index a28ca13385..3daec85aef 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1662,9 +1662,8 @@ Name(fp_contract_mode) Type(enum fp_contract_mode) UnknownError(unknown floating EnumValue Enum(fp_contract_mode) String(off) Value(FP_CONTRACT_OFF) -; Not implemented, fall back to conservative FP_CONTRACT_OFF. EnumValue -Enum(fp_contract_mode) String(on) Value(FP_CONTRACT_OFF) +Enum(fp_contract_mode) String(on) Value(FP_CONTRACT_ON)