diff mbox

[AVR] : PR46278 (fake X addressing)

Message ID 4E36990E.70701@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay Aug. 1, 2011, 12:16 p.m. UTC
This is Denis' work from http://codereview.appspot.com/4674046/
updated to current trunk in order to resume work on that PR.

I removed some changes from the patch (which originated in my original patch)
that are avr backend cleanups and don't deal with this fake X addressing PR.

Likewise the fix for PR46779 is no more included because that PR is already fixed.


There are still many test fails like


gcc.c-torture/execute/20021120-1.c:45:1: error: unrecognizable insn:
(insn 4063 4062 918 3 (set (reg:SF 24 r24)
        (mem/c:SF (plus:HI (reg:HI 30 r30)
                           (const_int 62 [0x3e])) [5 %sfp+254 S4 A8]))

FAIL: gcc.c-torture/execute/20021120-1.c compilation,  -Os


gcc.c-torture/compile/20071207-1.c:14:1: error: unrecognizable insn:
(insn 306 291 86 4 (set (reg:HI 30 r30)
        (mem/c:HI (plus:HI (reg/f:HI 28 r28)
                           (const_int 1101 [0x44d])) [3 %sfp+1101 S2 A8]))

FAIL: gcc.c-torture/compile/20071207-1.c  -O3 -fomit-frame-pointer -funroll-loops

gcc.c-torture/compile/pr27907.c:23:1: internal compiler error: in cselib_record_set, at cselib.c:2241

FAIL: gcc.c-torture/compile/pr27907.c  -O3 -fomit-frame-pointer -funroll-loops

There are also new execution fails.


The first kind of unrecognizable fails are like

(set (reg: mode > QI)
     (mem (plus:HI (Z + offset ca. 63))))

The second kind looks like

(set (X or Z)
     (mem:HI (plus:HI (Y + big offset))))


Appears that the second ICEs are triggered by LRA.

Regards.

Johann
diff mbox

Patch

Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md	(revision 177011)
+++ config/avr/avr.md	(working copy)
@@ -862,10 +862,10 @@  (define_insn "*addhi3_sp_R_pc3"
                (const_int 0)))])
 
 (define_insn "*addhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r")
+  [(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r,!&d")
  	(plus:HI
- 	 (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
- 	 (match_operand:HI 2 "nonmemory_operand" "r,I,J,i,P,N")))]
+ 	 (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,r")
+ 	 (match_operand:HI 2 "nonmemory_operand" "r,I,J,i,P,N,rn")))]
   ""
   "@
  	add %A0,%A2\;adc %B0,%B2
@@ -873,9 +873,26 @@  (define_insn "*addhi3"
  	sbiw %A0,%n2
  	subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))
  	sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__
- 	sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__"
-  [(set_attr "length" "2,1,1,2,3,3")
-   (set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")])
+ 	sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__
+        #"
+  [(set_attr "length" "2,1,1,2,3,3,4")
+   (set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n,set_n")])
+
+;; Special split for three addressing addhi3
+;; to make postreload optimization possible
+(define_split ; addhi3 !&d,r,rn
+  [(set (match_operand:HI 0 "d_register_operand" "")
+	(plus:HI (match_operand:HI 1 "register_operand" "")
+		 (match_operand:HI 2 "nonmemory_operand" "")))]
+  "reload_completed
+   && REGNO (operands[0]) != REGNO (operands[1])"
+  [(set (match_dup 0)
+        (match_dup 1))
+   (set (match_dup 0)
+        (plus:HI (match_dup 0)
+                 (match_dup 2)))]
+  "")
+
 
 (define_insn "addsi3"
   [(set (match_operand:SI 0 "register_operand" "=r,!w,!w,d,r,r")
@@ -2755,54 +2772,6 @@  (define_insn_and_split "zero_extendhisi2
   operands[3] = simplify_gen_subreg (HImode, operands[0], SImode, high_off);
 })
 
-(define_insn_and_split "zero_extendqidi2"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-        (zero_extend:DI (match_operand:QI 1 "register_operand" "r")))]
-  ""
-  "#"
-  "reload_completed"
-  [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
-   (set (match_dup 3) (const_int 0))]
-{
-  unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
-  unsigned int high_off = subreg_highpart_offset (SImode, DImode);
-
-  operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
-  operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
-})
-
-(define_insn_and_split "zero_extendhidi2"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-        (zero_extend:DI (match_operand:HI 1 "register_operand" "r")))]
-  ""
-  "#"
-  "reload_completed"
-  [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
-   (set (match_dup 3) (const_int 0))]
-{
-  unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
-  unsigned int high_off = subreg_highpart_offset (SImode, DImode);
-
-  operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
-  operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
-})
-
-(define_insn_and_split "zero_extendsidi2"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-        (zero_extend:DI (match_operand:SI 1 "register_operand" "r")))]
-  ""
-  "#"
-  "reload_completed"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_dup 3) (const_int 0))]
-{
-  unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
-  unsigned int high_off = subreg_highpart_offset (SImode, DImode);
-
-  operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
-  operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
-})
-
 ;;<=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=>
 ;; compare
 
