Richard Henderson <[email protected]> writes:
> On 03/29/2011 06:21 AM, Richard Sandiford wrote:
>> - enum machine_mode mode0 = insn_data[(int) icode].operand[1].mode;
>> - enum machine_mode mode1 = insn_data[(int) icode].operand[2].mode;
>> - enum machine_mode tmp_mode;
>> + enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
>> + enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
>> + enum machine_mode mode0, mode1, tmp_mode;
> ...
>> - if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
>> - xop0 = convert_modes (mode0,
>> - GET_MODE (xop0) != VOIDmode
>> - ? GET_MODE (xop0)
>> - : mode,
>> - xop0, unsignedp);
>> -
>> - if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
>> - xop1 = convert_modes (mode1,
>> - GET_MODE (xop1) != VOIDmode
>> - ? GET_MODE (xop1)
>> - : mode,
>> - xop1, unsignedp);
>> + mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode;
>> + if (xmode0 != VOIDmode && xmode0 != mode0)
>> + {
>> + xop0 = convert_modes (xmode0, mode0, xop0, unsignedp);
>> + mode0 = xmode0;
>> + }
>> +
>> + mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
>> + if (xmode1 != VOIDmode && xmode1 != mode1)
>> + {
>> + xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
>> + mode1 = xmode1;
>> + }
>
> This smells like a target bug, but I can't quite put my finger
> on exactly what's wrong, and I haven't debugged the original.
>
> The backend has said xmode[01] is what it expects. The only
> reason you wouldn't write xmode[01] in the create_input_operand
> line is if xmode[01] are VOIDmode.
Right. Sorry, I should have said, but the failure was actually from:
case EXPAND_INPUT:
input:
gcc_assert (mode != VOIDmode);
expand_binop_direct passed the match_operand's mode to create_input_operand,
which was really the opposite of the intention. The caller should be
passing the mode of the rtx, which it should always "know".
> That seems like mistake number one, particularly for a binop,
> but I'll accept that for the nonce. Which pattern triggered
> the problem in the target?
It was ashrdi3:
(define_expand "ashrdi3"
[(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand 2 "const_int_operand" "")))]
"!TARGET_COLDFIRE"
Which seems reasonable in this context, since the shift count isn't
really DImode.
> Then we've got the conditionalization in the init of mode[01],
> which is presumably to handle CONST_INT as an input.
>
> What about something like
>
> xmode0 = insn_data...
> if (xmode0 == VOIDmode)
> xmode0 = mode;
>
> mode0 = GET_MODE (xop0);
> if (mode0 == VOIDmode)
> mode0 = mode;
>
> if (xmode0 != mode0)
> convert_modes
>
> create_input_operand(..., xmode0)
>
> ? That seems more obvious than what you have. And I *think*
> it should produce the same results. If it doesn't, then this
> whole block of code needs a lot more explanation.
The problem is that a VOIDmode match_operand doesn't necessary imply
that "mode" is the right mode. VOIDmode register-accepting operands
are only a warning, not an error, and are sometimes needed for
flag-specific variations. They've traditionally not forced a conversion
to "mode". E.g. if you have something like this on a 32-bit target:
unsigned long long foo (unsigned long long x, int y)
{
return x >>= y;
}
then op1 will be (reg:SI y). Having a VOIDmode match_operand shouldn't
force that to be converted to (reg:DI y), whereas I think the sequence
above would.
Or to put it another way: as things stand, "mode" is only trustworthy
for CONST_INT opNs. A VOIDmode match_operand doesn't imply that the
opN argument to expand_binop_directly is a CONST_INT, or even that
only CONST_INTs are acceptable to the target.
This comes back to the point that we really should know up-front what
modes op0 and op1 actually have. (The thing I left as a future clean-up.)
Until then, the process implemented by yesterday's patch was supposed to be:
- work out what mode opN actually has at this point in time
- see if the target has specifically asked for a different mode
- if so, convert the operand
This is directly equivalent to what create_convert_operand_from does:
case EXPAND_CONVERT_FROM:
if (GET_MODE (op->value) != VOIDmode)
mode = GET_MODE (op->value);
else
/* The caller must tell us what mode this value has. */
gcc_assert (mode != VOIDmode);
imode = insn_data[(int) icode].operand[opno].mode;
if (imode != VOIDmode && imode != mode)
{
op->value = convert_modes (imode, mode, op->value, op->unsigned_p);
mode = imode;
}
But we have to break the flow there (rather than go on to coerce the operands)
because of the commutative thing.
Richard