diff options
Diffstat (limited to 'gcc/config/avr')
| -rw-r--r-- | gcc/config/avr/avr.cc | 43 | ||||
| -rw-r--r-- | gcc/config/avr/avr.md | 67 | 
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.  | 
