Track both parts of far addresses so they don't get optimized away. Committed.
* config/rl78/constraints.md: For each W* constraint, rename to C* and create a W* constraint that checks for an optional ES: prefix pattern also. * config/rl78/rl78.md (UNS_ES_ADDR): New. (es_addr): New. Used to wrap far addresses. * config/rl78/rl78-protos.h (rl78_es_addr): New. (rl78_es_base): New. * config/rl78/rl78.c (rl78_as_legitimate_address): Accept "unspec" wrapped far addresses. (rl78_print_operand_1): Unwrap far addresses before processing. (rl78_lo16): Wrap far addresses in unspecs. (rl78_es_addr): New. (rl78_es_base): New. (insn_ok_now): Check for not-yet-wrapped far addresses. (transcode_memory_rtx): Properly re-wrap far addresses. Index: config/rl78/constraints.md =================================================================== --- config/rl78/constraints.md (revision 202665) +++ config/rl78/constraints.md (working copy) @@ -200,103 +200,155 @@ (define_register_constraint "Zint" "INT_REGS" "The interrupt registers.") ; All the memory addressing schemes the RL78 supports ; of the form W {register} {bytes of offset} ; or W {register} {register} +; Additionally, the Cxx forms are the same as the Wxx forms, but without +; the ES: override. ; absolute address -(define_memory_constraint "Wab" +(define_memory_constraint "Cab" "[addr]" (and (match_code "mem") (ior (match_test "CONSTANT_P (XEXP (op, 0))") (match_test "GET_CODE (XEXP (op, 0)) == PLUS && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF")) ) ) +(define_memory_constraint "Wab" + "es:[addr]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Cab (rl78_es_base (op)) + || satisfies_constraint_Cab (op)") + ) -(define_memory_constraint "Wbc" +(define_memory_constraint "Cbc" "word16[BC]" (and (match_code "mem") (ior (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) == BC_REG")) (and (match_code "plus" "0") (and (and (match_code "reg" "00") (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == BC_REG")) (match_test "uword_operand (XEXP (XEXP (op, 0), 1), VOIDmode)")))) ) ) +(define_memory_constraint "Wbc" + "es:word16[BC]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Cbc (rl78_es_base (op)) + || satisfies_constraint_Cbc (op)") + ) -(define_memory_constraint "Wde" +(define_memory_constraint "Cde" "[DE]" (and (match_code "mem") (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) == DE_REG"))) ) +(define_memory_constraint "Wde" + "es:[DE]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Cde (rl78_es_base (op)) + || satisfies_constraint_Cde (op)") + ) -(define_memory_constraint "Wca" +(define_memory_constraint "Cca" "[AX..HL] for calls" (and (match_code "mem") (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) <= HL_REG"))) ) +(define_memory_constraint "Wca" + "es:[AX..HL] for calls" + (match_test "rl78_es_addr (op) && satisfies_constraint_Cca (rl78_es_base (op)) + || satisfies_constraint_Cca (op)") + ) -(define_memory_constraint "Wcv" +(define_memory_constraint "Ccv" "[AX..HL,r8-r23] for calls" (and (match_code "mem") (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) < 24"))) ) +(define_memory_constraint "Wcv" + "es:[AX..HL,r8-r23] for calls" + (match_test "rl78_es_addr (op) && satisfies_constraint_Ccv (rl78_es_base (op)) + || satisfies_constraint_Ccv (op)") + ) -(define_memory_constraint "Wd2" +(define_memory_constraint "Cd2" "word16[DE]" (and (match_code "mem") (ior (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) == DE_REG")) (and (match_code "plus" "0") (and (and (match_code "reg" "00") (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == DE_REG")) (match_test "uword_operand (XEXP (XEXP (op, 0), 1), VOIDmode)")))) ) ) +(define_memory_constraint "Wd2" + "es:word16[DE]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Cd2 (rl78_es_base (op)) + || satisfies_constraint_Cd2 (op)") + ) -(define_memory_constraint "Whl" +(define_memory_constraint "Chl" "[HL]" (and (match_code "mem") (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) == HL_REG"))) ) +(define_memory_constraint "Whl" + "es:[HL]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Chl (rl78_es_base (op)) + || satisfies_constraint_Chl (op)") + ) -(define_memory_constraint "Wh1" +(define_memory_constraint "Ch1" "byte8[HL]" (and (match_code "mem") (and (match_code "plus" "0") (and (and (match_code "reg" "00") (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == HL_REG")) (match_test "ubyte_operand (XEXP (XEXP (op, 0), 1), VOIDmode)")))) ) +(define_memory_constraint "Wh1" + "es:byte8[HL]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Ch1 (rl78_es_base (op)) + || satisfies_constraint_Ch1 (op)") + ) -(define_memory_constraint "Whb" +(define_memory_constraint "Chb" "[HL+B]" (and (match_code "mem") (match_test "rl78_hl_b_c_addr_p (XEXP (op, 0))")) ) +(define_memory_constraint "Whb" + "es:[HL+B]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Chb (rl78_es_base (op)) + || satisfies_constraint_Chb (op)") + ) -(define_memory_constraint "Ws1" +(define_memory_constraint "Cs1" "word8[SP]" (and (match_code "mem") (ior (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) == SP_REG")) (and (match_code "plus" "0") (and (and (match_code "reg" "00") (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == SP_REG")) (match_test "ubyte_operand (XEXP (XEXP (op, 0), 1), VOIDmode)")))) ) ) +(define_memory_constraint "Ws1" + "es:word8[SP]" + (match_test "rl78_es_addr (op) && satisfies_constraint_Cs1 (rl78_es_base (op)) + || satisfies_constraint_Cs1 (op)") + ) (define_memory_constraint "Wfr" "ES/CS far pointer" (and (match_code "mem") (match_test "rl78_far_p (op)")) ) Index: config/rl78/rl78-protos.h =================================================================== --- config/rl78/rl78-protos.h (revision 202665) +++ config/rl78/rl78-protos.h (working copy) @@ -39,6 +39,9 @@ enum reg_class rl78_mode_code_base_reg_c bool rl78_peep_movhi_p (rtx *); bool rl78_real_insns_ok (void); void rl78_register_pragmas (void); bool rl78_regno_mode_code_ok_for_base_p (int, enum machine_mode, addr_space_t, int, int); void rl78_setup_peep_movhi (rtx *); bool rl78_virt_insns_ok (void); + +bool rl78_es_addr (rtx); +rtx rl78_es_base (rtx); Index: config/rl78/rl78.md =================================================================== --- config/rl78/rl78.md (revision 202665) +++ config/rl78/rl78.md (working copy) @@ -42,12 +42,13 @@ (UNS_PROLOG 1) (UNS_EPILOG 1) (UNS_RETI 2) (UNS_RETB 3) (UNS_SET_RB 10) + (UNS_ES_ADDR 11) (UNS_TRAMPOLINE_INIT 20) (UNS_TRAMPOLINE_UNINIT 21) (UNS_NONLOCAL_GOTO 22) ]) @@ -429,6 +430,14 @@ nop ; Additional nop for MAC movw ax, !0xf00e0 ; MDCL movw %H0, ax ; end of mulsi macro" [(set_attr "valloc" "macax")] ) + +(define_expand "es_addr" + [(unspec:SI [(reg:QI ES_REG) + (match_operand:HI 0 "" "") + ] UNS_ES_ADDR)] + "" + "" +) Index: config/rl78/rl78.c =================================================================== --- config/rl78/rl78.c (revision 202665) +++ config/rl78/rl78.c (working copy) @@ -855,12 +855,16 @@ rl78_is_legitimate_constant (enum machin bool rl78_as_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x, bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED) { rtx base, index, addend; + if (GET_CODE (x) == UNSPEC + && XINT (x, 1) == UNS_ES_ADDR) + x = XVECEXP (x, 0, 1); + if (as == ADDR_SPACE_GENERIC && GET_MODE (x) == SImode) return false; if (! characterize_address (x, &base, &index, &addend)) return false; @@ -1287,13 +1291,16 @@ rl78_print_operand_1 (FILE * file, rtx o case MEM: if (letter == 'A') rl78_print_operand_1 (file, XEXP (op, 0), letter); else { if (rl78_far_p (op)) - fprintf (file, "es:"); + { + fprintf (file, "es:"); + op = gen_rtx_MEM (GET_MODE (op), XVECEXP (XEXP (op, 0), 0, 1)); + } if (letter == 'H') { op = adjust_address (op, HImode, 2); letter = 0; } if (letter == 'h') @@ -1844,12 +1851,14 @@ During devirtualization, a simple regist would be better to run a full CSE/propogation pass on it through, or re-run regmove, but that has not yet been attempted. */ #define DEBUG_ALLOC 0 +#define OP(x) (*recog_data.operand_loc[x]) + /* This array is used to hold knowledge about the contents of the real registers (A ... H), the memory-based registers (r8 ... r31) and the first NUM_STACK_LOCS words on the stack. We use this to avoid generating redundant move instructions. A value in the range 0 .. 31 indicates register A .. r31. @@ -2069,19 +2078,45 @@ already_contains (rtx loc, rtx value) if (GET_MODE (loc) == HImode) return content_memory [index + 1] == val + 1; return true; } +bool +rl78_es_addr (rtx addr) +{ + if (GET_CODE (addr) == MEM) + addr = XEXP (addr, 0); + if (GET_CODE (addr) != UNSPEC) + return false; + if (XINT (addr, 1) != UNS_ES_ADDR) + return false; + return true; +} + +rtx +rl78_es_base (rtx addr) +{ + if (GET_CODE (addr) == MEM) + addr = XEXP (addr, 0); + addr = XVECEXP (addr, 0, 1); + if (GET_CODE (addr) == CONST + && GET_CODE (XEXP (addr, 0)) == ZERO_EXTRACT) + addr = XEXP (XEXP (addr, 0), 0); + /* Mode doesn't matter here. */ + return gen_rtx_MEM (HImode, addr); +} + /* Rescans an insn to see if it's recognized again. This is done carefully to ensure that all the constraint information is accurate for the newly matched insn. */ static bool insn_ok_now (rtx insn) { rtx pattern = PATTERN (insn); + int i; INSN_CODE (insn) = -1; if (recog (pattern, insn, 0) > -1) { extract_insn (insn); @@ -2092,12 +2127,20 @@ insn_ok_now (rtx insn) debug_rtx (insn); fprintf (stderr, "\033[0m"); #endif if (SET_P (pattern)) record_content (SET_DEST (pattern), SET_SRC (pattern)); + /* We need to detect far addresses that haven't been + converted to es/lo16 format. */ + for (i=0; i<recog_data.n_operands; i++) + if (GET_CODE (OP(i)) == MEM + && GET_MODE (XEXP (OP(i), 0)) == SImode + && GET_CODE (XEXP (OP(i), 0)) != UNSPEC) + return false; + return true; } } else { /* We need to re-recog the insn with virtual registers to get @@ -2152,14 +2195,12 @@ insn_ok_now (rtx insn) #define AX gen_rtx_REG (HImode, 0) #define BC gen_rtx_REG (HImode, 2) #define DE gen_rtx_REG (HImode, 4) #define HL gen_rtx_REG (HImode, 6) -#define OP(x) (*recog_data.operand_loc[x]) - /* Returns TRUE if R is a virtual register. */ static bool is_virtual_register (rtx r) { return (GET_CODE (r) == REG && REGNO (r) >= 8 @@ -2192,20 +2233,26 @@ EM2 (int line ATTRIBUTE_UNUSED, rtx r) #define EM(x) EM2 (__LINE__, x) /* Return a suitable RTX for the low half of a __far address. */ static rtx rl78_lo16 (rtx addr) { + rtx r; + if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST) { - rtx r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0)); + r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0)); r = gen_rtx_CONST (HImode, r); - return r; } - return rl78_subreg (HImode, addr, SImode, 0); + else + r = rl78_subreg (HImode, addr, SImode, 0); + + r = gen_es_addr (r); + + return r; } /* Return a suitable RTX for the high half's lower byte of a __far address. */ static rtx rl78_hi8 (rtx addr) { @@ -2303,12 +2350,13 @@ gen_and_emit_move (rtx to, rtx from, rtx return M. Any needed insns are emitted before BEFORE. */ static rtx transcode_memory_rtx (rtx m, rtx newbase, rtx before) { rtx base, index, addendr; int addend = 0; + int need_es = 0; if (! MEM_P (m)) return m; if (GET_MODE (XEXP (m, 0)) == SImode) { @@ -2319,12 +2367,13 @@ transcode_memory_rtx (rtx m, rtx newbase #endif emit_insn_before (EM (gen_movqi (A, seg)), before); emit_insn_before (EM (gen_movqi_es (A)), before); record_content (A, NULL_RTX); m = change_address (m, GET_MODE (m), rl78_lo16 (XEXP (m, 0))); + need_es = 1; } characterize_address (XEXP (m, 0), & base, & index, & addendr); gcc_assert (index == NULL_RTX); #if DEBUG_ALLOC @@ -2378,13 +2427,16 @@ transcode_memory_rtx (rtx m, rtx newbase } #if DEBUG_ALLOC fprintf (stderr, "\033[33m"); debug_rtx (m); #endif - m = change_address (m, GET_MODE (m), base); + if (need_es) + m = change_address (m, GET_MODE (m), gen_es_addr (base)); + else + m = change_address (m, GET_MODE (m), base); #if DEBUG_ALLOC debug_rtx (m); fprintf (stderr, "\033[0m"); #endif return m; }