diff mbox

[AVR] : Clean up SFR offset usage.

Message ID 4EC81070.9020707@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay Nov. 19, 2011, 8:24 p.m. UTC
Subtracting 0x20 to get the SFR address from a RAM address is scattered all
over the backend.  The patch makes - PRINT_OPERAND_PUNCT_VALID_P and uses %- to
subtract the SFR offset instead of hard coded magic number 0x20 all over the
place.  The offset is stored in a new field base_arch_s.sfr_offset

Code of out_movhi_r_mr, out_movhi_mr_r, out_shift_with_cnt undergoes clean-up, too.

output_reload_in_const is generic enough to handle 3- and 4- byte symbols.

Tested without regressions.

Ok for trunk?

Johann

	* config/avr/avr.h (PRINT_OPERAND_PUNCT_VALID_P): Add '-'.
	(struct base_arch_s): Add field sfr_offset.
	* config/avr/avr-devices.c: Ditto. And initialize it.
	* config/avr/avr-c.c (avr_cpu_cpp_builtins): New built-in define
	__AVR_SFR_OFFSET__.
	* config/avr/avr-protos.h (out_movqi_r_mr, out_movqi_mr_r): Remove.
	(out_movhi_r_mr, out_movhi_mr_r): Remove.
	(out_movsi_r_mr, out_movsi_mr_r): Remove.
	(*cbi, *sbi): Use %- instead of magic number 0x20.
	(*insv.io*, insv.not.io): Ditto.
	* config/avr/avr.c (out_movsi_r_mr, out_movsi_mr_r): Make static.
	(print_operand): Map "%-" to subtractio of SFR offset.
	(output_movqi): Clean up call of out_movqi_mr_r.
	(output_movhi): Clean up call of out_movhi_mr_r.
	(avr_file_start): Use avr_current_arch->sfr_offset instead of
	magic -0x20. Use TMP_REGNO, ZERO_REGNO instead of 0, 1.
	(avr_out_sbxx_branch): Use %- instead of magic -0x20.
	(out_movqi_r_mr, out_movqi_mr_r): Ditto. And make static.
	(out_movhi_r_mr, out_movhi_mr_r): Ditto. And use avr_asm_len.
	(out_shift_with_cnt): Clean up code and: Use avr_asm_len.
	(output_movsisf): Use output_reload_insisf for all CONSTANT_P sources.
	(avr_out_movpsi): USE avr_out_reload_inpsi for all CONSTANT_P sources.
	Clean up call of avr_out_store_psi.
	(output_reload_in_const): Don't cut symbols longer than 2 bytes.
	(output_reload_insisf): Filter CONST_INT_P or CONST_DOUBLE_P to
	try if setting pre-cleared register is advantageous.

Comments

Denis Chertykov Nov. 20, 2011, 7:28 a.m. UTC | #1
2011/11/20 Georg-Johann Lay <avr@gjlay.de>:
> Subtracting 0x20 to get the SFR address from a RAM address is scattered all
> over the backend.  The patch makes - PRINT_OPERAND_PUNCT_VALID_P and uses %- to
> subtract the SFR offset instead of hard coded magic number 0x20 all over the
> place.  The offset is stored in a new field base_arch_s.sfr_offset

I don't like '%-' as a sequence and I don't like it as a suffix.
May be a right way is an adding a new prefix '%i' or '%I'.
I.e.
  %m0 - memory address
  %i0 - io address (equal to %m0 - 0x20)

Denis.
diff mbox

Patch

Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md	(revision 181510)
+++ config/avr/avr.md	(working copy)
@@ -34,6 +34,8 @@ 
 ;;..x..Constant Direct Program memory address.
 ;;  ~  Output 'r' if not AVR_HAVE_JMP_CALL.
 ;;  !  Output 'e' if AVR_HAVE_EIJMP_EICALL.
+;;  -  Output '-0x20', i.e. subtraction of offset between RAM address
+;;     and SFR address.
 
 
 (define_constants
@@ -45,12 +47,12 @@  (define_constants
    (LPM_REGNO	0)	; implicit target register of LPM
    (TMP_REGNO	0)	; temporary register r0
    (ZERO_REGNO	1)	; zero register r1
-   
-   (SREG_ADDR   0x5F)
-   (SP_ADDR     0x5D)
 
-   ;; Register holding the address' high part when loading via ELPM
-   (RAMPZ_ADDR  0x5B)
+   ;; RAM addresses of some SFRs common to all Devices.
+
+   (SREG_ADDR   0x5F)   ; Status Register
+   (SP_ADDR     0x5D)   ; Stack Pointer
+   (RAMPZ_ADDR  0x5B)   ; Address' high part when loading via ELPM
    ])
 
 (define_c_enum "unspec"
@@ -4658,25 +4660,25 @@  (define_insn "sez"
 
 (define_insn "*cbi"
   [(set (mem:QI (match_operand 0 "low_io_address_operand" "n"))
-	(and:QI (mem:QI (match_dup 0))
-		(match_operand:QI 1 "single_zero_operand" "n")))]
-  "(optimize > 0)"
-{
-  operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
-  return AS2 (cbi,%m0-0x20,%2);
-}
+        (and:QI (mem:QI (match_dup 0))
+                (match_operand:QI 1 "single_zero_operand" "n")))]
+  "optimize > 0"
+  {
+    operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
+    return "cbi %m0%-,%2";
+  }
   [(set_attr "length" "1")
    (set_attr "cc" "none")])
 
 (define_insn "*sbi"
   [(set (mem:QI (match_operand 0 "low_io_address_operand" "n"))
-	(ior:QI (mem:QI (match_dup 0))
-		(match_operand:QI 1 "single_one_operand" "n")))]
-  "(optimize > 0)"
-{
-  operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
-  return AS2 (sbi,%m0-0x20,%2);
-}
+        (ior:QI (mem:QI (match_dup 0))
+                (match_operand:QI 1 "single_one_operand" "n")))]
+  "optimize > 0"
+  {
+    operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
+    return "sbi %m0%-,%2";
+  }
   [(set_attr "length" "1")
    (set_attr "cc" "none")])
 
