@@ -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;
}
}
@@ -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"
@@ -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)")))