Index: config/avr/avr-protos.h
===================================================================
--- config/avr/avr-protos.h	(revision 177011)
+++ config/avr/avr-protos.h	(working copy)
@@ -99,6 +99,7 @@  extern int byte_immediate_operand (rtx o
 extern int test_hard_reg_class (enum reg_class rclass, rtx x);
 extern int jump_over_one_insn_p (rtx insn, rtx dest);
 
+extern int avr_hard_regno_nregs (int regno, enum machine_mode mode);
 extern int avr_hard_regno_mode_ok (int regno, enum machine_mode mode);
 extern void final_prescan_insn (rtx insn, rtx *operand, int num_operands);
 extern int avr_simplify_comparison_p (enum machine_mode mode,
@@ -107,7 +108,10 @@  extern RTX_CODE avr_normalize_condition
 extern int compare_eq_p (rtx insn);
 extern void out_shift_with_cnt (const char *templ, rtx insn,
 				rtx operands[], int *len, int t_len);
+extern reg_class_t avr_mode_code_base_reg_class (enum machine_mode, RTX_CODE, RTX_CODE);
+extern bool avr_regno_mode_code_ok_for_base_p (int, enum machine_mode, RTX_CODE, RTX_CODE);
 extern rtx avr_incoming_return_addr_rtx (void);
+extern rtx avr_legitimize_reload_address (rtx, enum machine_mode, int, int, int, int);
 #endif /* RTX_CODE */
 
 #ifdef REAL_VALUE_TYPE
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 177011)
+++ config/avr/avr.c	(working copy)
@@ -420,29 +420,28 @@  avr_regs_to_save (HARD_REG_SET *set)
 /* Return true if register FROM can be eliminated via register TO.  */
 
 bool
-avr_can_eliminate (const int from, const int to)
+avr_can_eliminate (int from ATTRIBUTE_UNUSED, int to)
 {
-  return ((from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
-	  || ((from == FRAME_POINTER_REGNUM 
-	       || from == FRAME_POINTER_REGNUM + 1)
-	      && !frame_pointer_needed));
+  return to == HARD_FRAME_POINTER_REGNUM;
 }
 
 /* Compute offset between arg_pointer and frame_pointer.  */
 
 int
-avr_initial_elimination_offset (int from, int to)
+avr_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
 {
-  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
-    return 0;
-  else
-    {
-      int offset = frame_pointer_needed ? 2 : 0;
-      int avr_pc_size = AVR_HAVE_EIJMP_EICALL ? 3 : 2;
+  int offset = 0;
 
+  if (from == ARG_POINTER_REGNUM)
+    {
+      offset += AVR_HAVE_EIJMP_EICALL ? 3 : 2;
+      offset += frame_pointer_needed ? 2 : 0;
       offset += avr_regs_to_save (NULL);
-      return get_frame_size () + (avr_pc_size) + 1 + offset;
+      offset += get_frame_size ();
+      offset += 1; /* post-dec stack space */
     }
+
+  return offset;
 }
 
 /* Actual start of frame is virtual_stack_vars_rtx this is offset from 
@@ -674,12 +673,12 @@  expand_prologue (void)
 	 notes to the front.  Thus we build them in the reverse order of
 	 how we want dwarf2out to process them.  */
 
-      /* The function does always set frame_pointer_rtx, but whether that
+      /* The function does always set hard_frame_pointer_rtx, but whether that
 	 is going to be permanent in the function is frame_pointer_needed.  */
       add_reg_note (insn, REG_CFA_ADJUST_CFA,
 		    gen_rtx_SET (VOIDmode,
 				 (frame_pointer_needed
-				  ? frame_pointer_rtx : stack_pointer_rtx),
+				  ? hard_frame_pointer_rtx : stack_pointer_rtx),
 				 plus_constant (stack_pointer_rtx,
 						-(size + live_seq))));
 
@@ -720,7 +719,7 @@  expand_prologue (void)
 
           if (!size)
             {
-              insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+              insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
               RTX_FRAME_RELATED_P (insn) = 1;
             }
           else
@@ -743,12 +742,12 @@  expand_prologue (void)
                 {
                   /* The high byte (r29) doesn't change.  Prefer 'subi'
 		     (1 cycle) over 'sbiw' (2 cycles, same size).  */
-                  myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM);
+                  myfp = gen_rtx_REG (QImode, HARD_FRAME_POINTER_REGNUM);
                 }
               else 
                 {
                   /*  Normal sized addition.  */
-                  myfp = frame_pointer_rtx;
+                  myfp = hard_frame_pointer_rtx;
                 }
 
 	      /* Method 1-Adjust frame pointer.  */
@@ -760,12 +759,12 @@  expand_prologue (void)
 		 instead indicate that the entire operation is complete after
 		 the frame pointer subtraction is done.  */
 
-              emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+              emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
 
               insn = emit_move_insn (myfp, plus_constant (myfp, -size));
               RTX_FRAME_RELATED_P (insn) = 1;
 	      add_reg_note (insn, REG_CFA_ADJUST_CFA,
-			    gen_rtx_SET (VOIDmode, frame_pointer_rtx,
+			    gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
 					 plus_constant (stack_pointer_rtx,
 							-size)));
 
@@ -774,23 +773,23 @@  expand_prologue (void)
 		 need not be annotated at all.  */
 	      if (AVR_HAVE_8BIT_SP)
 		{
-		  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+		  emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
 		}
 	      else if (TARGET_NO_INTERRUPTS 
 		       || cfun->machine->is_signal
 		       || cfun->machine->is_OS_main)
 		{
 		  emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, 
-						     frame_pointer_rtx));
+						     hard_frame_pointer_rtx));
 		}
 	      else if (cfun->machine->is_interrupt)
 		{
 		  emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, 
-						    frame_pointer_rtx));
+						    hard_frame_pointer_rtx));
 		}
 	      else
 		{
-		  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+		  emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
 		}
 
 	      fp_plus_insns = get_insns ();
