Hi,
I am working on a port for a processor that has 32 bit registers but can
only load 16 bit immediates. I have tried several ways to split moves
with larger immediates into two RTL insns. One is using a
define_expand:
-------------------------code-----------------------
(define_expand "movsi"
[(set (match_operand:SI 0 "nonimmediate_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
{
if (GET_CODE(operands[0]) != REG) {
operands[1] = force_reg(SImode, operands[1]);
}
else if(s17to32_const_int_operand(operands[1],
GET_MODE(operands[1]))){
emit_move_insn(operands[0],
gen_rtx_HIGH(GET_MODE(operands[1]), operands[1]));
emit_move_insn(operands[0],
gen_rtx_LO_SUM(GET_MODE(operands[1]),
operands[0], operands[1]));
DONE;
}
})
------------------------/code-----------------------
With the corresponding define_insns:
-------------------------code-----------------------
(define_insn "movsi_high"
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (match_operand:SI 1 "immediate_operand" "i")))]
""
"%0.h = #HI(%1)")
(define_insn "movsi_lo_sum"
[(set (match_operand:SI 0 "register_operand" "+r")
(lo_sum:SI (match_dup 0)
(match_operand:SI 1 "immediate_operand" "i")))]
""
"%0.l = #LO(%1)")
------------------------/code-----------------------
but using this method, I get the following error:
-------------------------error-----------------------
./libgcc2.c:470: error: unrecognizable insn:
(insn 100 99 86 0 ./libgcc2.c:464 (set (reg:SI 10 r10)
(lo_sum (reg:SI 10 r10)
(const_int 65536 [0x10000]))) -1 (nil)
(nil))
./libgcc2.c:470: internal compiler error: in extract_insn, at
recog.c:2083
------------------------/error-----------------------
Why would that RTL not match my movsi_lo_sum define_insn?
I also tried using a define_split:
-------------------------code-----------------------
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "s17to32_const_int_operand" ""))]
"reload_completed"
[(set (match_dup 0)
(high:SI (match_dup 1)))
(set (match_dup 0)
(lo_sum:SI (match_dup 0)
(match_dup 1)))]
"")
------------------------/code-----------------------
along with the same define_insns, but then I get the following error:
-------------------------error-----------------------
./crtstuff.c:288: error: insn does not satisfy its constraints:
(insn 103 12 11 0 (set (reg:SI 0 r0)
(symbol_ref/u:SI ("*.LC0") [flags 0x2])) 18 {movsi_real} (nil)
(nil))
./crtstuff.c:288: internal compiler error: in
reload_cse_simplify_operands, at postreload.c:378
------------------------/error-----------------------
In other words, that RTL never matches my define_split, even though I
placed it before the more general movsi define_insn and
s17to32_const_int_operand should return 1 for a symbol_ref.
Do you have any idea why either of these attempts do not work? Which
method do you think is better? In case you were wondering, here is the
code for s17to32_const_int_operand. I modified the function
int_2word_operand from the frv port.
-------------------------code-----------------------
int s17to32_const_int_operand(rtx op, enum machine_mode mode
ATTRIBUTE_UNUSED)
{
HOST_WIDE_INT value;
REAL_VALUE_TYPE rv;
long l;
switch (GET_CODE (op))
{
default:
break;
case LABEL_REF:
case SYMBOL_REF:
case CONST:
return 1;
case CONST_INT:
return ! IN_RANGE_P (INTVAL (op), -0x8000, 0x7FFF);
case CONST_DOUBLE:
if (GET_MODE (op) == SFmode)
{
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
value = l;
return ! IN_RANGE_P (value, -0x8000, 0x7FFF);
}
else if (GET_MODE (op) == VOIDmode)
{
value = CONST_DOUBLE_LOW (op);
return ! IN_RANGE_P (value, -0x8000, 0x7FFF);
}
break;
}
return 0;
}
------------------------/code-----------------------
Thank you,
Charles J. Tabony