[PATCH] ifcvt: Fix regression in aarch64/fcsel_1.c

Jeff Law jeffreyalaw@gmail.com
Mon Feb 13 06:46:22 GMT 2023



On 2/3/23 02:15, Richard Sandiford via Gcc-patches wrote:
> aarch64/fcsel_1.c contains:
> 
> double
> f_2 (double a, double b, double c, double d)
> {
>    if (a > b)
>      return c;
>    else
>      return d;
> }
> 
> which started failing in the GCC 12 timeframe.  When it passed,
> the RTL had the form:
> 
> [A]
>    (set (reg ret) (reg c))
>    (set (pc) (if_then_else (gt ...) (label_ref ret) (pc)))
>      edge to ret, fallthru to else
> else:
>    (set (reg ret) (reg d))
>      fallthru to ret
> ret:
>    ...exit...
> 
> i.e. a branch around.  Now the RTL has form:
> 
> [B]
>    (set (reg ret) (reg d))
>    (set (pc) (if_then_else (gt ...) (label_ref then) (pc)))
>      edge to then, fallthru to ret
> ret:
>    ...exit...
> 
> then:
>    (set (reg ret) (reg c))
>      edge to ret
> 
> i.e. a branch out.
> 
> Both are valid, of course, and there's no easy way to predict
> which we'll get.  But ifcvt canonicalises its representation on:
> 
>    if (cond) goto fallthru else goto non-fallthru
> 
> That is, it canoncalises on the branch-around case for half-diamonds.
> It therefore wants to invert the comparison in [B] to get:
> 
>    if (...) goto ret else goto then
> 
> But that isn't possible for strict FP gt, so the optimisation fails.
> 
> Canonicalising on the branch-around case seems like the wrong choice for
> half diamonds.  The natural way of expressing a conditional branch is
> for the label_ref to be the "then" destination and pc to be the "else"
> destination.  And the natural choice of condition seems to be the one
> under which extra stuff *is* done, rather than the one under which extra
> stuff *isn't* done.  But that decision goes back at least 20 years and
> it doesn't seem like a good idea to change it in stage 4.
As I was parsing things up to the last sentence my first thought was no 
isn't the right time to fix this :-)


> 
> This patch instead allows the internal structure to store the
> condition in inverted form.  For simplicity it handles only
> conditional moves, which is the one case that is needed
> to fix the known regression.  (There are probably unknown
> regressions too, but still.)
> 
> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?
> 
> Richard
> 
> 
> gcc/
> 	* ifcvt.h (noce_if_info::cond_inverted): New field.
> 	* ifcvt.cc (cond_move_convert_if_block): Swap the then and else
> 	values when cond_inverted is true.
> 	(noce_find_if_block): Allow the condition to be inverted when
> 	handling conditional moves.
> ---
>   gcc/ifcvt.cc | 31 +++++++++++++++++++------------
>   gcc/ifcvt.h  |  8 ++++++++
>   2 files changed, 27 insertions(+), 12 deletions(-)
> 
> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
> index 008796838f7..63ef42b3c34 100644
> --- a/gcc/ifcvt.cc
> +++ b/gcc/ifcvt.cc
> @@ -4253,6 +4253,9 @@ cond_move_convert_if_block (struct noce_if_info *if_infop,
>   	    e = dest;
>   	}
>   
> +      if (if_infop->cond_inverted)
> +	std::swap (t, e);
> +
>         target = noce_emit_cmove (if_infop, dest, code, cond_arg0, cond_arg1,
>   				t, e);
>         if (!target)
> @@ -4405,7 +4408,6 @@ noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge,
>     basic_block then_bb, else_bb, join_bb;
>     bool then_else_reversed = false;
>     rtx_insn *jump;
> -  rtx cond;
>     rtx_insn *cond_earliest;
>     struct noce_if_info if_info;
>     bool speed_p = optimize_bb_for_speed_p (test_bb);
> @@ -4481,25 +4483,28 @@ noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge,
>     if (! onlyjump_p (jump))
>       return FALSE;
>   
> -  /* If this is not a standard conditional jump, we can't parse it.  */
> -  cond = noce_get_condition (jump, &cond_earliest, then_else_reversed);
> -  if (!cond)
> -    return FALSE;
> -
> -  /* We must be comparing objects whose modes imply the size.  */
> -  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
> -    return FALSE;
> -
>     /* Initialize an IF_INFO struct to pass around.  */
>     memset (&if_info, 0, sizeof if_info);
>     if_info.test_bb = test_bb;
>     if_info.then_bb = then_bb;
>     if_info.else_bb = else_bb;
>     if_info.join_bb = join_bb;
> -  if_info.cond = cond;
> +  if_info.cond = noce_get_condition (jump, &cond_earliest,
> +				     then_else_reversed);;
Extraneous ';'.

OK with that nit fixed.

jeff


More information about the Gcc-patches mailing list