After r14-2667-gceae1400cf24f329393e96dd9720, we force a constant to a register if it is shared with one of the other operands. The problem is used the comparison mode for the register but that could be different from the operand mode. This causes some issues on some targets. To fix it, we either need to have the modes match or if it is an integer mode, then we can use the lower part for the smaller mode.
Bootstrapped and tested on both aarch64-linux-gnu and x86_64-linux. PR middle-end/111260 gcc/ChangeLog: * optabs.cc (emit_conditional_move): Fix up mode handling for forcing the constant to a register. gcc/testsuite/ChangeLog: * gcc.c-torture/compile/condmove-1.c: New test. Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com> --- gcc/optabs.cc | 40 +++++++++++++++++-- .../gcc.c-torture/compile/condmove-1.c | 9 +++++ 2 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/condmove-1.c diff --git a/gcc/optabs.cc b/gcc/optabs.cc index f0a048a6bdb..573cf22760e 100644 --- a/gcc/optabs.cc +++ b/gcc/optabs.cc @@ -5131,26 +5131,58 @@ emit_conditional_move (rtx target, struct rtx_comparison comp, /* If we are optimizing, force expensive constants into a register but preserve an eventual equality with op2/op3. */ if (CONSTANT_P (orig_op0) && optimize + && (cmpmode == mode + || (GET_MODE_CLASS (cmpmode) == MODE_INT + && GET_MODE_CLASS (mode) == MODE_INT)) && (rtx_cost (orig_op0, mode, COMPARE, 0, optimize_insn_for_speed_p ()) > COSTS_N_INSNS (1)) && can_create_pseudo_p ()) { + machine_mode new_mode; + if (known_le (GET_MODE_PRECISION (cmpmode), GET_MODE_PRECISION (mode))) + new_mode = mode; + else + new_mode = cmpmode; if (rtx_equal_p (orig_op0, op2)) - op2p = XEXP (comparison, 0) = force_reg (cmpmode, orig_op0); + { + rtx r = force_reg (new_mode, orig_op0); + op2p = gen_lowpart (mode, r); + XEXP (comparison, 0) = gen_lowpart (cmpmode, r); + } else if (rtx_equal_p (orig_op0, op3)) - op3p = XEXP (comparison, 0) = force_reg (cmpmode, orig_op0); + { + rtx r = force_reg (new_mode, orig_op0); + op3p = gen_lowpart (mode, r); + XEXP (comparison, 0) = gen_lowpart (cmpmode, r); + } } if (CONSTANT_P (orig_op1) && optimize + && (cmpmode == mode + || (GET_MODE_CLASS (cmpmode) == MODE_INT + && GET_MODE_CLASS (mode) == MODE_INT)) && (rtx_cost (orig_op1, mode, COMPARE, 0, optimize_insn_for_speed_p ()) > COSTS_N_INSNS (1)) && can_create_pseudo_p ()) { + machine_mode new_mode; + if (known_le (GET_MODE_PRECISION (cmpmode), GET_MODE_PRECISION (mode))) + new_mode = mode; + else + new_mode = cmpmode; if (rtx_equal_p (orig_op1, op2)) - op2p = XEXP (comparison, 1) = force_reg (cmpmode, orig_op1); + { + rtx r = force_reg (new_mode, orig_op1); + op2p = gen_lowpart (mode, r); + XEXP (comparison, 1) = gen_lowpart (cmpmode, r); + } else if (rtx_equal_p (orig_op1, op3)) - op3p = XEXP (comparison, 1) = force_reg (cmpmode, orig_op1); + { + rtx r = force_reg (new_mode, orig_op1); + op3p = gen_lowpart (mode, r); + XEXP (comparison, 1) = gen_lowpart (cmpmode, r); + } } prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1), GET_CODE (comparison), NULL_RTX, unsignedp, diff --git a/gcc/testsuite/gcc.c-torture/compile/condmove-1.c b/gcc/testsuite/gcc.c-torture/compile/condmove-1.c new file mode 100644 index 00000000000..3fcc591af00 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/condmove-1.c @@ -0,0 +1,9 @@ +/* PR middle-end/111260 */ + +/* Used to ICE while expansion of the `(a == b) ? b : 0;` */ +int f1(long long a) +{ + int b = 822920; + int t = a == b; + return t * (int)b; +} -- 2.39.3