diff mbox

RX: 4.5 branch: Fix alignment and addressing issues.

Message ID m3k4fzs2v1.fsf@redhat.com
State New
Headers show

Commit Message

Nick Clifton March 16, 2011, 11:48 a.m. UTC
Hi Guys,

  I am checking in the attached patch to fix some regressions in the RX
  port with regard to alignment and addressing modes.  With this patch
  applied I have 18 fewer failures in the GCC testsuite.

Cheers
  Nick

gcc/ChangeLog
2011-03-16  Nick Clifton  <nickc@redhat.com>

	* config/rx/rx.h (JUMP_ALIGN): Define.
	(JUMP_ALIGN_MAX_SKIP, LABEL_ALIGN_AFTER_BARRIER, LOOP_ALIGN,
	(LABEL_ALIGN, LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP,
	(LOOP_ALIGN_MAX_SKIP, LABEL_ALIGN_MAX_SKIP): Define.
	* config/rx/rx-protos.h (rx_align_for_label): Prototype.
	(rx_max_skip_for_label): Prototype.
	* config/rx/rx.md (abssi3): Use CC_ZSmode.
	(andis3): Fix timings.
	(peephole): Add peephole to combine zero- and sign- extending
	loads with arithmetic instructions.
	(bset): Fix timing.
	(bclr): Fix timing.
	* config/rx/rx.c (rx_is_legitimate_address): Add checks for QImode
	and HImode reg+int address.
	(rx_print_operand): Add support for %R.  Fix generation of .B and
	.W addressing modes.
	(rx_align_for_label): New function.
	(rx_max_skip_for_label): New function.

Comments

Richard Henderson March 16, 2011, 5:12 p.m. UTC | #1
On 03/16/2011 04:48 AM, Nick Clifton wrote:
> 	(peephole): Add peephole to combine zero- and sign- extending
> 	loads with arithmetic instructions.

Do you really need peepholes for this?  I would have thought that
merely adding the instruction patterns for this would have been
enough to encourage combine to do its job merging these patterns...


r~
Nick Clifton March 16, 2011, 5:59 p.m. UTC | #2
Hi Richard,

> Do you really need peepholes for this?  I would have thought that
> merely adding the instruction patterns for this would have been
> enough to encourage combine to do its job merging these patterns...

I thought so too, but I found in my tests that combine was missing 
plenty of cases where the optimization could take place.  Hence I added 
the peepholes.  (I admit that I did not delve deeply into *why* combine 
was not using my instruction pattens, I just found that the peepholes 
worked).  Plus I reasoned that the peepholes could not hurt...

Cheers
   Nick
Andrew Pinski March 16, 2011, 7:05 p.m. UTC | #3
On Wed, Mar 16, 2011 at 4:48 AM, Nick Clifton <nickc@redhat.com> wrote:
> Hi Guys,
>
>  I am checking in the attached patch to fix some regressions in the RX
>  port with regard to alignment and addressing modes.  With this patch
>  applied I have 18 fewer failures in the GCC testsuite.

> +   (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME: If we defined separate patterns
> +)                            ;; rather than using iterators we could specify exact sizes.

You can set up the correct length even without using separate patterns.
An example can be found in mips/mips.md:
(define_insn "*div<mode>3"
  [(set (match_operand:ANYF 0 "register_operand" "=f")
	(div:ANYF (match_operand:ANYF 1 "register_operand" "f")
		  (match_operand:ANYF 2 "register_operand" "f")))]
  "<divide_condition>"
{
  if (TARGET_FIX_SB1)
    return "div.<fmt>\t%0,%1,%2\;mov.<fmt>\t%0,%0";
  else
    return "div.<fmt>\t%0,%1,%2";
}
  [(set_attr "type" "fdiv")
   (set_attr "mode" "<UNITMODE>")
   (set (attr "length")
        (if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
                      (const_int 8)
                      (const_int 4)))])

Thanks,
Andrew Pinski
Mike Stump March 16, 2011, 8:41 p.m. UTC | #4
On Mar 16, 2011, at 10:12 AM, Richard Henderson wrote:
> On 03/16/2011 04:48 AM, Nick Clifton wrote:
>> 	(peephole): Add peephole to combine zero- and sign- extending
>> 	loads with arithmetic instructions.
> 
> Do you really need peepholes for this?  I would have thought that
> merely adding the instruction patterns for this would have been
> enough to encourage combine to do its job merging these patterns...

I've caught 4.5.x not handling really, really simple things like:

unsigned char ub;
unsigned short us;
unsigned int ui;
unsigned long ul;
signed char sb;
signed short ss;
signed int si;
signed long sl;

main() {
  us = ub;
  ui = us;
}

because there were two zero_extends, instead of just one, my patterns only covered 1.  I've love a more comprehensive solution, where I can explain my loads can do either sign or zero extend, and simply not have to worry about all the knock on patterns.  Another nit, I had a QI->DI extending load pattern, but when asked to do a QI-SI load, it didn't want to widen to a QI->DI load and then just subreg the SI part.  :-(  The scary thing, it isn't like zero extension is a brand new instruction that had been invented last week.
Mike Stump March 16, 2011, 8:46 p.m. UTC | #5
On Mar 16, 2011, at 12:05 PM, Andrew Pinski wrote:
>> +   (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME: If we defined separate patterns
>> +)                            ;; rather than using iterators we could specify exact sizes.
> 
> You can set up the correct length even without using separate patterns.

and you can also run match_operand in these things as well...  :-)

[(set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
        (const_string "alu_shift")
        (const_string "alu_shift_reg")))]
Nick Clifton March 17, 2011, 12:31 p.m. UTC | #6
Hi Andrew,

>> +   (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME: If we defined separate patterns
>> +)                            ;; rather than using iterators we could specify exact sizes.
>
> You can set up the correct length even without using separate patterns.

The problem is that the lengths depend upon an *two* iterators and the 
MEM involved as well.  For example:

   (define_insn "*comparesi3_<extend_types:code><small_int_modes:mode>"
     [(set (reg:CC CC_REG)
	  (compare:CC (match_operand:SI
                          0 "register_operand" "=r")
                       (extend_types:SI (match_operand:small_int_modes
                          1 "rx_restricted_mem_operand" "Q"))))]
     ""
     "cmp\t%<extend_types:letter>1, %0"
     [(set_attr "timings" "33")
      (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME:

This insn is 2 bytes long if operand[1] is just MEM (REG) (ie no offset) 
*and* the extend_types is zero-extend.  It is 3 bytes long if 
operands[1] is MEM (REG) and the extend_types is sign-extend.  It is 
also 3 bytes long if operands[1] is MEM (REG+INT) and the INT is < 256 
(for QImode extensions) or less than (256 * 2) for HImode extensions and 
the extend type is zero-extend.  It is 4 bytes long if ... [snip - you 
get the idea].

So really I think that I should be defining the ADJUST_INSN_LENGTH macro 
to handle these patterns.  I'll look into that.

Cheers
   Nick
Richard Henderson March 17, 2011, 3:32 p.m. UTC | #7
On 03/17/2011 05:31 AM, Nick Clifton wrote:
> So really I think that I should be defining the ADJUST_INSN_LENGTH macro to handle these patterns.  I'll look into that.

What is length used for in the rx port?  I don't see any branch shortening
going on here; out of range branches are completely handled by the assembler.

You might be better off simply deleting the length attribute, so that the
compiler skips the bulk of the shorten_branches pass.


r~
DJ Delorie March 17, 2011, 4:30 p.m. UTC | #8
> What is length used for in the rx port?

We have a local patch that uses the length to decide if/when to align
labels; it goes along with the label alignment change I made a while
back.  However, the patch works best in 4.5 (align patch not
backported) and there are other optimization problems with 4.6 that
make the alignment not work as well as it should.

The RX incurs a one-cycle penalty if you branch to an insn that spans
a fetch line.  So, we want to align by adding no more than N-1 bytes
for an N-byte insn.  A 3-byte insn will only be aligned if doing so
adds 1 or 2 bytes; if 3 bytes are needed, the insn does not span a
fetch line.
Mike Stump March 17, 2011, 7:28 p.m. UTC | #9
On Mar 17, 2011, at 5:31 AM, Nick Clifton wrote:
>> You can set up the correct length even without using separate patterns.
> 
> The problem is

And why is that a problem?  You get to write arbitrarily complex C code that can depend upon insn and operands.  I presume that you can do that.

See:

   (set (attr "length") (symbol_ref "arm_attr_length_move_neon (insn)"))])

from arm, for example.
Nick Clifton March 18, 2011, 8:23 a.m. UTC | #10
Hi Richard,

> What is length used for in the rx port?  I don't see any branch shortening
> going on here; out of range branches are completely handled by the assembler.
>
> You might be better off simply deleting the length attribute, so that the
> compiler skips the bulk of the shorten_branches pass.

Darn - I feel like a complete idiot!  You are right of course - the 
length attribute is not used at all.  Adding the attribute was just 
habitual, I never thought to check to see if it was really needed.

I'll make a patch to remove the lengths and check it in shortly.

Cheers
   Nick
Nick Clifton March 18, 2011, 8:38 a.m. UTC | #11
Hi Mike,

> And why is that a problem?  You get to write arbitrarily complex C code that can depend upon insn and operands.

Ah - I did not know this.  I thought that you had to stick to RTL 
expressions in the definition of attributes.  Thanks for letting me know 
otherwise.

Cheers
   Nick
diff mbox

Patch

Index: gcc/config/rx/rx.h
===================================================================
--- gcc/config/rx/rx.h	(revision 171032)
+++ gcc/config/rx/rx.h	(working copy)
@@ -663,3 +663,28 @@ 
   
 #define SELECT_CC_MODE(OP,X,Y)  rx_select_cc_mode ((OP), (X), (Y))
 
+#define JUMP_ALIGN(x)				rx_align_for_label (x)
+#define JUMP_ALIGN_MAX_SKIP			rx_max_skip_for_label (label)
+#define LABEL_ALIGN_AFTER_BARRIER(x)		rx_align_for_label (x)
+#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP	rx_max_skip_for_label (label)
+#define LOOP_ALIGN(x)				rx_align_for_label (x)
+#define LOOP_ALIGN_MAX_SKIP			rx_max_skip_for_label (label)
+#define LABEL_ALIGN(x)				rx_align_for_label (x)
+#define LABEL_ALIGN_MAX_SKIP			rx_max_skip_for_label (NULL_RTX)
+
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM, LOG, MAX_SKIP)	\
+  do						\
+    {						\
+      if ((LOG) == 0 || (MAX_SKIP) == 0)	\
+        break;					\
+      if (TARGET_AS100_SYNTAX)			\
+	{					\
+	  if ((LOG) >= 2)			\
+	    fprintf (STREAM, "\t.ALIGN 4\t; %d alignment actually requested\n", 1 << (LOG)); \
+	  else					\
+	    fprintf (STREAM, "\t.ALIGN 2\n");	\
+	}					\
+      else					\
+	fprintf (STREAM, "\t.balign %d,3,%d\n", 1 << (LOG), (MAX_SKIP));	\
+    }						\
+  while (0)
Index: gcc/config/rx/rx-protos.h
===================================================================
--- gcc/config/rx/rx-protos.h	(revision 171032)
+++ gcc/config/rx/rx-protos.h	(working copy)
@@ -31,6 +31,7 @@ 
 extern void		rx_set_optimization_options (void);
 
 #ifdef RTX_CODE
+extern int 		rx_align_for_label (rtx);
 extern bool		rx_compare_redundant (rtx);
 extern void             rx_emit_stack_popm (rtx *, bool);
 extern void             rx_emit_stack_pushm (rtx *);
@@ -41,6 +42,7 @@ 
 extern bool 		rx_is_mode_dependent_addr (rtx);
 extern bool		rx_is_restricted_memory_address (rtx, Mmode);
 extern bool		rx_match_ccmode (rtx, Mmode);
+extern int		rx_max_skip_for_label (rtx);
 extern void		rx_notice_update_cc (rtx body, rtx insn);
 extern void		rx_print_operand (FILE *, rtx, int);
 extern void		rx_print_operand_address (FILE *, rtx);
Index: gcc/config/rx/rx.md
===================================================================
--- gcc/config/rx/rx.md	(revision 171032)
+++ gcc/config/rx/rx.md	(working copy)
@@ -798,7 +798,10 @@ 
    (set (reg CC_REG)
 	(compare (abs:SI (match_dup 1))
 		 (const_int 0)))]