@@ -5635,9 +5637,9 @@  (define_insn "*insv.io"
         (match_operand:QI 2 "nonmemory_operand"                            "L,P,r"))]
   ""
   "@
-	cbi %m0-0x20,%1
-	sbi %m0-0x20,%1
-	sbrc %2,0\;sbi %m0-0x20,%1\;sbrs %2,0\;cbi %m0-0x20,%1"
+	cbi %m0%-,%1
+	sbi %m0%-,%1
+	sbrc %2,0\;sbi %m0%-,%1\;sbrs %2,0\;cbi %m0%-,%1"
   [(set_attr "length" "1,1,4")
    (set_attr "cc" "none")])
 
@@ -5647,7 +5649,7 @@  (define_insn "*insv.not.io"
                          (match_operand:QI 1 "const_0_to_7_operand"        "n"))
         (not:QI (match_operand:QI 2 "register_operand"                     "r")))]
   ""
-  "sbrs %2,0\;sbi %m0-0x20,%1\;sbrc %2,0\;cbi %m0-0x20,%1"
+  "sbrs %2,0\;sbi %m0%-,%1\;sbrc %2,0\;cbi %m0%-,%1"
   [(set_attr "length" "4")
    (set_attr "cc" "none")])
 
Index: config/avr/avr-devices.c
===================================================================
--- config/avr/avr-devices.c	(revision 181510)
+++ config/avr/avr-devices.c	(working copy)
@@ -29,23 +29,23 @@  const struct base_arch_s
 avr_arch_types[] =
 {
   /* unknown device specified */
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 1, NULL,               "avr2" },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, NULL,              "avr2"  },
   /*
-    A  M  J  L  E  E  E         d  S   # F
-    S  U  M  P  L  L  I         a  t   6 l 
-    M  L  P  M  P  P  J  -  -   t  a   4 a   
-             X  M  M  M         a  r     s
-                   X  P            t   k h  */
-  { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=1",   "avr1" },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=2",   "avr2" },
-  { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=25",  "avr25" },
-  { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=3",   "avr3" },
-  { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 2, "__AVR_ARCH__=31",  "avr31" },
-  { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=35",  "avr35" },
-  { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=4",   "avr4" },
-  { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=5",   "avr5" },
-  { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 2, "__AVR_ARCH__=51",  "avr51" },
-  { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 4, "__AVR_ARCH__=6",   "avr6" }
+    A  M  J  L  E  E  E         d S   S O  # F
+    S  U  M  P  L  L  I         a t   F f  6 l 
+    M  L  P  M  P  P  J  -  -   t a   R s  4 a   
+             X  M  M  M         a r     e    s
+                   X  P           t     t  k h  */
+  { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=1",  "avr1"  },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=2",  "avr2"  },
+  { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=25", "avr25" },
+  { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=3",  "avr3"  },
+  { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 32, 2, "__AVR_ARCH__=31", "avr31" },
+  { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=35", "avr35" },
+  { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=4",  "avr4"  },
+  { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=5",  "avr5"  },
+  { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, 2, "__AVR_ARCH__=51", "avr51" },
+  { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 32, 4, "__AVR_ARCH__=6",  "avr6"  }
 };
 
 const struct mcu_type_s avr_mcu_types[] = {
Index: config/avr/avr-c.c
===================================================================
--- config/avr/avr-c.c	(revision 181510)
+++ config/avr/avr-c.c	(working copy)
@@ -106,6 +106,9 @@  avr_cpu_cpp_builtins (struct cpp_reader
         cpp_define (pfile, "__AVR_ERRATA_SKIP_JMP_CALL__");
     }
 
+  cpp_define_formatted (pfile, "__AVR_SFR_OFFSET__=0x%x",
+                        avr_current_arch->sfr_offset);
+    
   /* Define builtin macros so that the user can easily query if or if not
      non-generic address spaces (and which) are supported.
      This is only supported for C.  For C++, a language extension is needed
Index: config/avr/avr-protos.h
===================================================================
--- config/avr/avr-protos.h	(revision 181510)
+++ config/avr/avr-protos.h	(working copy)
@@ -51,12 +51,6 @@  extern void init_cumulative_args (CUMULA
 #ifdef RTX_CODE
 extern const char *output_movqi (rtx insn, rtx operands[], int *l);
 extern const char *output_movhi (rtx insn, rtx operands[], int *l);
-extern const char *out_movqi_r_mr (rtx insn, rtx op[], int *l);
-extern const char *out_movqi_mr_r (rtx insn, rtx op[], int *l);
-extern const char *out_movhi_r_mr (rtx insn, rtx op[], int *l);
-extern const char *out_movhi_mr_r (rtx insn, rtx op[], int *l);
-extern const char *out_movsi_r_mr (rtx insn, rtx op[], int *l);
-extern const char *out_movsi_mr_r (rtx insn, rtx op[], int *l);
 extern const char *output_movsisf (rtx insn, rtx operands[], int *l);
 extern const char *avr_out_tstsi (rtx, rtx*, int*);
 extern const char *avr_out_tsthi (rtx, rtx*, int*);
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 181510)
+++ config/avr/avr.c	(working copy)
@@ -63,6 +63,13 @@ 
 
 /* Prototypes for local helper functions.  */
 
+static const char* out_movqi_r_mr (rtx, rtx[], int*);
+static const char* out_movhi_r_mr (rtx, rtx[], int*);
+static const char* out_movsi_r_mr (rtx, rtx[], int*);
+static const char* out_movqi_mr_r (rtx, rtx[], int*);
+static const char* out_movhi_mr_r (rtx, rtx[], int*);
+static const char* out_movsi_mr_r (rtx, rtx[], int*);
+
 static int avr_naked_function_p (tree);
 static int interrupt_function_p (tree);
 static int signal_function_p (tree);
@@ -1808,6 +1815,10 @@  print_operand (FILE *file, rtx x, int co
       if (AVR_HAVE_EIJMP_EICALL)
 	fputc ('e', file);
     }
+  else if (code == '-')
+    {
+      fprintf (file, "-0x%x", avr_current_arch->sfr_offset);
+    }
   else if (REG_P (x))
     {
       if (x == zero_reg_rtx)
@@ -2796,17 +2807,12 @@  output_movqi (rtx insn, rtx operands[],
     }
   else if (GET_CODE (dest) == MEM)
     {
-      const char *templ;
+      rtx xop[2];
 
-      if (src == const0_rtx)
-	operands[1] = zero_reg_rtx;
-
-      templ = out_movqi_mr_r (insn, operands, real_l);
-
-      if (!real_l)
-	output_asm_insn (templ, operands);
+      xop[0] = dest;
+      xop[1] = src == const0_rtx ? zero_reg_rtx : src;
 
-      operands[1] = src;
+      return out_movqi_mr_r (insn, xop, real_l);
     }
   return "";
 }
@@ -2877,24 +2883,18 @@  output_movhi (rtx insn, rtx operands[],
     }
   else if (GET_CODE (dest) == MEM)
     {
-      const char *templ;
-
-      if (src == const0_rtx)
-	operands[1] = zero_reg_rtx;
+      rtx xop[2];
 
-      templ = out_movhi_mr_r (insn, operands, real_l);
-
-      if (!real_l)
-	output_asm_insn (templ, operands);
+      xop[0] = dest;
+      xop[1] = src == const0_rtx ? zero_reg_rtx : src;
 
-      operands[1] = src;
-      return "";
+      return out_movhi_mr_r (insn, xop, real_l);
     }
   fatal_insn ("invalid insn:", insn);
   return "";
 }
 
-const char *
+static const char*
 out_movqi_r_mr (rtx insn, rtx op[], int *plen)
 {
   rtx dest = op[0];
@@ -2913,7 +2913,7 @@  out_movqi_r_mr (rtx insn, rtx op[], int
         }
       
       if (optimize > 0 && io_address_operand (x, QImode))
-        return avr_asm_len ("in %0,%m1-0x20", op, plen, -1);
+        return avr_asm_len ("in %0,%m1%-", op, plen, -1);
 
       return avr_asm_len ("lds %0,%m1", op, plen, -2);
     }
@@ -2964,8 +2964,8 @@  out_movqi_r_mr (rtx insn, rtx op[], int
   return avr_asm_len ("ld %0,%1", op, plen, -1);
 }
 
-const char *
-out_movhi_r_mr (rtx insn, rtx op[], int *l)
+static const char*
+out_movhi_r_mr (rtx insn, rtx op[], int *plen)
 {
   rtx dest = op[0];
   rtx src = op[1];
@@ -2975,39 +2975,25 @@  out_movhi_r_mr (rtx insn, rtx op[], int
   /* "volatile" forces reading low byte first, even if less efficient,
      for correct operation with 16-bit I/O registers.  */
   int mem_volatile_p = MEM_VOLATILE_P (src);
-  int tmp;
-
-  if (!l)
-    l = &tmp;
 
   if (reg_base > 0)
     {
       if (reg_dest == reg_base)         /* R = (R) */
-	{
-	  *l = 3;
-	  return (AS2 (ld,__tmp_reg__,%1+) CR_TAB
-		  AS2 (ld,%B0,%1) CR_TAB
-		  AS2 (mov,%A0,__tmp_reg__));
-	}
-      else if (reg_base == REG_X)        /* (R26) */
-        {
-          if (reg_unused_after (insn, base))
-	    {
-	      *l = 2;
-	      return (AS2 (ld,%A0,X+) CR_TAB
-		      AS2 (ld,%B0,X));
-	    }
-	  *l  = 3;
-	  return (AS2 (ld,%A0,X+) CR_TAB
-		  AS2 (ld,%B0,X) CR_TAB
-		  AS2 (sbiw,r26,1));
-        }
-      else                      /* (R)  */
-	{
-	  *l = 2;
-	  return (AS2 (ld,%A0,%1)    CR_TAB
-		  AS2 (ldd,%B0,%1+1));
-	}
+        return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB
+                            "ld %B0,%1"          CR_TAB
+                            "mov %A0,__tmp_reg__", op, plen, -3);
+
+      if (reg_base != REG_X)
+        return avr_asm_len ("ld %A0,%1" CR_TAB
+                            "ldd %B0,%1+1", op, plen, -2);
+      
+      avr_asm_len ("ld %A0,X+" CR_TAB
+                   "ld %B0,X", op, plen, -2);
+          
+      if (!reg_unused_after (insn, base))
+        avr_asm_len ("sbiw r26,1", op, plen, 1);
+
+      return "";
     }
   else if (GET_CODE (base) == PLUS) /* (R + i) */
     {
@@ -3015,109 +3001,90 @@  out_movhi_r_mr (rtx insn, rtx op[], int
       int reg_base = true_regnum (XEXP (base, 0));
       
       if (disp > MAX_LD_OFFSET (GET_MODE (src)))
-	{
-	  if (REGNO (XEXP (base, 0)) != REG_Y)
-	    fatal_insn ("incorrect insn:",insn);
-	  
-	  if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
-	    return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
-			    AS2 (ldd,%A0,Y+62)    CR_TAB
-			    AS2 (ldd,%B0,Y+63)    CR_TAB
-			    AS2 (sbiw,r28,%o1-62));
+        {
+          if (REGNO (XEXP (base, 0)) != REG_Y)
+            fatal_insn ("incorrect insn:",insn);
+          
+          return disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))
+            ? avr_asm_len ("adiw r28,%o1-62" CR_TAB
+                           "ldd %A0,Y+62"    CR_TAB
+                           "ldd %B0,Y+63"    CR_TAB
+                           "sbiw r28,%o1-62", op, plen, -4)
+
+            : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB
+                           "sbci r29,hi8(-%o1)" CR_TAB
+                           "ld %A0,Y"           CR_TAB
+                           "ldd %B0,Y+1"        CR_TAB
+                           "subi r28,lo8(%o1)"  CR_TAB
+                           "sbci r29,hi8(%o1)", op, plen, -6);
+        }
+
+      /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
+         it but I have this situation with extremal
+         optimization options.  */
 
-	  return *l = 6, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
-			  AS2 (sbci,r29,hi8(-%o1)) CR_TAB
-			  AS2 (ld,%A0,Y)           CR_TAB
-			  AS2 (ldd,%B0,Y+1)        CR_TAB
-			  AS2 (subi,r28,lo8(%o1))  CR_TAB
-			  AS2 (sbci,r29,hi8(%o1)));
-	}
       if (reg_base == REG_X)
-	{
-	  /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
-	     it but I have this situation with extremal
-	     optimization options.  */
-	  
-	  *l = 4;
-	  if (reg_base == reg_dest)
-	    return (AS2 (adiw,r26,%o1)      CR_TAB
-		    AS2 (ld,__tmp_reg__,X+) CR_TAB
-		    AS2 (ld,%B0,X)          CR_TAB
-		    AS2 (mov,%A0,__tmp_reg__));
-
-	  return (AS2 (adiw,r26,%o1) CR_TAB
-		  AS2 (ld,%A0,X+)    CR_TAB
-		  AS2 (ld,%B0,X)     CR_TAB
-		  AS2 (sbiw,r26,%o1+1));
-	}
+        return reg_base == reg_dest
+          ? avr_asm_len ("adiw r26,%o1"      CR_TAB
+                         "ld __tmp_reg__,X+" CR_TAB
+                         "ld %B0,X"          CR_TAB
+                         "mov %A0,__tmp_reg__", op, plen, -4)
+
+          : avr_asm_len ("adiw r26,%o1" CR_TAB
+                         "ld %A0,X+"    CR_TAB
+                         "ld %B0,X"     CR_TAB
+                         "sbiw r26,%o1+1", op, plen, -4);
+
+      return reg_base == reg_dest
+        ? avr_asm_len ("ldd __tmp_reg__,%A1" CR_TAB
+                       "ldd %B0,%B1"         CR_TAB
+                       "mov %A0,__tmp_reg__", op, plen, -3)
 
-      if (reg_base == reg_dest)
-	{
-	  *l = 3;
-	  return (AS2 (ldd,__tmp_reg__,%A1) CR_TAB
-		  AS2 (ldd,%B0,%B1)         CR_TAB
-		  AS2 (mov,%A0,__tmp_reg__));
-	}
-      
-      *l = 2;
-      return (AS2 (ldd,%A0,%A1) CR_TAB
-	      AS2 (ldd,%B0,%B1));
+        : avr_asm_len ("ldd %A0,%A1" CR_TAB
+                       "ldd %B0,%B1", op, plen, -2);
     }
   else if (GET_CODE (base) == PRE_DEC) /* (--R) */
     {
       if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
-	fatal_insn ("incorrect insn:", insn);
-
-      if (mem_volatile_p)
-        {
-          if (REGNO (XEXP (base, 0)) == REG_X)
-            {
-              *l = 4;
-              return (AS2 (sbiw,r26,2)  CR_TAB
-                      AS2 (ld,%A0,X+)   CR_TAB
-                      AS2 (ld,%B0,X)    CR_TAB
-                      AS2 (sbiw,r26,1));
-            }
-          else
-            {
-              *l = 3;
-              return (AS2 (sbiw,%r1,2)   CR_TAB
-                      AS2 (ld,%A0,%p1)  CR_TAB
-                      AS2 (ldd,%B0,%p1+1));
-            }
-        }
+        fatal_insn ("incorrect insn:", insn);
 
-      *l = 2;
-      return (AS2 (ld,%B0,%1) CR_TAB
-	      AS2 (ld,%A0,%1));
+      if (!mem_volatile_p)
+        return avr_asm_len ("ld %B0,%1" CR_TAB
+                            "ld %A0,%1", op, plen, -2);
+      
+      return REGNO (XEXP (base, 0)) == REG_X
+        ? avr_asm_len ("sbiw r26,2"  CR_TAB
+                       "ld %A0,X+"   CR_TAB
+                       "ld %B0,X"    CR_TAB
+                       "sbiw r26,1", op, plen, -4)
+        
+        : avr_asm_len ("sbiw %r1,2"  CR_TAB
+                       "ld %A0,%p1"  CR_TAB
+                       "ldd %B0,%p1+1", op, plen, -3);
     }
   else if (GET_CODE (base) == POST_INC) /* (R++) */
     {
       if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
-	fatal_insn ("incorrect insn:", insn);
+        fatal_insn ("incorrect insn:", insn);
 
-      *l = 2;
-      return (AS2 (ld,%A0,%1)  CR_TAB
-	      AS2 (ld,%B0,%1));
+      return avr_asm_len ("ld %A0,%1"  CR_TAB
+                          "ld %B0,%1", op, plen, -2);
     }
   else if (CONSTANT_ADDRESS_P (base))
     {
-      if (optimize > 0 && io_address_operand (base, HImode))
-	{
-	  *l = 2;
-	  return (AS2 (in,%A0,%m1-0x20) CR_TAB
-		  AS2 (in,%B0,%m1+1-0x20));
-	}
-      *l = 4;
-      return (AS2 (lds,%A0,%m1) CR_TAB
-	      AS2 (lds,%B0,%m1+1));
+      return optimize > 0 && io_address_operand (base, HImode)
+        ? avr_asm_len ("in %A0,%m1%-" CR_TAB
+                       "in %B0,%m1+1%-", op, plen, -2)
+
+        : avr_asm_len ("lds %A0,%m1" CR_TAB
+                       "lds %B0,%m1+1", op, plen, -4);
     }
   
   fatal_insn ("unknown move insn:",insn);
   return "";
 }
 
-const char *
+static const char*
 out_movsi_r_mr (rtx insn, rtx op[], int *l)
 {
   rtx dest = op[0];
@@ -3278,7 +3245,7 @@  out_movsi_r_mr (rtx insn, rtx op[], int
   return "";
 }
 
-const char *
+static const char*
 out_movsi_mr_r (rtx insn, rtx op[], int *l)
 {
   rtx dest = op[0];
@@ -3483,34 +3450,10 @@  output_movsisf (rtx insn, rtx operands[]
 		      AS2 (mov,%D0,%D1));
 	    }
 	}
-      else if (CONST_INT_P (src)
-               || CONST_DOUBLE_P (src))
-        {
-          return output_reload_insisf (operands, NULL_RTX, real_l);
-        }
       else if (CONSTANT_P (src))
 	{
-	  if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
-	    {
-	      *l = 4;
-	      return (AS2 (ldi,%A0,lo8(%1))  CR_TAB
-		      AS2 (ldi,%B0,hi8(%1))  CR_TAB
-		      AS2 (ldi,%C0,hlo8(%1)) CR_TAB
-		      AS2 (ldi,%D0,hhi8(%1)));
-	    }
-	  /* Last resort, better than loading from memory.  */
-	  *l = 10;
-	  return (AS2 (mov,__tmp_reg__,r31) CR_TAB
-		  AS2 (ldi,r31,lo8(%1))     CR_TAB
-		  AS2 (mov,%A0,r31)         CR_TAB
-		  AS2 (ldi,r31,hi8(%1))     CR_TAB
-		  AS2 (mov,%B0,r31)         CR_TAB
-		  AS2 (ldi,r31,hlo8(%1))    CR_TAB
-		  AS2 (mov,%C0,r31)         CR_TAB
-		  AS2 (ldi,r31,hhi8(%1))    CR_TAB
-		  AS2 (mov,%D0,r31)         CR_TAB
-		  AS2 (mov,r31,__tmp_reg__));
-	}
+          return output_reload_insisf (operands, NULL_RTX, real_l);
+        }
       else if (GET_CODE (src) == MEM)
 	return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */
     }
@@ -3797,41 +3740,21 @@  avr_out_movpsi (rtx insn, rtx *op, int *
               return avr_asm_len ("mov %C0,%C1", op, plen, 1);
             }
         }
-      else if (CONST_INT_P (src))
-        {
-          return avr_out_reload_inpsi (op, NULL_RTX, plen);
-        }
       else if (CONSTANT_P (src))
         {
-          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
-            {
-              return avr_asm_len ("ldi %A0,lo8(%1)" CR_TAB
-                                  "ldi %B0,hi8(%1)" CR_TAB
-                                  "ldi %C0,hh8(%1)", op, plen, -3);
-            }
-          
-          /* Last resort, better than loading from memory.  */
-          return avr_asm_len ("mov __tmp_reg__,r31" CR_TAB
-                              "ldi r31,lo8(%1)" CR_TAB
-                              "mov %A0,r31"     CR_TAB
-                              "ldi r31,hi8(%1)" CR_TAB
-                              "mov %B0,r31"     CR_TAB
-                              "ldi r31,hh8(%1)" CR_TAB
-                              "mov %C0,r31"     CR_TAB
-                              "mov r31,__tmp_reg__", op, plen, -8);
+          return avr_out_reload_inpsi (op, NULL_RTX, plen);
         }
       else if (MEM_P (src))
         return avr_out_load_psi (insn, op, plen); /* mov r,m */
     }
   else if (MEM_P (dest))
     {
-      if (src == CONST0_RTX (GET_MODE (dest)))
-        op[1] = zero_reg_rtx;
-      
-      avr_out_store_psi (insn, op, plen);
+      rtx xop[2];
+
+      xop[0] = dest;
+      xop[1] = src == CONST0_RTX (GET_MODE (dest)) ? zero_reg_rtx : src;
       
-      op[1] = src;
-      return "";
+      return avr_out_store_psi (insn, xop, plen);
     }
     
   fatal_insn ("invalid insn:", insn);
@@ -3839,7 +3762,7 @@  avr_out_movpsi (rtx insn, rtx *op, int *
 }
 
 
-const char *
+static const char*
 out_movqi_mr_r (rtx insn, rtx op[], int *plen)
 {
   rtx dest = op[0];
@@ -3858,7 +3781,7 @@  out_movqi_mr_r (rtx insn, rtx op[], int
         }
       
       if (optimize > 0 && io_address_operand (x, QImode))
-        avr_asm_len ("out %m0-0x20,%1", op, plen, -1);
+        avr_asm_len ("out %m0%-,%1", op, plen, -1);
 
       return avr_asm_len ("sts %m0,%1", op, plen, -2);
     }
@@ -3912,8 +3835,8 @@  out_movqi_mr_r (rtx insn, rtx op[], int
   return avr_asm_len ("st %0,%1", op, plen, 1);
 }
 
-const char *
-out_movhi_mr_r (rtx insn, rtx op[], int *l)
+static const char*
+out_movhi_mr_r (rtx insn, rtx op[], int *plen)
 {
   rtx dest = op[0];
   rtx src = op[1];
@@ -3923,127 +3846,103 @@  out_movhi_mr_r (rtx insn, rtx op[], int
   /* "volatile" forces writing high byte first, even if less efficient,
      for correct operation with 16-bit I/O registers.  */
   int mem_volatile_p = MEM_VOLATILE_P (dest);
-  int tmp;
 
-  if (!l)
-    l = &tmp;
   if (CONSTANT_ADDRESS_P (base))
-    {
-      if (optimize > 0 && io_address_operand (base, HImode))
-	{
-	  *l = 2;
-	  return (AS2 (out,%m0+1-0x20,%B1) CR_TAB
-		  AS2 (out,%m0-0x20,%A1));
-	}
-      return *l = 4, (AS2 (sts,%m0+1,%B1) CR_TAB
-		      AS2 (sts,%m0,%A1));
-    }
+    return optimize > 0 && io_address_operand (base, HImode)
+      ? avr_asm_len ("out %m0+1%-,%B1" CR_TAB
+                     "out %m0%-,%A1", op, plen, -2)
+
+      : avr_asm_len ("sts %m0+1,%B1" CR_TAB
+                     "sts %m0,%A1", op, plen, -4);
+  
   if (reg_base > 0)
     {
-      if (reg_base == REG_X)
-        {
-          if (reg_src == REG_X)
-            {
-              /* "st X+,r26" and "st -X,r26" are undefined.  */
-              if (!mem_volatile_p && reg_unused_after (insn, src))
-		return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
-			      AS2 (st,X,r26)            CR_TAB
-			      AS2 (adiw,r26,1)          CR_TAB
-			      AS2 (st,X,__tmp_reg__));
-              else
-		return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
-			      AS2 (adiw,r26,1)          CR_TAB
-			      AS2 (st,X,__tmp_reg__)    CR_TAB
-                              AS2 (sbiw,r26,1)          CR_TAB
-                              AS2 (st,X,r26));
-            }
-          else
-            {
-              if (!mem_volatile_p && reg_unused_after (insn, base))
-                return *l=2, (AS2 (st,X+,%A1) CR_TAB
-                              AS2 (st,X,%B1));
-              else
-                return *l=3, (AS2 (adiw,r26,1) CR_TAB
-                              AS2 (st,X,%B1)   CR_TAB
-                              AS2 (st,-X,%A1));
-            }
-        }
-      else
-        return  *l=2, (AS2 (std,%0+1,%B1) CR_TAB
-                       AS2 (st,%0,%A1));
+      if (reg_base != REG_X)
+        return avr_asm_len ("std %0+1,%B1" CR_TAB
+                            "st %0,%A1", op, plen, -2);
+      
+      if (reg_src == REG_X)
+        /* "st X+,r26" and "st -X,r26" are undefined.  */
+        return !mem_volatile_p && reg_unused_after (insn, src)
+          ? avr_asm_len ("mov __tmp_reg__,r27" CR_TAB
+                         "st X,r26"            CR_TAB
+                         "adiw r26,1"          CR_TAB
+                         "st X,__tmp_reg__", op, plen, -4)
+
+          : avr_asm_len ("mov __tmp_reg__,r27" CR_TAB
+                         "adiw r26,1"          CR_TAB
+                         "st X,__tmp_reg__"    CR_TAB
+                         "sbiw r26,1"          CR_TAB
+                         "st X,r26", op, plen, -5);
+      
+      return !mem_volatile_p && reg_unused_after (insn, base)
+        ? avr_asm_len ("st X+,%A1" CR_TAB
+                       "st X,%B1", op, plen, -2)
+        : avr_asm_len ("adiw r26,1" CR_TAB
+                       "st X,%B1"   CR_TAB
+                       "st -X,%A1", op, plen, -3);
     }
   else if (GET_CODE (base) == PLUS)
     {
       int disp = INTVAL (XEXP (base, 1));
       reg_base = REGNO (XEXP (base, 0));
       if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
-	{
-	  if (reg_base != REG_Y)
-	    fatal_insn ("incorrect insn:",insn);
-
-	  if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
-	    return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
-			    AS2 (std,Y+63,%B1)    CR_TAB
-			    AS2 (std,Y+62,%A1)    CR_TAB
-			    AS2 (sbiw,r28,%o0-62));
-
-	  return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
-			  AS2 (sbci,r29,hi8(-%o0)) CR_TAB
-			  AS2 (std,Y+1,%B1)        CR_TAB
-			  AS2 (st,Y,%A1)           CR_TAB
-			  AS2 (subi,r28,lo8(%o0))  CR_TAB
-			  AS2 (sbci,r29,hi8(%o0)));
-	}
-      if (reg_base == REG_X)
-	{
-	  /* (X + d) = R */
-	  if (reg_src == REG_X)
-            {
-	      *l = 7;
-	      return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
-		      AS2 (mov,__zero_reg__,r27) CR_TAB
-                      AS2 (adiw,r26,%o0+1)       CR_TAB
-		      AS2 (st,X,__zero_reg__)    CR_TAB
-		      AS2 (st,-X,__tmp_reg__)    CR_TAB
-		      AS1 (clr,__zero_reg__)     CR_TAB
-                      AS2 (sbiw,r26,%o0));
-	    }
-	  *l = 4;
-          return (AS2 (adiw,r26,%o0+1) CR_TAB
-                  AS2 (st,X,%B1)       CR_TAB
-                  AS2 (st,-X,%A1)      CR_TAB
-                  AS2 (sbiw,r26,%o0));
-	}
-      return *l=2, (AS2 (std,%B0,%B1)    CR_TAB
-                    AS2 (std,%A0,%A1));
+        {
+          if (reg_base != REG_Y)
+            fatal_insn ("incorrect insn:",insn);
+          
+          return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))
+            ? avr_asm_len ("adiw r28,%o0-62" CR_TAB
+                           "std Y+63,%B1"    CR_TAB
+                           "std Y+62,%A1"    CR_TAB
+                           "sbiw r28,%o0-62", op, plen, -4)
+
+            : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB
+                           "sbci r29,hi8(-%o0)" CR_TAB
+                           "std Y+1,%B1"        CR_TAB
+                           "st Y,%A1"           CR_TAB
+                           "subi r28,lo8(%o0)"  CR_TAB
+                           "sbci r29,hi8(%o0)", op, plen, -6);
+        }
+      
+      if (reg_base != REG_X)
+        return avr_asm_len ("std %B0,%B1" CR_TAB
+                            "std %A0,%A1", op, plen, -2);
+      /* (X + d) = R */
+      return reg_src == REG_X
+        ? avr_asm_len ("mov __tmp_reg__,r26"  CR_TAB
+                       "mov __zero_reg__,r27" CR_TAB
+                       "adiw r26,%o0+1"       CR_TAB
+                       "st X,__zero_reg__"    CR_TAB
+                       "st -X,__tmp_reg__"    CR_TAB
+                       "clr __zero_reg__"     CR_TAB
+                       "sbiw r26,%o0", op, plen, -7)
+
+        : avr_asm_len ("adiw r26,%o0+1" CR_TAB
+                       "st X,%B1"       CR_TAB
+                       "st -X,%A1"      CR_TAB
+                       "sbiw r26,%o0", op, plen, -4);
     }
   else if (GET_CODE (base) == PRE_DEC) /* (--R) */
