On Sat, Dec 20, 2025 at 3:20 PM Arsen Arsenović <[email protected]> wrote:
>
> With the following testcase, on AMDGCN with -Ofast:
>
> void
> foo (float* output, float* input)
> {
> for (int i = 0; i < 1024 * 1024; i++) {
> output[i] = __builtin_sinf (input[i]) + __builtin_cosf (input[i]);
> }
> }
>
> ... the following ICE happens:
>
> during GIMPLE pass: sincos
> test.cpp: In function 'void foo(float*, float*)':
> test.cpp:2:1: internal compiler error: Segmentation fault
> 2 | foo (float* output, float* input)
> | ^~~
> [... snipped ...]
> 0x17befb8 types_compatible_p(tree_node*, tree_node*)
> gcc/gimple-expr.h:67
> 0x17befb8 execute_cse_sincos_1
> gcc/tree-ssa-math-opts.cc:1299
> 0x17befb8 execute
> gcc/tree-ssa-math-opts.cc:2248
>
> This happens because the vect pass converted the testcase into:
>
> vect__4.6_40 = MEM <vector(64) float> [(float *)vectp_input.4_38];
> vect__6.8_42 = .COS (vect__4.6_40);
> vect__5.7_41 = .SIN (vect__4.6_40);
> vect__8.9_43 = vect__5.7_41 + vect__6.8_42;
>
> Then, sincos attempts to find the type of the IFN_SIN/IFN_COS via
> mathfn_built_in_type. This fails, so the compiler crashes.
>
> For these IFNs, their input type is the same as their output type, so
> we can fall back to that.
>
> Note that, currently, GCC can't seem to handle vector sincos/cexpi
> operations, so any attempt to CSE these will fail quickly after. This
> patch does not fix that, only the ICE that happens in the attempt.
>
> gcc/ChangeLog:
>
> * tree-ssa-math-opts.cc (execute_cse_sincos_1): If
> mathfn_built_in_type fails to determine a type for our
> operation, presume that it is the same as the input type.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/sincos-ice-on-ifn_sin-call.c: New test.
> * gcc.target/gcn/sincos-ice-on-ifn_sin-call-1.c: New test.
> ---
> Reg-strapped on x86_64-linux-gnu and amdgcn-amdhsa (when that finishes
> running; I suspect it'll be fine).
>
> OK for trunk?
>
> .../tree-ssa/sincos-ice-on-ifn_sin-call.c | 19 +++++++++++++++++++
> .../gcn/sincos-ice-on-ifn_sin-call-1.c | 13 +++++++++++++
> gcc/tree-ssa-math-opts.cc | 12 +++++++++++-
> 3 files changed, 43 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/sincos-ice-on-ifn_sin-call.c
> create mode 100644
> gcc/testsuite/gcc.target/gcn/sincos-ice-on-ifn_sin-call-1.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/sincos-ice-on-ifn_sin-call.c
> b/gcc/testsuite/gcc.dg/tree-ssa/sincos-ice-on-ifn_sin-call.c
> new file mode 100644
> index 000000000000..3a8c047502e0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/sincos-ice-on-ifn_sin-call.c
> @@ -0,0 +1,19 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-O -fgimple" } */
> +typedef float V __attribute__ ((vector_size (16)));
> +
> +void __GIMPLE (ssa, startwith ("sincos"))
> +foo (float * output, const float * input)
> +{
> + V a;
> + V b;
> + V c;
> + V d;
> +
> + __BB(2):
> + a = __MEM <const V> (input);
> + b = .COS (a);
> + c = .SIN (a);
> + d = a + b;
> + return;
> +}
> diff --git a/gcc/testsuite/gcc.target/gcn/sincos-ice-on-ifn_sin-call-1.c
> b/gcc/testsuite/gcc.target/gcn/sincos-ice-on-ifn_sin-call-1.c
> new file mode 100644
> index 000000000000..b787a49fb0e8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/gcn/sincos-ice-on-ifn_sin-call-1.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-Ofast" } */
> +#include <math.h>
> +
> +/* This test is the original, platform-specific, version of
> + gcc.dg/tree-ssa/sincos-ice-on-ifn_sin-call.c. */
> +void
> +foo (float output[1024 * 1024], const float input[1024 * 1024])
> +{
> + for (int i = 0; i < 1024 * 1024; i++) {
> + output[i] = __builtin_sinf (input[i]) + __builtin_cosf (input[i]);
> + }
> +}
> diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
> index 04c9f2c07e92..f4c6c64a5375 100644
> --- a/gcc/tree-ssa-math-opts.cc
> +++ b/gcc/tree-ssa-math-opts.cc
> @@ -1287,7 +1287,17 @@ execute_cse_sincos_1 (tree name)
> continue;
> }
>
> - tree t = mathfn_built_in_type (gimple_call_combined_fn (use_stmt));
> + auto stmt_cfn = gimple_call_combined_fn (use_stmt);
> + tree t = mathfn_built_in_type (stmt_cfn);
> + if (!t)
> + {
> + /* mathfn_built_in_type does not handle internal functions, which
> may
> + also be CSE'd. For them, the input type is the same as the
> + output type. */
> + gcc_checking_assert (internal_fn_p (stmt_cfn));
> + t = TREE_TYPE (name);
> + }
Since mathfn_built_in_type is only used here. why not, instead pass
the use statement. And then if it was an internal function return the
type of the lhs of the internal statement.
So
tree t = mathfn_built_in_type (use_stmt);
And inside mathfn_built_in_type do:
```
#define DEF_INTERNAL_FLT_FN(NAME, FLAGS, OPTAB, TYPE) \
case IFN_##NAME: return TREE_TYPE (gimple_call_lhs (stmt));
#define DEF_INTERNAL_FLT_FLOATN_FN(NAME, FLAGS, OPTAB, TYPE) \
case IFN_##NAME: return TREE_TYPE (gimple_call_lhs (stmt));
#define DEF_INTERNAL_INT_FN(NAME, FLAGS, OPTAB, TYPE) \
case IFN_##NAME: return TREE_TYPE (gimple_call_lhs (stmt));
#include "internal-fn.def"
```
I think this will work.
> +
> if (!type)
> {
> type = t;
> --
> 2.52.0
>