@@ -807,7 +806,7 @@  expand_prologue (void)
 		  insn = emit_move_insn (stack_pointer_rtx, insn);
 		  RTX_FRAME_RELATED_P (insn) = 1;
 		  
-		  insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+		  insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
 		  RTX_FRAME_RELATED_P (insn) = 1;
 
 		  sp_plus_insns = get_insns ();
@@ -924,13 +923,13 @@  expand_epilogue (bool sibcall_p)
       if (frame_pointer_needed)
 	{
           /*  Get rid of frame.  */
-	  emit_move_insn(frame_pointer_rtx,
-                         gen_rtx_PLUS (HImode, frame_pointer_rtx,
-                                       gen_int_mode (size, HImode)));
+	  emit_move_insn (hard_frame_pointer_rtx,
+                          gen_rtx_PLUS (HImode, hard_frame_pointer_rtx,
+                                        gen_int_mode (size, HImode)));
 	}
       else
 	{
-          emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+          emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
 	}
 	
       emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode)));
@@ -949,12 +948,12 @@  expand_epilogue (bool sibcall_p)
                 {
                   /* The high byte (r29) doesn't change - prefer 'subi' 
                      (1 cycle) over 'sbiw' (2 cycles, same size).  */
-                  myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM);
+                  myfp = gen_rtx_REG (QImode, HARD_FRAME_POINTER_REGNUM);
                 }
               else 
                 {
                   /* Normal sized addition.  */
-                  myfp = frame_pointer_rtx;
+                  myfp = hard_frame_pointer_rtx;
                 }
 	      
               /* Method 1-Adjust frame pointer.  */
