Patchwork [rl78] fix far address optimizations

login
register
mail settings
Submitter DJ Delorie
Date Sept. 17, 2013, 9:01 p.m.
Message ID <201309172101.r8HL15Tb009170@greed.delorie.com>
Download mbox | patch
Permalink /patch/275541/
State New
Headers show

Comments

DJ Delorie - Sept. 17, 2013, 9:01 p.m.
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.

Patch

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;
 }