https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116979
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |uros at gcc dot gnu.org --- Comment #11 from Jakub Jelinek <jakub at gcc dot gnu.org> --- C testcase (-O2 -mfma): struct S { __complex__ float f; }; struct S foo (const struct S *a, const struct S *b) { struct S r; r.f = a->f * b->f; return r; } I've tried to catch this up during widening_mul with --- gcc/tree-ssa-math-opts.cc.jj 2024-11-23 13:00:31.445983255 +0100 +++ gcc/tree-ssa-math-opts.cc 2024-12-12 18:22:42.078324724 +0100 @@ -3092,7 +3092,17 @@ convert_mult_to_fma_1 (tree mul_result, if (!can_interpret_as_conditional_op_p (use_stmt, &cond, &code, ops, &else_value, &len, &bias)) - gcc_unreachable (); + { + gcc_assert (gimple_call_internal_p (use_stmt, IFN_VEC_ADDSUB)); + cond = NULL_TREE; + code = ERROR_MARK; + ops[0] = gimple_call_arg (use_stmt, 0); + ops[1] = gimple_call_arg (use_stmt, 1); + ops[2] = NULL_TREE; + else_value = NULL_TREE; + len = NULL_TREE; + bias = NULL_TREE; + } addop = ops[0] == result ? ops[1] : ops[0]; if (code == MINUS_EXPR) @@ -3118,6 +3128,9 @@ convert_mult_to_fma_1 (tree mul_result, else if (cond) fma_stmt = gimple_build_call_internal (IFN_COND_FMA, 5, cond, mulop1, op2, addop, else_value); + else if (code == ERROR_MARK) + fma_stmt = gimple_build_call_internal (IFN_VEC_FMADDSUB, 3, mulop1, + op2, addop); else fma_stmt = gimple_build_call_internal (IFN_FMA, 3, mulop1, op2, addop); gimple_set_lhs (fma_stmt, gimple_get_lhs (use_stmt)); @@ -3419,22 +3432,38 @@ convert_mult_to_fma (gimple *mul_stmt, t tree cond, else_value, ops[3], len, bias; tree_code code; - if (!can_interpret_as_conditional_op_p (use_stmt, &cond, &code, ops, - &else_value, &len, &bias)) - return false; - - switch (code) + if (can_interpret_as_conditional_op_p (use_stmt, &cond, &code, ops, + &else_value, &len, &bias)) + switch (code) + { + case MINUS_EXPR: + if (ops[1] == result) + negate_p = !negate_p; + break; + case PLUS_EXPR: + break; + default: + /* FMA can only be formed from PLUS and MINUS. */ + return false; + } + else if (gimple_call_internal_p (use_stmt, IFN_VEC_ADDSUB)) { - case MINUS_EXPR: - if (ops[1] == result) - negate_p = !negate_p; - break; - case PLUS_EXPR: - break; - default: - /* FMA can only be formed from PLUS and MINUS. */ - return false; + cond = NULL_TREE; + code = ERROR_MARK; + ops[0] = gimple_call_arg (use_stmt, 0); + ops[1] = gimple_call_arg (use_stmt, 1); + ops[2] = NULL_TREE; + else_value = NULL_TREE; + len = NULL_TREE; + bias = NULL_TREE; + if (negate_p + || ops[0] != result + || !direct_internal_fn_supported_p (IFN_VEC_FMADDSUB, type, + opt_type)) + return false; } + else + return false; if (len) { but it doesn't work anyway, because vec_fmaddsubv2sf4 is not supported. And if I change the testcase s/float/double/, then it uses vfmaddsub132pd even without my patch. So maybe the fix would be to introduce vec_fmaddsubv2sf4 and maybe vec_fmsubaddv2sf4 patterns for (TARGET_FMA || TARGET_FMA4 || TARGET_AVX512VL) && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math ? CCing Uros, I really have limited experience with the mmx with sse stuff.