@@ -965,22 +964,22 @@  expand_epilogue (bool sibcall_p)
 	      /* Copy to stack pointer.  */
 	      if (AVR_HAVE_8BIT_SP)
 		{
-		  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+		  emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
 		}
 	      else if (TARGET_NO_INTERRUPTS 
 		       || cfun->machine->is_signal)
 		{
 		  emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, 
-						     frame_pointer_rtx));
+						     hard_frame_pointer_rtx));
 		}
 	      else if (cfun->machine->is_interrupt)
 		{
 		  emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, 
-						    frame_pointer_rtx));
+						    hard_frame_pointer_rtx));
 		}
 	      else
 		{
-		  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+		  emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
 		}
 
 	      fp_plus_insns = get_insns ();
@@ -1082,104 +1081,165 @@  avr_cannot_modify_jumps_p (void)
 }
 
 
-/* Return nonzero if X (an RTX) is a legitimate memory address on the target
-   machine for a memory operand of mode MODE.  */
+/* Helper function for `avr_legitimate_address_p'.  */
+
+static inline int
+avr_reg_ok_for_addr (rtx reg, int strict)
+{
+  return (REG_P (reg)
+          && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, MEM, UNKNOWN)
+              || (!strict && REGNO (reg) >= FIRST_PSEUDO_REGISTER)));
+}
+
+
+/* Implement `TARGET_LEGITIMATE_ADDRESS_P'.  */
 
 bool
 avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 {
-  enum reg_class r = NO_REGS;
-  
-  if (TARGET_ALL_DEBUG)
-    {
-      fprintf (stderr, "mode: (%s) %s %s %s %s:",
-	       GET_MODE_NAME(mode),
-	       strict ? "(strict)": "",
-	       reload_completed ? "(reload_completed)": "",
-	       reload_in_progress ? "(reload_in_progress)": "",
-	       reg_renumber ? "(reg_renumber)" : "");
-      if (GET_CODE (x) == PLUS
-	  && REG_P (XEXP (x, 0))
-	  && GET_CODE (XEXP (x, 1)) == CONST_INT
-	  && INTVAL (XEXP (x, 1)) >= 0
-	  && INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode)
-	  && reg_renumber
-	  )
-	fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
-		 true_regnum (XEXP (x, 0)));
-      debug_rtx (x);
-    }
-  
-  if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
-                    : REG_OK_FOR_BASE_NOSTRICT_P (x)))
-    r = POINTER_REGS;
-  else if (CONSTANT_ADDRESS_P (x))
-    r = ALL_REGS;
-  else if (GET_CODE (x) == PLUS
-           && REG_P (XEXP (x, 0))
-	   && GET_CODE (XEXP (x, 1)) == CONST_INT
-	   && INTVAL (XEXP (x, 1)) >= 0)
-    {
-      int fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode);
-      if (fit)
-	{
-	  if (! strict
-	      || REGNO (XEXP (x,0)) == REG_X
-	      || REGNO (XEXP (x,0)) == REG_Y
-	      || REGNO (XEXP (x,0)) == REG_Z)
-	    r = BASE_POINTER_REGS;
-	  if (XEXP (x,0) == frame_pointer_rtx
-	      || XEXP (x,0) == arg_pointer_rtx)
-	    r = BASE_POINTER_REGS;
-	}
-      else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
-	r = POINTER_Y_REGS;
-    }
-  else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
-           && REG_P (XEXP (x, 0))
-           && (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
-               : REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
-    {
-      r = POINTER_REGS;
-    }
-  if (TARGET_ALL_DEBUG)
+  bool ok = false;
+
+  switch (GET_CODE (x))
     {
-      fprintf (stderr, "   ret = %c\n", r + '0');
+    case REG:
+      ok = avr_reg_ok_for_addr (x, strict);
+      if (strict
+          && DImode == mode
+          && REG_X == REGNO (x))
+        {
+          ok = false;
+        }
+      break;
+
+    case POST_INC:
+    case PRE_DEC:
+      ok = avr_reg_ok_for_addr (XEXP (x, 0), strict);
+      break;
+
+    case SYMBOL_REF:
+    case CONST_INT:
+    case CONST:
+      ok = true;
+      break;
+      
+    case PLUS:
+      {
+        rtx op0 = XEXP (x, 0);
+        rtx op1 = XEXP (x, 1);
+            
+        if (REG_P (op0)
+            && CONST_INT_P (op1))
+          {
+            ok = (avr_reg_ok_for_addr (op0, strict)
+                  && INTVAL (op1) >= 0
+                  && INTVAL (op1) <= MAX_LD_OFFSET (mode));
+            
+            if (strict
+                && REG_X == REGNO (op0))
+              {
+                ok = false;
+              }
+          }
+        break;
+      }
+      
+    default:
+      break;
     }
-  return r == NO_REGS ? 0 : (int)r;
+
+  return ok;
 }
 
