aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/avr')
-rw-r--r--gcc/config/avr/avr.cc43
-rw-r--r--gcc/config/avr/avr.md67
2 files changed, 102 insertions, 8 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 227c12a..0bdba55 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -3272,7 +3272,8 @@ avr_load_libgcc_p (rtx op)
return (n_bytes > 2
&& !AVR_HAVE_LPMX
- && avr_mem_flash_p (op));
+ && avr_mem_flash_p (op)
+ && MEM_ADDR_SPACE (op) == ADDR_SPACE_FLASH);
}
@@ -3624,6 +3625,46 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen)
avr_asm_len ("sbiw %2,1", xop, plen, 1);
break; /* 2 */
+
+ /* cases 3 and 4 are only needed with ELPM but no ELPMx. */
+
+ case 3:
+ if (REGNO (dest) == REG_Z - 2
+ && !reg_unused_after (insn, all_regs_rtx[REG_31]))
+ avr_asm_len ("push r31", xop, plen, 1);
+
+ avr_asm_len ("%4lpm $ mov %A0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %B0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %C0,%3", xop, plen, 2);
+
+ if (REGNO (dest) == REG_Z - 2)
+ {
+ if (!reg_unused_after (insn, all_regs_rtx[REG_31]))
+ avr_asm_len ("pop r31", xop, plen, 1);
+ }
+ else if (!reg_unused_after (insn, addr))
+ avr_asm_len ("sbiw %2,2", xop, plen, 1);
+
+ break; /* 3 */
+
+ case 4:
+ avr_asm_len ("%4lpm $ mov %A0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %B0,%3 $ adiw %2,1", xop, plen, 3);
+ if (REGNO (dest) != REG_Z - 2)
+ {
+ avr_asm_len ("%4lpm $ mov %C0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %D0,%3", xop, plen, 2);
+ if (!reg_unused_after (insn, addr))
+ avr_asm_len ("sbiw %2,3", xop, plen, 1);
+ }
+ else
+ {
+ avr_asm_len ("%4lpm $ push %3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %D0,%3", xop, plen, 2);
+ avr_asm_len ("pop $C0", xop, plen, 1);
+ }
+
+ break; /* 4 */
}
break; /* REG */
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 30a02a4..d73cf96 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -3947,9 +3947,17 @@
(match_operand:PSI 2 "nonmemory_operand" "")))
(clobber (reg:HI 26))
(clobber (reg:DI 18))])]
- "AVR_HAVE_MUL"
+ "AVR_HAVE_MUL
+ || (avropt_pr118012
+ /* AVR_TINY passes args on the stack, so we cannot work
+ around PR118012 like this. */
+ && ! AVR_TINY)"
{
- if (s8_operand (operands[2], PSImode))
+ if (!AVR_HAVE_MUL)
+ {
+ operands[2] = force_reg (PSImode, operands[2]);
+ }
+ else if (s8_operand (operands[2], PSImode))
{
rtx reg = force_reg (QImode, gen_int_mode (INTVAL (operands[2]), QImode));
emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1]));
@@ -4038,7 +4046,9 @@
(match_operand:PSI 2 "pseudo_register_or_const_int_operand" "rn")))
(clobber (reg:HI 26))
(clobber (reg:DI 18))]
- "AVR_HAVE_MUL && !reload_completed"
+ "!reload_completed
+ && (AVR_HAVE_MUL
+ || (avropt_pr118012 && !AVR_TINY))"
{ gcc_unreachable(); }
"&& 1"
[(set (reg:PSI 18)
@@ -4048,13 +4058,30 @@
(parallel [(set (reg:PSI 22)
(mult:PSI (reg:PSI 22)
(reg:PSI 18)))
- (clobber (reg:QI 21))
- (clobber (reg:QI 25))
- (clobber (reg:HI 26))])
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))
+ (clobber (match_dup 5))])
(set (match_dup 0)
(reg:PSI 22))]
{
- if (s8_operand (operands[2], PSImode))
+ if (AVR_HAVE_MUL)
+ {
+ operands[3] = gen_rtx_REG (QImode, REG_21);
+ operands[4] = gen_rtx_REG (QImode, REG_25);
+ operands[5] = gen_rtx_REG (HImode, REG_26);
+ }
+ else
+ {
+ operands[3] = gen_rtx_REG (SImode, REG_18);
+ operands[4] = gen_rtx_SCRATCH (QImode);
+ operands[5] = gen_rtx_SCRATCH (HImode);
+ }
+
+ if (!AVR_HAVE_MUL)
+ {
+ operands[2] = force_reg (PSImode, operands[2]);
+ }
+ else if (s8_operand (operands[2], PSImode))
{
rtx reg = force_reg (QImode, gen_int_mode (INTVAL (operands[2]), QImode));
emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1]));
@@ -4106,6 +4133,32 @@
"%~call __mulpsi3"
[(set_attr "type" "xcall")])
+(define_insn_and_split "*mulpsi3-nomul.libgcc_split"
+ [(set (reg:PSI 22)
+ (mult:PSI (reg:PSI 22)
+ (reg:PSI 18)))
+ (clobber (reg:SI 18))
+ (clobber (scratch:QI))
+ (clobber (scratch:HI))]
+ "!AVR_HAVE_MUL && avropt_pr118012 && !AVR_TINY"
+ "#"
+ "&& reload_completed"
+ [(scratch)]
+ { DONE_ADD_CCC })
+
+(define_insn "*mulpsi3-nomul.libgcc"
+ [(set (reg:PSI 22)
+ (mult:PSI (reg:PSI 22)
+ (reg:PSI 18)))
+ (clobber (reg:SI 18))
+ (clobber (scratch:QI))
+ (clobber (scratch:HI))
+ (clobber (reg:CC REG_CC))]
+ "reload_completed
+ && !AVR_HAVE_MUL && avropt_pr118012 && !AVR_TINY"
+ "%~call __mulpsi3"
+ [(set_attr "type" "xcall")])
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 24-bit signed/unsigned division and modulo.