[Putting the gcc-list back in CC:, ]
Le mardi 08 avril 2008 à 18:24 -0400, DJ Delorie a écrit :
> Do you have one insn for each pair of src/dest that movqi supports?
> If so, this isn't the best way to do it - you should have one insn
> with multiple constraint alternativess, not multiple insns.
[...]
> reload deals with selecting among constraint
> options, it doesn't usually have the choice about which pattern to
> choose - the first that matches is used. If you have a list of
> patterns that all match, only the first is available to reload. Plus,
> reload gets confused when the predicates are used to choose among
> otherwise identical patterns. So, it's best to have a more general
> predicate (like general_operand) and use the constraints to tell
> reload how to implement that insn in hardware.
Thanks to your suggestion, I changed my movqi pattern to look like:
(define_insn "*movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,y,y,m,r")
(match_operand:QI 1 "general_operand" "r,n,s,r,m"))]
""
{
switch (which_alternative) {
case 0: /* register to register */
return "tfr %0,%1";
case 1: /* immediate to register */
output_asm_insn ("ldih %0, hi(%1)", operands);
output_asm_insn ("ldil %0, lo(%1)", operands);
return "";
case 2: /* immediate symbol to register */
output_asm_insn ("ldih %0, hi(%c1)", operands);
output_asm_insn ("ldil %0, lo(%c1)", operands);
return "";
case 3: /* register to memory */
if (GET_CODE (XEXP(operands[0], 0)) == REG) {
operands[0] = XEXP(operands[0], 0);
return "st %1,(%0)";
}
fatal_insn ("Incorrect operand:", operands[0]);
case 4: /* memory to register */
if (GET_CODE (XEXP(operands[1], 0)) == REG) {
operands[1] = XEXP(operands[1], 0);
return "ld %0,(%1)";
}
fatal_insn ("Incorrect operand:", operands[1]);
}
return "";
}
[(set_attr "cc" "none")]
)
Does this look ok ? The 'fatal_insn' should not happen, because if I see
such a pattern in the define_expand "movqi" I force the use of a register:
(define_expand "movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
{
if (!reload_in_progress
&& !reload_completed) {
if (GET_CODE (operands[0]) == MEM
&& (GET_CODE (operands[1]) != REG)) {
operands[1] = force_reg (QImode, operands[1]);
}
else if (GET_CODE(operands[1]) == MEM
&& GET_CODE(XEXP(operands[1], 0)) == PLUS
&& GET_CODE(XEXP(XEXP(operands[1], 0), 0)) == REG
&& GET_CODE(XEXP(XEXP(operands[1], 0), 1)) ==
CONST_INT) {
/* indirect load */
XEXP(operands[1], 0) = force_reg (QImode, XEXP
(operands[1], 0));
}
else if (GET_CODE(operands[0]) == MEM
&& GET_CODE(XEXP(operands[0], 0)) == PLUS
&& GET_CODE(XEXP(XEXP(operands[0], 0), 0)) == REG
&& GET_CODE(XEXP(XEXP(operands[0], 0), 1)) ==
CONST_INT) {
/* indirect store */
XEXP(operands[0], 0) = force_reg (QImode, XEXP
(operands[0], 0));
}
}
}
)
This seems to work ok, but I still have issues at reload time, because
of the base register addressing mode: in the reload pass gcc generates
moves from/to the stack:
Reloads for insn # 3
Reload 0: reload_in (QI) = (reg/f:QI 31 r31)
EVEN_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 0)
reload_in_reg: (reg/f:QI 31 r31)
reload_reg_rtx: (reg:QI 0 r0)
Reload 1: reload_out (QI) = (mem/c:QI (plus:QI (reg/f:QI 31 r31)
(const_int -3
[0xfffffffd])) [10 S1 A16])
EVEN_REGS, RELOAD_FOR_OUTPUT (opnum = 0), optional
reload_out_reg: (reg:QI 109 [ u ])
But those moves are illegal because there is no offset allowed in the
base register addressing mode (see the definition of my
GO_IF_LEGITIMATE_ADDRESS() ),
so gcc crashes with 'unrecognizable insn'.
So what's the proper way to tell that indirect addressing is allowed,
but not with an offset ? Should I define an extra define_expand to deal
with those insns ?
Thanks again,
Stelian.
--
Stelian Pop <[EMAIL PROTECTED]>