+
 /* Attempts to replace X with a valid
    memory address for an operand of mode MODE  */
 
-rtx
-avr_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
+static rtx
+avr_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+                        enum machine_mode mode)
 {
-  x = oldx;
-  if (TARGET_ALL_DEBUG)
+  if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)))
     {
-      fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode));
-      debug_rtx (oldx);
+      HOST_WIDE_INT addend = INTVAL (XEXP (x, 1));
+
+      if (addend > MAX_LD_OFFSET (mode))
+        {
+          HOST_WIDE_INT hi, lo;
+
+          x = XEXP (x, 0);
+          if (!REG_P (x)
+              || !avr_regno_mode_code_ok_for_base_p (REGNO (x), mode,
+                                                     PLUS, UNKNOWN))
+            x = force_reg (Pmode, x);
+
+          lo = addend & 63;
+          hi = addend - lo;
+          x = force_reg (Pmode, plus_constant (x, hi));
+
+          return plus_constant (x, lo);
+        }
     }
+
+  return x;
+}
+
+
+/* Implement `LEGITIMIZE_RELOAD_ADDRESS'.  */
+
+rtx
+avr_legitimize_reload_address (rtx x, enum machine_mode mode,
+                               int opnum, int type, int addr_type,
+                               int ind_levels ATTRIBUTE_UNUSED)
+{
+  /* We must recognize output that we have already generated ourselves.  */
   
-  if (GET_CODE (oldx) == PLUS
-      && REG_P (XEXP (oldx,0)))
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && REG_P (XEXP (XEXP (x, 0), 0))
+      && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+      && CONST_INT_P (XEXP (x, 1)))
+    {
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                   BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0,
+                   opnum, (enum reload_type) addr_type);
+      return x;
+    }
+  
+  /* We wish to handle large displacements off a register by splitting
+     the addend into two parts.  This may allow some sharing.  */
+  
+  if (GET_CODE (x) == PLUS
+      && REG_P (XEXP (x, 0))
+      && CONST_INT_P (XEXP (x, 1)))
     {
-      if (REG_P (XEXP (oldx,1)))
-	x = force_reg (GET_MODE (oldx), oldx);
-      else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT)
-	{
-	  int offs = INTVAL (XEXP (oldx,1));
-	  if (frame_pointer_rtx != XEXP (oldx,0))
-	    if (offs > MAX_LD_OFFSET (mode))
-	      {
-		if (TARGET_ALL_DEBUG)
-		  fprintf (stderr, "force_reg (big offset)\n");
-		x = force_reg (GET_MODE (oldx), oldx);
-	      }
-	}
+      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+      HOST_WIDE_INT lo = val & 63;
+      HOST_WIDE_INT hi = val - lo;
+      
+      if (val > MAX_LD_OFFSET (mode) && hi && lo)
+        {
+          /* Reload the high part into a base reg; leave the low part
+             in the mem directly.  */
+          
+          x = plus_constant (XEXP (x, 0), hi);
+          x = gen_rtx_PLUS (Pmode, x, GEN_INT (lo));
+
+          push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                       BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0,
+                       opnum, (enum reload_type) addr_type);
+          return x;
+        }
     }
-  return x;
+
+  if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC)
+    {
+      push_reload (XEXP (x, 0), NULL, &XEXP (x,0), NULL,
+                   POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0,
+                   opnum, (enum reload_type) type);
+      return x;
+    }
+  
+  return NULL_RTX;
 }
 
 
@@ -6189,6 +6249,18 @@  jump_over_one_insn_p (rtx insn, rtx dest
   return dest_addr - jump_addr == get_attr_length (insn) + 1;
 }
 
