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