-  "reload_completed && rx_match_ccmode (insn, CC_ZSOmode)"
+  ;; Note - although the ABS instruction does set the O bit in the processor
+  ;; status word, it does not do so in a way that is comparable with the CMP
+  ;; instruction.  Hence we use CC_ZSmode rather than CC_ZSOmode.
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
   "@
   abs\t%0
   abs\t%1, %0"
@@ -1005,7 +1008,7 @@ 
   and\t%1, %0
   and\t%2, %1, %0
   and\t%Q2, %0"
-  [(set_attr "timings" "11,11,11,11,11,11,11,33,33")
+  [(set_attr "timings" "11,11,11,11,11,11,11,11,33")
    (set_attr "length" "2,2,3,4,5,6,2,5,5")]
 )
 
@@ -1027,7 +1030,7 @@ 
   and\t%1, %0
   and\t%2, %1, %0
   and\t%Q2, %0"
-  [(set_attr "timings" "11,11,11,11,11,11,11,33,33")
+  [(set_attr "timings" "11,11,11,11,11,11,11,11,33")
    (set_attr "length" "2,2,3,4,5,6,2,5,5")]
 )
 
@@ -1543,6 +1546,139 @@ 
    (set_attr "length" "3,4,5,6,7,6")]
 )
 
+;; A set of peepholes to catch extending loads followed by arithmetic operations.
+;; We use iterators where possible to reduce the amount of typing and hence the
+;; possibilities for typos.
+
+(define_code_iterator extend_types [(zero_extend "") (sign_extend "")])
+(define_code_attr     letter       [(zero_extend "R") (sign_extend "Q")])
+
+(define_code_iterator memex_commutative [(plus "") (and "") (ior "") (xor "")])
+(define_code_iterator memex_noncomm     [(div "") (udiv "") (minus "")])
+(define_code_iterator memex_nocc        [(smax "") (smin "") (mult "")])
+
+(define_code_attr     op                [(plus "add") (and "and") (div "div") (udiv "divu") (smax "max") (smin "min") (mult "mul") (ior "or") (minus "sub") (xor "xor")])
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+	(extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+		   (memex_commutative:SI (match_dup 0)
+					 (match_dup 2)))
+	      (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(parallel [(set:SI (match_dup 2)
+		      (memex_commutative:SI (match_dup 2)
+					    (extend_types:SI (match_dup 1))))
+	      (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+	(extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+		   (memex_commutative:SI (match_dup 2)
+					 (match_dup 0)))
+	      (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(parallel [(set:SI (match_dup 2)
+		      (memex_commutative:SI (match_dup 2)
+					    (extend_types:SI (match_dup 1))))
+	      (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+	(extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+		   (memex_noncomm:SI (match_dup 2)
+				     (match_dup 0)))
+	      (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(parallel [(set:SI (match_dup 2)
+		      (memex_noncomm:SI (match_dup 2)
+					(extend_types:SI (match_dup 1))))
+	      (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+	(extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (match_operand:SI                               2 "register_operand")
+	(memex_nocc:SI (match_dup 0)
+		       (match_dup 2)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(set:SI (match_dup 2)
+	   (memex_nocc:SI (match_dup 2)
+			  (extend_types:SI (match_dup 1))))]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+	(extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (match_operand:SI                               2 "register_operand")
+	(memex_nocc:SI (match_dup 2)
+		       (match_dup 0)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(set:SI (match_dup 2)
+	   (memex_nocc:SI (match_dup 2)
+			  (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "*<memex_commutative:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                                     0 "register_operand" "=r")
+	(memex_commutative:SI (match_operand:SI                               1 "register_operand" "%0")
+ 		              (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "<memex_commutative:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME: If we defined separate patterns 
+)                            ;; rather than using iterators we could specify exact sizes.
+
+(define_insn "*<memex_noncomm:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                                 0 "register_operand" "=r")
+	(memex_noncomm:SI (match_operand:SI                               1 "register_operand" "0")
+                          (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "<memex_noncomm:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME: If we defined separate patterns 
+)                            ;; rather than using iterators we could specify exact sizes.
+
+(define_insn "*<memex_nocc:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                              0 "register_operand" "=r")
+	(memex_nocc:SI (match_operand:SI                               1 "register_operand" "%0")
+		       (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))]
+  ""
+  "<memex_nocc:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME: If we defined separate patterns 
+)                            ;; rather than using iterators we could specify exact sizes.
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+	(extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (reg:CC CC_REG)
+	(compare:CC (match_operand:SI                   2 "register_operand")
+		    (match_dup 0)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(set (reg:CC CC_REG)
+	(compare:CC (match_dup 2)
+		    (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "*comparesi3_<extend_types:code><small_int_modes:mode>"
+  [(set (reg:CC CC_REG)
+	(compare:CC (match_operand:SI                               0 "register_operand" "=r")
+		    (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand" "Q"))))]
+  ""
+  "cmp\t%<extend_types:letter>1, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; Worst case sceanario.  FIXME: If we defined separate patterns 
+)                            ;; rather than using iterators we could specify exact sizes.
+
 ;; Floating Point Instructions
 
 (define_insn "addsf3"
@@ -1641,7 +1777,7 @@ 
   ""
   "bset\t%1, %0.B"
   [(set_attr "length" "3")
-   (set_attr "timings" "34")]
+   (set_attr "timings" "33")]
 )
 
 (define_insn "*bitinvert"
@@ -1687,7 +1823,7 @@ 
   ""
   "bclr\t%1, %0.B"
   [(set_attr "length" "3")
-   (set_attr "timings" "34")]
+   (set_attr "timings" "33")]
 )
 
 (define_insn "*insv_imm"
Index: gcc/config/rx/rx.c
===================================================================
--- gcc/config/rx/rx.c	(revision 171032)
+++ gcc/config/rx/rx.c	(working copy)
@@ -80,7 +80,9 @@ 
     /* Register Indirect.  */
     return true;
 
-  if (GET_MODE_SIZE (mode) == 4
+  if ((GET_MODE_SIZE (mode) == 4
+       || GET_MODE_SIZE (mode) == 2
+       || GET_MODE_SIZE (mode) == 1)
       && (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC))
     /* Pre-decrement Register Indirect or
        Post-increment Register Indirect.  */
@@ -182,8 +184,11 @@ 
       base = XEXP (mem, 0);
       index = XEXP (mem, 1);
 
-      return RX_REG_P (base) && CONST_INT_P (index);
+      if (! RX_REG_P (base) || ! CONST_INT_P (index))
+	  return false;
 
+      return IN_RANGE (INTVAL (index), 0, (0x10000 * GET_MODE_SIZE (mode)) - 1);
+
     case SYMBOL_REF:
       /* Can happen when small data is being supported.
          Assume that it will be resolved into GP+INT.  */
@@ -447,11 +452,14 @@ 
      %L  Print low part of a DImode register, integer or address.
      %N  Print the negation of the immediate value.
      %Q  If the operand is a MEM, then correctly generate
-         register indirect or register relative addressing.  */
+         register indirect or register relative addressing.
+     %R  Like %Q but for zero-extending loads.  */
 
 void
 rx_print_operand (FILE * file, rtx op, int letter)
 {
+  bool unsigned_load = false;
+
   switch (letter)
     {
     case 'A':
@@ -615,10 +623,15 @@ 
       rx_print_integer (file, - INTVAL (op));
       break;
 
+    case 'R':
+      gcc_assert (GET_MODE_SIZE (GET_MODE (op)) < 4);
+      unsigned_load = true;
+      /* Fall through.  */
     case 'Q':
       if (MEM_P (op))
 	{
 	  HOST_WIDE_INT offset;
+	  rtx mem = op;
 
 	  op = XEXP (op, 0);
 
@@ -653,22 +666,24 @@ 
 	  rx_print_operand (file, op, 0);
 	  fprintf (file, "].");
 
-	  switch (GET_MODE_SIZE (GET_MODE (op)))
+	  switch (GET_MODE_SIZE (GET_MODE (mem)))
 	    {
 	    case 1:
-	      gcc_assert (offset < 65535 * 1);
-	      fprintf (file, "B");
+	      gcc_assert (offset <= 65535 * 1);
+	      fprintf (file, unsigned_load ? "UB" : "B");
 	      break;
 	    case 2:
 	      gcc_assert (offset % 2 == 0);
-	      gcc_assert (offset < 65535 * 2);
-	      fprintf (file, "W");
+	      gcc_assert (offset <= 65535 * 2);
+	      fprintf (file, unsigned_load ? "UW" : "W");
 	      break;
-	    default:
+	    case 4:
 	      gcc_assert (offset % 4 == 0);
-	      gcc_assert (offset < 65535 * 4);
+	      gcc_assert (offset <= 65535 * 4);
 	      fprintf (file, "L");
 	      break;
+	    default:
+	      gcc_unreachable ();
 	    }
 	  break;
 	}
@@ -2656,6 +2671,36 @@ 
   return true;
 }
 
+int
+rx_align_for_label (rtx lab ATTRIBUTE_UNUSED)
+{
+  return optimize_size ? 1 : 3;
+}
+
+int
+rx_max_skip_for_label (rtx lab)
+{
+  int opsize;
+  rtx op;
+
+  if (lab == NULL_RTX)
+    return 0;
+  op = lab;
+  do
+    {
+      op = next_nonnote_insn (op);
+    }
+  while (op && (LABEL_P (op)
+		|| (INSN_P (op) && GET_CODE (PATTERN (op)) == USE)));
+  if (!op)
+    return 0;
+
+  opsize = get_attr_length (op);
+  if (opsize >= 0 && opsize < 8)
+    return opsize - 1;
+  return 0;
+}
+
 #undef  TARGET_FUNCTION_VALUE
 #define TARGET_FUNCTION_VALUE		rx_function_value