-    return *l=2, (AS2 (st,%0,%B1) CR_TAB
-		  AS2 (st,%0,%A1));
+    {
+      return avr_asm_len ("st %0,%B1" CR_TAB
+                          "st %0,%A1", op, plen, -2);
+    }
   else if (GET_CODE (base) == POST_INC) /* (R++) */
     {
-      if (mem_volatile_p)
-        {
-          if (REGNO (XEXP (base, 0)) == REG_X)
-            {
-              *l = 4;
-              return (AS2 (adiw,r26,1)  CR_TAB
-                      AS2 (st,X,%B1)    CR_TAB
-                      AS2 (st,-X,%A1)   CR_TAB
-                      AS2 (adiw,r26,2));
-            }
-          else
-            {
-              *l = 3;
-              return (AS2 (std,%p0+1,%B1) CR_TAB
-                      AS2 (st,%p0,%A1)    CR_TAB
-                      AS2 (adiw,%r0,2));
-            }
-        }
-
-      *l = 2;
-      return (AS2 (st,%0,%A1)  CR_TAB
-            AS2 (st,%0,%B1));
+      if (!mem_volatile_p)
+        return avr_asm_len ("st %0,%A1"  CR_TAB
+                            "st %0,%B1", op, plen, -2);
+      
+      return REGNO (XEXP (base, 0)) == REG_X
+        ? avr_asm_len ("adiw r26,1"  CR_TAB
+                       "st X,%B1"    CR_TAB
+                       "st -X,%A1"   CR_TAB
+                       "adiw r26,2", op, plen, -4)
+
+        : avr_asm_len ("std %p0+1,%B1" CR_TAB
+                       "st %p0,%A1"    CR_TAB
+                       "adiw %r0,2", op, plen, -3);
     }
   fatal_insn ("unknown move insn:",insn);
   return "";
