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
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)