===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -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"
===================================================================
@@ -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)