@@ -4338,29 +4237,33 @@  avr_out_tstsi (rtx insn, rtx *op, int *p
 }
 
 
-/* Generate asm equivalent for various shifts.
-   Shift count is a CONST_INT, MEM or REG.
-   This only handles cases that are not already
-   carefully hand-optimized in ?sh??i3_out.  */
+/* Generate asm equivalent for various shifts.  This only handles cases
+   that are not already carefully hand-optimized in ?sh??i3_out.
+
+   OPERANDS[0] resp. %0 in TEMPL is the operand to be shifted.
+   OPERANDS[2] is the shift count as CONST_INT, MEM or REG.
+   OPERANDS[3] is a QImode scratch register from LD regs if
+               available and SCRATCH, otherwise (no scratch available)
+
+   TEMPL is an assembler template that shifts by one position.
+   T_LEN is the length of this template.  */
 
 void
 out_shift_with_cnt (const char *templ, rtx insn, rtx operands[],
-		    int *len, int t_len)
+		    int *plen, int t_len)
 {
-  rtx op[10];
-  char str[500];
-  int second_label = 1;
-  int saved_in_tmp = 0;
-  int use_zero_reg = 0;
+  bool second_label = true;
+  bool saved_in_tmp = false;
+  bool use_zero_reg = false;
+  rtx op[5];
 
   op[0] = operands[0];
   op[1] = operands[1];
   op[2] = operands[2];
   op[3] = operands[3];
-  str[0] = 0;
 
-  if (len)
-    *len = 1;
+  if (plen)
+    *plen = 0;
 
   if (CONST_INT_P (operands[2]))
     {
@@ -4370,118 +4273,90 @@  out_shift_with_cnt (const char *templ, r
       int max_len = 10;  /* If larger than this, always use a loop.  */
 
       if (count <= 0)
-	{
-	  if (len)
-	    *len = 0;
-	  return;
-	}
+          return;
 
       if (count < 8 && !scratch)
-	use_zero_reg = 1;
+        use_zero_reg = true;
 
       if (optimize_size)
-	max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
+        max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
 
       if (t_len * count <= max_len)
-	{
-	  /* Output shifts inline with no loop - faster.  */
-	  if (len)
-	    *len = t_len * count;
-	  else
-	    {
-	      while (count-- > 0)
-		output_asm_insn (templ, op);
-	    }
+        {
+          /* Output shifts inline with no loop - faster.  */
+          
+          while (count-- > 0)
+            avr_asm_len (templ, op, plen, t_len);
 
-	  return;
-	}
+          return;
+        }
 
       if (scratch)
-	{
-	  if (!len)
-	    strcat (str, AS2 (ldi,%3,%2));
-	}
+        {
+          avr_asm_len ("ldi %3,%2", op, plen, 1);
+        }
       else if (use_zero_reg)
-	{
-	  /* Hack to save one word: use __zero_reg__ as loop counter.
-	     Set one bit, then shift in a loop until it is 0 again.  */
+        {
+          /* Hack to save one word: use __zero_reg__ as loop counter.
+             Set one bit, then shift in a loop until it is 0 again.  */
 
-	  op[3] = zero_reg_rtx;
-	  if (len)
-	    *len = 2;
-	  else
-	    strcat (str, ("set" CR_TAB
-			  AS2 (bld,%3,%2-1)));
-	}
+          op[3] = zero_reg_rtx;
+
+          avr_asm_len ("set" CR_TAB
+                       "bld %3,%2-1", op, plen, 2);
+        }
       else
-	{
-	  /* No scratch register available, use one from LD_REGS (saved in
-	     __tmp_reg__) that doesn't overlap with registers to shift.  */
+        {
+          /* No scratch register available, use one from LD_REGS (saved in
+             __tmp_reg__) that doesn't overlap with registers to shift.  */
 
-	  op[3] = all_regs_rtx[((REGNO (operands[0]) - 1) & 15) + 16];
-	  op[4] = tmp_reg_rtx;
-	  saved_in_tmp = 1;
+          op[3] = all_regs_rtx[((REGNO (op[0]) - 1) & 15) + 16];
+          op[4] = tmp_reg_rtx;
+          saved_in_tmp = true;
 
-	  if (len)
-	    *len = 3;  /* Includes "mov %3,%4" after the loop.  */
-	  else
-	    strcat (str, (AS2 (mov,%4,%3) CR_TAB
-			  AS2 (ldi,%3,%2)));
-	}
+          avr_asm_len ("mov %4,%3" CR_TAB
+                       "ldi %3,%2", op, plen, 2);
+        }
 
-      second_label = 0;
+      second_label = false;
     }
-  else if (GET_CODE (operands[2]) == MEM)
+  else if (MEM_P (op[2]))
     {
-      rtx op_mov[10];
+      rtx op_mov[2];
       
-      op[3] = op_mov[0] = tmp_reg_rtx;
+      op_mov[0] = op[3] = tmp_reg_rtx;
       op_mov[1] = op[2];
 
-      if (len)
-	out_movqi_r_mr (insn, op_mov, len);
-      else
-	output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
+      out_movqi_r_mr (insn, op_mov, plen);
     }
-  else if (register_operand (operands[2], QImode))
+  else if (register_operand (op[2], QImode))
     {
-      if (reg_unused_after (insn, operands[2])
-          && !reg_overlap_mentioned_p (operands[0], operands[2]))
+      op[3] = op[2];
+      
+      if (!reg_unused_after (insn, op[2])
+          || reg_overlap_mentioned_p (op[0], op[2]))
         {
-          op[3] = op[2];
+          op[3] = tmp_reg_rtx;
+          avr_asm_len ("mov %3,%2", op, plen, 1);
         }
-      else
-	{
-	  op[3] = tmp_reg_rtx;
-	  if (!len)
-	    strcat (str, (AS2 (mov,%3,%2) CR_TAB));
-	}
     }
   else
     fatal_insn ("bad shift insn:", insn);
 
   if (second_label)
-    {
-      if (len)
-	++*len;
-      else
-	strcat (str, AS1 (rjmp,2f));
-    }
+      avr_asm_len ("rjmp 2f", op, plen, 1);
 
-  if (len)
-    *len += t_len + 2;  /* template + dec + brXX */
-  else
-    {
-      strcat (str, "\n1:\t");
-      strcat (str, templ);
-      strcat (str, second_label ? "\n2:\t" : "\n\t");
-      strcat (str, use_zero_reg ? AS1 (lsr,%3) : AS1 (dec,%3));
-      strcat (str, CR_TAB);
-      strcat (str, second_label ? AS1 (brpl,1b) : AS1 (brne,1b));
-      if (saved_in_tmp)
-	strcat (str, (CR_TAB AS2 (mov,%3,%4)));
-      output_asm_insn (str, op);
-    }
+  avr_asm_len ("1:", op, plen, 0);
+  avr_asm_len (templ, op, plen, t_len);
+
+  if (second_label)
+    avr_asm_len ("2:", op, plen, 0);
+
+  avr_asm_len (use_zero_reg ? "lsr %3" : "dec %3", op, plen, 1);
+  avr_asm_len (second_label ? "brpl 1b" : "brne 1b", op, plen, 1);
+
+  if (saved_in_tmp)
+    avr_asm_len ("mov %3,%4", op, plen, 1);
 }
 
 
@@ -7355,7 +7230,7 @@  avr_asm_select_section (tree decl, int r
 static void
 avr_file_start (void)
 {
-  int sfr_offset = 0x20;
+  int sfr_offset = avr_current_arch->sfr_offset;
 
   if (avr_current_arch->asm_only)
     error ("MCU %qs supported for assembler only", avr_current_device->name);
@@ -7367,12 +7242,14 @@  avr_file_start (void)
            "__SP_H__ = 0x%02x\n"
            "__SP_L__ = 0x%02x\n"
            "__RAMPZ__ = 0x%02x\n"
-           "__tmp_reg__ = 0\n" 
-           "__zero_reg__ = 1\n",
+           "__tmp_reg__ = %d\n" 
+           "__zero_reg__ = %d\n",
            -sfr_offset + SREG_ADDR,
            -sfr_offset + SP_ADDR + 1,
            -sfr_offset + SP_ADDR,
-           -sfr_offset + RAMPZ_ADDR);
+           -sfr_offset + RAMPZ_ADDR,
+           TMP_REGNO,
+           ZERO_REGNO);
 }
 
 
