Zhenqiang Chen wrote:
> Function noce_emit_store_flag tries to generate instruction to store flag by
> emit_store_flag for general_operand. For s390, CCU is a general _operand,
> but can not match cstorecc4, then it tries to generate a register move
> instruction from CCU to CCZ1, which will trigger an ICE.
OK, I think I see the problem now. emit_store_flag calls emit_cstore, which
calls prepare_operand, which does:
if (!insn_operand_matches (icode, opnum, x))
{
if (reload_completed)
return NULL_RTX;
x = copy_to_mode_reg (insn_data[(int) icode].operand[opnum].mode, x);
}
The insn_operand_matches call will indeed fail since x has CCUmode, but
the operand only accepts CCZ1mode for this insn.
However, it is a bug to use copy_to_mode_reg with a mode different
from the mode of the RTX to be loaded (unless that RTX is a constant
of VOIDmode); copy_to_mode_reg will simply abort in that case.
Usually, this doesn't happen since prepare_operand is called on insns that
were already selected according to the operand mode. However, this is
weakened for MODE_CC modes in emit_store_flag:
machine_mode optab_mode = mclass == MODE_CC ? CCmode : compare_mode;
icode = optab_handler (cstore_optab, optab_mode);
So the assumption seems to be that a cstorecc4 insn must accept *any*
MODE_CC mode, or else prepare_operand will abort. I don't think this
requirement is really useful; on s390 there are good reasons to only
accept certain MODE_CC modes and ask the middle-end to fall back to
the generic implemention for others.
Thus I'd propose to add a mode check to prepare_operand and simply fail
instead of aborting if the mode doesn't match what the insn expects.
The appended patch does this; it fixes the ICEs when adding your patch.
Tested on s390x-ibm-linux.
Richard, does this look reasonable to you?
Bye,
Ulrich
ChangeLog:
* optabs.c (prepare_operand): Gracefully fail if the mode of X
does not match the operand mode expected by the insn pattern.
Index: gcc/optabs.c
===================================================================
*** gcc/optabs.c (revision 217416)
--- gcc/optabs.c (working copy)
*************** prepare_operand (enum insn_code icode, r
*** 4308,4316 ****
if (!insn_operand_matches (icode, opnum, x))
{
if (reload_completed)
return NULL_RTX;
! x = copy_to_mode_reg (insn_data[(int) icode].operand[opnum].mode, x);
}
return x;
--- 4308,4319 ----
if (!insn_operand_matches (icode, opnum, x))
{
+ machine_mode op_mode = insn_data[(int) icode].operand[opnum].mode;
if (reload_completed)
return NULL_RTX;
! if (GET_MODE (x) != op_mode && GET_MODE (x) != VOIDmode)
! return NULL_RTX;
! x = copy_to_mode_reg (op_mode, x);
}
return x;
--
Dr. Ulrich Weigand
GNU/Linux compilers and toolchain
[email protected]