+/* Returns the number of registers required to hold a value of MODE.  */
+
+int
+avr_hard_regno_nregs (int regno, enum machine_mode mode)
+{
+  /* The fake registers are designed to hold exactly a pointer.  */
+  if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
+    return 1;
+
+  return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+}
+
 /* Returns 1 if a value of mode MODE can be stored starting with hard
    register number REGNO.  On the enhanced core, anything larger than
    1 byte must start in even numbered register for "movw" to work
@@ -6197,6 +6269,11 @@  jump_over_one_insn_p (rtx insn, rtx dest
 int
 avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
 {
+  /* The fake registers are designed to hold exactly a pointer.  */
+  
+  if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
+    return mode == Pmode;
+
   /* NOTE: 8-bit values must not be disallowed for R28 or R29.
         Disallowing QI et al. in these regs might lead to code like
             (set (subreg:QI (reg:HI 28) n) ...)
@@ -6224,6 +6301,69 @@  avr_hard_regno_mode_ok (int regno, enum
   return !(regno & 1);
 }
 
+
+/* Implement `MODE_CODE_BASE_REG_CLASS'.  */
+
+reg_class_t
+avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
+                              RTX_CODE outer_code,
+                              RTX_CODE index_code ATTRIBUTE_UNUSED)
+{
+  reg_class_t rclass = BASE_POINTER_REGS;
+  
+  switch (outer_code)
+    {
+    case MEM:
+    case POST_INC:
+    case PRE_DEC:
+      rclass = POINTER_REGS;
+      break;
+      
+    default:
+      break;
+    }
+  
+  return rclass;
+}
+
+
+/* Implement `REGNO_MODE_CODE_OK_FOR_BASE_P'.  */
+
+bool
+avr_regno_mode_code_ok_for_base_p (int regno,
+				   enum machine_mode mode ATTRIBUTE_UNUSED,
+                                   RTX_CODE outer_code,
+				   RTX_CODE index_code ATTRIBUTE_UNUSED)
+{
+  bool ok;
+  
+  ok = (regno == REG_Z
+        || regno == REG_Y
+        || regno == ARG_POINTER_REGNUM
+        || regno == FRAME_POINTER_REGNUM);
+
+  switch (outer_code)
+    {
+    case PLUS:
+      /* Computed above */
+      break;
+      
+    case MEM: /* plain reg */
+    case POST_INC:
+    case PRE_DEC:
+      /* As above, but also X.  */
+      if (regno == REG_X)
+	ok = true;
+      break;
+      
+    default:
+      ok = false;
+      break;
+    }
+
+  return ok;
+}
+
 const char *
 output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
 {
@@ -6962,4 +7102,36 @@  avr_expand_builtin (tree exp, rtx target
 }
 
 
+void
+debug_regno_equiv (int regno)
+{
+  printf ("Pseudo: %4d  mem: ", regno);
+  if (reg_equiv_mem (regno))
+    print_inline_rtx (stdout, reg_equiv_mem (regno), 0);
+  else
+    printf ("None");
+
+  printf ("     addr: ");
+  if (reg_equiv_address (regno))
+    print_inline_rtx (stdout, reg_equiv_address (regno), 0);
+  else
+    printf ("None");
+  printf ("\n");
+}
+
+void
+debug_reg_equiv (rtx r)
+{
+  if (REG_P (r))
+    debug_regno_equiv (REGNO (r));
+}
+
+void
+debug_reg_equivs (void)
+{
+  int i;
+  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+    debug_regno_equiv (i);
+}
+
 #include "gt-avr.h"
Index: config/avr/avr.h
===================================================================
--- config/avr/avr.h	(revision 177011)
+++ config/avr/avr.h	(working copy)
@@ -189,7 +189,8 @@  extern GTY(()) section *progmem_section;
   0,0,/* r28 r29 */\
   0,0,/* r30 r31 */\
   1,1,/*  STACK */\
-  1,1 /* arg pointer */  }
+  1,  /* arg pointer */\
+  1   /* frame pointer */  }
 
 #define CALL_USED_REGISTERS {			\
   1,1,/* r0 r1 */				\
