diff --git a/config/avr/avr.c b/config/avr/avr.c index 8a942c1..c12234e 100644 --- a/config/avr/avr.c +++ b/config/avr/avr.c @@ -2300,28 +2300,58 @@ avr_xload_libgcc_p (enum machine_mode mode) } +/* Find an unused d-register to be used as scratch in INSN. + EXCLUDE is either NULL_RTX or some register. In the case where EXCLUDE + is a register, skip all possible return values that overlap EXCLUDE. + The policy for the returned register is similar to that of + `reg_unused_after', i.e. the returned register may overlap the SET_DEST + of INSN. + + Return a QImode d-register or NULL_RTX if nothing found. */ + static rtx avr_find_unused_d_reg (rtx insn, rtx exclude) { int regno; + bool isr_p = (interrupt_function_p (current_function_decl) + || signal_function_p (current_function_decl)); - for (regno = 16; regno < 32; regno ++) + for (regno = 16; regno < 32; regno++) { rtx reg = all_regs_rtx[regno]; - if (exclude - && reg_overlap_mentioned_p (exclude, reg)) + if ((exclude + && reg_overlap_mentioned_p (exclude, reg)) + || fixed_regs[regno]) { continue; } - if (reg_unused_after (insn, reg)) - return reg; + /* Try non-live register */ + + if (!df_regs_ever_live_p (regno) + && (TREE_THIS_VOLATILE (current_function_decl) + || cfun->machine->is_OS_task + || cfun->machine->is_OS_main + || (!isr_p && call_used_regs[regno]))) + { + return reg; + } + + /* Any live register can be used if it is unused after. + Prologue/epilogue will care for it as needed. */ + + if (df_regs_ever_live_p (regno) + && reg_unused_after (insn, reg)) + { + return reg; + } } return NULL_RTX; } + /* Helper function for the next function in the case where only restricted version of LPM instruction is available. */ @@ -2354,7 +2384,7 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen) case 1: return avr_asm_len ("%4lpm" CR_TAB - "mov %0,%3", xop, plen, -2); + "mov %0,%3", xop, plen, 2); case 2: if (REGNO (dest) == REG_Z) @@ -2363,14 +2393,14 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen) "adiw %2,1" CR_TAB "%4lpm" CR_TAB "mov %B0,%3" CR_TAB - "pop %A0", xop, plen, -6); + "pop %A0", xop, plen, 6); else { avr_asm_len ("%4lpm" CR_TAB "mov %A0,%3" CR_TAB "adiw %2,1" CR_TAB "%4lpm" CR_TAB - "mov %B0,%3", xop, plen, -5); + "mov %B0,%3", xop, plen, 5); if (!reg_unused_after (insn, addr)) avr_asm_len ("sbiw %2,1", xop, plen, 1); @@ -2386,7 +2416,7 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen) "mov %B0,%3" CR_TAB "adiw %2,1" CR_TAB "%4lpm" CR_TAB - "mov %C0,%3", xop, plen, -8); + "mov %C0,%3", xop, plen, 8); if (REGNO (dest) != REG_Z - 2 || !reg_unused_after (insn, addr)) @@ -2402,7 +2432,7 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen) "adiw %2,1" CR_TAB "%4lpm" CR_TAB "mov %B0,%3" CR_TAB - "adiw %2,1", xop, plen, -6); + "adiw %2,1", xop, plen, 6); if (REGNO (dest) == REG_Z - 2) return avr_asm_len ("%4lpm" CR_TAB @@ -2435,7 +2465,7 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen) avr_asm_len ("%4lpm" CR_TAB "mov %A0,%3" CR_TAB - "adiw %2,1", xop, plen, -3); + "adiw %2,1", xop, plen, 3); if (n_bytes >= 2) avr_asm_len ("%4lpm" CR_TAB @@ -2492,7 +2522,8 @@ avr_out_lpm (rtx insn, rtx *op, int *plen) segment = avr_pgm_segment (MEM_ADDR_SPACE (src)); gcc_assert (REG_P (dest) - && ((REG_P (addr) && segment >= 0) + && ((segment >= 0 + && (REG_P (addr) || POST_INC == GET_CODE (addr))) || (GET_CODE (addr) == LO_SUM && segment == -1))); if (segment == -1) @@ -2515,6 +2546,8 @@ avr_out_lpm (rtx insn, rtx *op, int *plen) segment %= avr_current_arch->n_segments; + /* Set RAMPZ as needed. */ + if (segment == 0) { xop[4] = xstring_empty; @@ -9430,7 +9463,7 @@ avr_reg_ok_for_pgm_addr (rtx reg, bool strict) /* Avoid combine to propagate hard regs. */ - if (can_create_pseude_p() + if (can_create_pseudo_p() && REGNO (reg) < REG_Z) { return false; @@ -9555,17 +9588,24 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) if (as_from != ADDR_SPACE_PGMX && as_to == ADDR_SPACE_PGMX) { + int n_segments = avr_current_arch->n_segments; + src = force_reg (Pmode, src); if (ADDR_SPACE_GENERIC_P (as_from) - || as_from == ADDR_SPACE_PGM) + || as_from == ADDR_SPACE_PGM + || n_segments == 1) { return gen_rtx_ZERO_EXTEND (PSImode, src); } else { - int hh8 = avr_pgm_segment (as_from) << 16; - src = SET_SRC (gen_n_extendhipsi2 (src, src, GEN_INT (hh8))); + rtx new_src = gen_reg_rtx (PSImode); + int segment = avr_pgm_segment (as_from) % n_segments; + + emit_insn (gen_n_extendhipsi2 (new_src, GEN_INT (segment), src)); + + return new_src; } } diff --git a/config/avr/avr.md b/config/avr/avr.md index 3656eef..d341755 100644 --- a/config/avr/avr.md +++ b/config/avr/avr.md @@ -3845,18 +3845,24 @@ }) (define_insn_and_split "n_extendhipsi2" - [(set (match_operand:PSI 0 "register_operand" "=d") - (ior:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r")) - (match_operand:PSI 2 "hh8_operand" "n")))] + [(set (match_operand:PSI 0 "register_operand" "=r,r,d,r") + (lo_sum:PSI (match_operand:QI 1 "const_int_operand" "L,P,n,n") + (match_operand:HI 2 "register_operand" "r,r,r,r"))) + (clobber (match_scratch:QI 3 "=X,X,X,&d"))] "" "#" "reload_completed" - [(set (match_dup 3) (match_dup 1)) - (set (match_dup 4) (match_dup 5))] + [(set (match_dup 4) (match_dup 2)) + (set (match_dup 3) (match_dup 6)) + ; no-op move in the case where no scratch is needed + (set (match_dup 5) (match_dup 3))] { - operands[3] = simplify_gen_subreg (HImode, operands[0], PSImode, 0); - operands[4] = simplify_gen_subreg (QImode, operands[0], PSImode, 2); - operands[5] = simplify_gen_subreg (QImode, operands[2], PSImode, 2); + operands[4] = simplify_gen_subreg (HImode, operands[0], PSImode, 0); + operands[5] = simplify_gen_subreg (QImode, operands[0], PSImode, 2); + operands[6] = operands[1]; + + if (GET_CODE (operands[3]) == SCRATCH) + operands[3] = operands[5]; }) (define_insn_and_split "zero_extendhisi2" diff --git a/config/avr/predicates.md b/config/avr/predicates.md index f2a6a70..2db6f3b 100644 --- a/config/avr/predicates.md +++ b/config/avr/predicates.md @@ -249,8 +249,3 @@ (define_predicate "o16_operand" (and (match_code "const_int") (match_test "IN_RANGE (INTVAL (op), -(1<<16), -1)"))) - -;; CONST_INT were ony sub-byte #2 may have non-zero value. -(define_predicate "hh8_operand" - (and (match_code "const_int") - (match_test "IN_RANGE (INTVAL (op), 0x00010000, 0x00ff0000)")))