@@ -9042,7 +8919,7 @@  output_reload_in_const (rtx *op, rtx clo
           xop[1] = src;
           xop[2] = clobber_reg;
 
-          if (n >= 2)
+          if (n >= 2 + (avr_current_arch->n_segments > 1))
             avr_asm_len ("clr %0", xop, len, 1);
           else
             avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2);
@@ -9218,7 +9095,9 @@  const char *
 output_reload_insisf (rtx *op, rtx clobber_reg, int *len)
 {
   if (AVR_HAVE_MOVW
-      && !test_hard_reg_class (LD_REGS, op[0]))
+      && !test_hard_reg_class (LD_REGS, op[0])
+      && (CONST_INT_P (op[1])
+          || CONST_DOUBLE_P (op[1])))
     {
       int len_clr, len_noclr;
       
@@ -9373,13 +9252,13 @@  avr_out_sbxx_branch (rtx insn, rtx opera
       if (low_io_address_operand (operands[1], QImode))
         {
           if (comp == EQ)
-            output_asm_insn ("sbis %m1-0x20,%2", operands);
+            output_asm_insn ("sbis %m1%-,%2", operands);
           else
-            output_asm_insn ("sbic %m1-0x20,%2", operands);
+            output_asm_insn ("sbic %m1%-,%2", operands);
         }
       else
         {
-          output_asm_insn ("in __tmp_reg__,%m1-0x20", operands);
+          output_asm_insn ("in __tmp_reg__,%m1%-", operands);
           if (comp == EQ)
             output_asm_insn ("sbrs __tmp_reg__,%2", operands);
           else
Index: config/avr/avr.h
===================================================================
--- config/avr/avr.h	(revision 181510)
+++ config/avr/avr.h	(working copy)
@@ -54,6 +54,10 @@  struct base_arch_s {
   /* Default start of data section address for architecture.  */
   int default_data_section_start;
 
+  /* Offset between SFR address and RAM address:
+     SFR-address = RAM-address - sfr_offset  */
+  int sfr_offset;
+
   /* Number of 64k segments in the flash.  */
   int n_segments;
 
@@ -469,7 +473,8 @@  typedef struct avr_args {
 
 #define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE)
 
-#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '~' || (CODE) == '!')
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE)       \
+  ((CODE) == '~' || (CODE) == '!' || (CODE) == '-')
 
 #define PRINT_OPERAND_ADDRESS(STREAM, X) print_operand_address(STREAM, X)