@@ -209,7 +210,8 @@  extern GTY(()) section *progmem_section;
     0,0,/* r28 r29 */				\
     1,1,/* r30 r31 */				\
     1,1,/*  STACK */				\
-    1,1 /* arg pointer */  }
+    1,  /* arg pointer */			\
+    1   /* frame pointer */ }
 
 #define REG_ALLOC_ORDER {			\
     24,25,					\
@@ -227,7 +229,7 @@  extern GTY(()) section *progmem_section;
 #define ADJUST_REG_ALLOC_ORDER order_regs_for_local_alloc ()
 
 
-#define HARD_REGNO_NREGS(REGNO, MODE) ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+#define HARD_REGNO_NREGS(REGNO, MODE) avr_hard_regno_nregs(REGNO, MODE)
 
 #define HARD_REGNO_MODE_OK(REGNO, MODE) avr_hard_regno_mode_ok(REGNO, MODE)
 
@@ -277,36 +279,28 @@  enum reg_class {
   {3 << REG_Z,0x00000000},      /* POINTER_Z_REGS, r30 - r31 */		\
   {0x00000000,0x00000003},	/* STACK_REG, STACK */			\
   {(3 << REG_Y) | (3 << REG_Z),						\
-     0x00000000},		/* BASE_POINTER_REGS, r28 - r31 */	\
+     0x0000000c},		/* BASE_POINTER_REGS, r28 - r31,ap,fp */\
   {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z),				\
-     0x00000000},		/* POINTER_REGS, r26 - r31 */		\
+     0x0000000c},		/* POINTER_REGS, r26 - r31,ap,fp */	\
   {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z) | (3 << REG_W),		\
      0x00000000},		/* ADDW_REGS, r24 - r31 */		\
   {0x00ff0000,0x00000000},	/* SIMPLE_LD_REGS r16 - r23 */          \
   {(3 << REG_X)|(3 << REG_Y)|(3 << REG_Z)|(3 << REG_W)|(0xff << 16),	\
-     0x00000000},	/* LD_REGS, r16 - r31 */			\
+     0x0000000c},	/* LD_REGS, r16 - r31 */			\
   {0x0000ffff,0x00000000},	/* NO_LD_REGS  r0 - r15 */              \
-  {0xffffffff,0x00000000},	/* GENERAL_REGS, r0 - r31 */		\
-  {0xffffffff,0x00000003}	/* ALL_REGS */				\
+  {0xffffffff,0x0000000c},	/* GENERAL_REGS, r0 - r31,ap,fp */	\
+  {0xffffffff,0x0000000f}	/* ALL_REGS */				\
 }
 
 #define REGNO_REG_CLASS(R) avr_regno_reg_class(R)
 
-#define BASE_REG_CLASS (reload_completed ? BASE_POINTER_REGS : POINTER_REGS)
+#define MODE_CODE_BASE_REG_CLASS(mode, outer_code, index_code)  \
+  avr_mode_code_base_reg_class (mode, outer_code, index_code)
 
 #define INDEX_REG_CLASS NO_REGS
 
-#define REGNO_OK_FOR_BASE_P(r) (((r) < FIRST_PSEUDO_REGISTER		\
-				 && ((r) == REG_X			\
-				     || (r) == REG_Y			\
-				     || (r) == REG_Z			\
-				     || (r) == ARG_POINTER_REGNUM))	\
-				|| (reg_renumber			\
-				    && (reg_renumber[r] == REG_X	\
-					|| reg_renumber[r] == REG_Y	\
-					|| reg_renumber[r] == REG_Z	\
-					|| (reg_renumber[r]		\
-					    == ARG_POINTER_REGNUM))))
+#define REGNO_MODE_CODE_OK_FOR_BASE_P(num, mode, outer_code, index_code) \
+  avr_regno_mode_code_ok_for_base_p (num, mode, outer_code, index_code) 
 
 #define REGNO_OK_FOR_INDEX_P(NUM) 0
 
@@ -326,16 +320,18 @@  enum reg_class {
 
 #define STACK_POINTER_REGNUM 32
 
-#define FRAME_POINTER_REGNUM REG_Y
+#define HARD_FRAME_POINTER_REGNUM REG_Y
 
 #define ARG_POINTER_REGNUM 34
+#define FRAME_POINTER_REGNUM 35
 
 #define STATIC_CHAIN_REGNUM 2
 
 #define ELIMINABLE_REGS {					\
-      {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},		\
-	{FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}		\
-       ,{FRAME_POINTER_REGNUM+1,STACK_POINTER_REGNUM+1}}
+      { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM },		\
+      { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM },	\
+      { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM },		\
+      { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }}
 
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
   OFFSET = avr_initial_elimination_offset (FROM, TO)
@@ -367,55 +363,21 @@  extern int avr_reg_order[];
 
 #define MAX_REGS_PER_ADDRESS 1
 
-#define REG_OK_FOR_BASE_NOSTRICT_P(X) \
-  (REGNO (X) >= FIRST_PSEUDO_REGISTER || REG_OK_FOR_BASE_STRICT_P(X))
-
-#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
-
-/* LEGITIMIZE_RELOAD_ADDRESS will allow register R26/27 to be used, where it
-   is no worse than normal base pointers R28/29 and R30/31. For example:
-   If base offset is greater than 63 bytes or for R++ or --R addressing.  */
-   
-#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)    \
-do {									    \
-  if (1&&(GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC))	    \
-    {									    \
-      push_reload (XEXP (X,0), XEXP (X,0), &XEXP (X,0), &XEXP (X,0),	    \
-	           POINTER_REGS, GET_MODE (X),GET_MODE (X) , 0, 0,	    \
-		   OPNUM, RELOAD_OTHER);				    \
-      goto WIN;								    \
-    }									    \
-  if (GET_CODE (X) == PLUS						    \
-      && REG_P (XEXP (X, 0))						    \
-      && (reg_equiv_constant (REGNO (XEXP (X, 0))) == 0)		    \
-      && GET_CODE (XEXP (X, 1)) == CONST_INT				    \
-      && INTVAL (XEXP (X, 1)) >= 1)					    \
-    {									    \
-      int fit = INTVAL (XEXP (X, 1)) <= (64 - GET_MODE_SIZE (MODE));	    \
-      if (fit)								    \
-	{								    \
-          if (reg_equiv_address (REGNO (XEXP (X, 0))) != 0)		    \
-	    {								    \
-	      int regno = REGNO (XEXP (X, 0));				    \
-	      rtx mem = make_memloc (X, regno);				    \
-	      push_reload (XEXP (mem,0), NULL, &XEXP (mem,0), NULL,         \
-		           POINTER_REGS, Pmode, VOIDmode, 0, 0,		    \
-		           1, ADDR_TYPE (TYPE));			    \
-	      push_reload (mem, NULL_RTX, &XEXP (X, 0), NULL,		    \
-		           BASE_POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0, \
-		           OPNUM, TYPE);				    \
-	      goto WIN;							    \
-	    }								    \
-	}								    \
-      else if (! (frame_pointer_needed && XEXP (X,0) == frame_pointer_rtx)) \
-	{								    \
-	  push_reload (X, NULL_RTX, &X, NULL,				    \
-		       POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0,	    \
-		       OPNUM, TYPE);					    \
-          goto WIN;							    \
-	}								    \
-    }									    \
-} while(0)
+/* Try a machine-dependent way of reloading an illegitimate address
+   operand.  If we find one, push the reload and jump to WIN.  This
+   macro is used in only one place: `find_reloads_address' in reload.c.  */
+
+#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_L,WIN)          \
+  do {                                                                  \
+    rtx new_x = avr_legitimize_reload_address (X, MODE, OPNUM, TYPE,    \
+                                               ADDR_TYPE (TYPE),        \
+                                               IND_L);                  \
+    if (new_x)                                                          \
+      {                                                                 \
+        X = new_x;                                                      \
+        goto WIN;                                                       \
+      }                                                                 \
+  } while (0)
 
 #define BRANCH_COST(speed_p, predictable_p) 0
 
@@ -476,7 +438,7 @@  do {									    \
     "r8","r9","r10","r11","r12","r13","r14","r15",	\
     "r16","r17","r18","r19","r20","r21","r22","r23",	\
     "r24","r25","r26","r27","r28","r29","r30","r31",	\
-    "__SP_L__","__SP_H__","argL","argH"}
+    "__SP_L__","__SP_H__","ap","fp"}
 
 #define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop)