diff options
Diffstat (limited to 'gcc/config/avr/avr.c')
-rw-r--r-- | gcc/config/avr/avr.c | 191 |
1 files changed, 161 insertions, 30 deletions
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 2a5be23e289..e65a98b444c 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -1,5 +1,5 @@ /* Subroutines for insn-output.c for ATMEL AVR micro controllers - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. Contributed by Denis Chertykov (denisc@overta.ru) @@ -660,14 +660,12 @@ avr_output_function_prologue (FILE *file, HOST_WIDE_INT size) } else if (minimize && (frame_pointer_needed || live_seq > 6)) { - const char *cfun_name = current_function_name (); fprintf (file, ("\t" AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, size); - fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB - AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB), - cfun_name, cfun_name); + fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB + AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file); prologue_size += 4; @@ -683,7 +681,7 @@ avr_output_function_prologue (FILE *file, HOST_WIDE_INT size) (18 - live_seq) * 2); ++prologue_size; } - fprintf (file, ".L_%s_body:\n", cfun_name); + fputs ("1:\n", file); } else { @@ -1099,6 +1097,16 @@ print_operand (FILE *file, rtx x, int code) print_operand (file, XEXP (addr, 1), 0); } + else if (code == 'p' || code == 'r') + { + if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC) + fatal_insn ("bad address, not post_inc or pre_dec:", addr); + + if (code == 'p') + print_operand_address (file, XEXP (addr, 0)); /* X, Y, Z */ + else + print_operand (file, XEXP (addr, 0), 0); /* r26, r28, r30 */ + } else if (GET_CODE (addr) == PLUS) { print_operand_address (file, XEXP (addr,0)); @@ -1208,6 +1216,7 @@ notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn) rtx x = XEXP (src, 1); if (GET_CODE (x) == CONST_INT + && INTVAL (x) > 0 && INTVAL (x) != 6) { cc_status.value1 = SET_DEST (set); @@ -1813,6 +1822,9 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l) rtx base = XEXP (src, 0); int reg_dest = true_regnum (dest); int reg_base = true_regnum (base); + /* "volatile" forces reading low byte first, even if less efficient, + for correct operation with 16-bit I/O registers. */ + int mem_volatile_p = MEM_VOLATILE_P (src); int tmp; if (!l) @@ -1906,6 +1918,25 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l) if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) fatal_insn ("incorrect insn:", insn); + if (mem_volatile_p) + { + if (REGNO (XEXP (base, 0)) == REG_X) + { + *l = 4; + return (AS2 (sbiw,r26,2) CR_TAB + AS2 (ld,%A0,X+) CR_TAB + AS2 (ld,%B0,X) CR_TAB + AS2 (sbiw,r26,1)); + } + else + { + *l = 3; + return (AS2 (sbiw,%r1,2) CR_TAB + AS2 (ld,%A0,%p1) CR_TAB + AS2 (ldd,%B0,%p1+1)); + } + } + *l = 2; return (AS2 (ld,%B0,%1) CR_TAB AS2 (ld,%A0,%1)); @@ -2486,7 +2517,11 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l) rtx base = XEXP (dest, 0); int reg_base = true_regnum (base); int reg_src = true_regnum (src); + /* "volatile" forces writing high byte first, even if less efficient, + for correct operation with 16-bit I/O registers. */ + int mem_volatile_p = MEM_VOLATILE_P (dest); int tmp; + if (!l) l = &tmp; if (CONSTANT_ADDRESS_P (base)) @@ -2506,33 +2541,33 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l) { if (reg_src == REG_X) { - /* "st X+,r26" is undefined */ - if (reg_unused_after (insn, src)) + /* "st X+,r26" and "st -X,r26" are undefined. */ + if (!mem_volatile_p && reg_unused_after (insn, src)) return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB AS2 (st,X,r26) CR_TAB AS2 (adiw,r26,1) CR_TAB AS2 (st,X,__tmp_reg__)); else return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB - AS2 (st,X,r26) CR_TAB AS2 (adiw,r26,1) CR_TAB AS2 (st,X,__tmp_reg__) CR_TAB - AS2 (sbiw,r26,1)); + AS2 (sbiw,r26,1) CR_TAB + AS2 (st,X,r26)); } else { - if (reg_unused_after (insn, base)) + if (!mem_volatile_p && reg_unused_after (insn, base)) return *l=2, (AS2 (st,X+,%A1) CR_TAB AS2 (st,X,%B1)); else - return *l=3, (AS2 (st ,X+,%A1) CR_TAB - AS2 (st ,X,%B1) CR_TAB - AS2 (sbiw,r26,1)); + return *l=3, (AS2 (adiw,r26,1) CR_TAB + AS2 (st,X,%B1) CR_TAB + AS2 (st,-X,%A1)); } } else - return *l=2, (AS2 (st ,%0,%A1) CR_TAB - AS2 (std,%0+1,%B1)); + return *l=2, (AS2 (std,%0+1,%B1) CR_TAB + AS2 (st,%0,%A1)); } else if (GET_CODE (base) == PLUS) { @@ -2545,14 +2580,14 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l) if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB - AS2 (std,Y+62,%A1) CR_TAB AS2 (std,Y+63,%B1) CR_TAB + AS2 (std,Y+62,%A1) CR_TAB AS2 (sbiw,r28,%o0-62)); return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB AS2 (sbci,r29,hi8(-%o0)) CR_TAB - AS2 (st,Y,%A1) CR_TAB AS2 (std,Y+1,%B1) CR_TAB + AS2 (st,Y,%A1) CR_TAB AS2 (subi,r28,lo8(%o0)) CR_TAB AS2 (sbci,r29,hi8(%o0))); } @@ -2560,31 +2595,53 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l) { /* (X + d) = R */ if (reg_src == REG_X) - { + { *l = 7; return (AS2 (mov,__tmp_reg__,r26) CR_TAB AS2 (mov,__zero_reg__,r27) CR_TAB - AS2 (adiw,r26,%o0) CR_TAB - AS2 (st,X+,__tmp_reg__) CR_TAB + AS2 (adiw,r26,%o0+1) CR_TAB AS2 (st,X,__zero_reg__) CR_TAB + AS2 (st,-X,__tmp_reg__) CR_TAB AS1 (clr,__zero_reg__) CR_TAB - AS2 (sbiw,r26,%o0+1)); + AS2 (sbiw,r26,%o0)); } *l = 4; - return (AS2 (adiw,r26,%o0) CR_TAB - AS2 (st,X+,%A1) CR_TAB - AS2 (st,X,%B1) CR_TAB - AS2 (sbiw,r26,%o0+1)); + return (AS2 (adiw,r26,%o0+1) CR_TAB + AS2 (st,X,%B1) CR_TAB + AS2 (st,-X,%A1) CR_TAB + AS2 (sbiw,r26,%o0)); } - return *l=2, (AS2 (std,%A0,%A1) CR_TAB - AS2 (std,%B0,%B1)); + return *l=2, (AS2 (std,%B0,%B1) CR_TAB + AS2 (std,%A0,%A1)); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ return *l=2, (AS2 (st,%0,%B1) CR_TAB AS2 (st,%0,%A1)); else if (GET_CODE (base) == POST_INC) /* (R++) */ - return *l=2, (AS2 (st,%0,%A1) CR_TAB - AS2 (st,%0,%B1)); + { + if (mem_volatile_p) + { + if (REGNO (XEXP (base, 0)) == REG_X) + { + *l = 4; + return (AS2 (adiw,r26,1) CR_TAB + AS2 (st,X,%B1) CR_TAB + AS2 (st,-X,%A1) CR_TAB + AS2 (adiw,r26,2)); + } + else + { + *l = 3; + return (AS2 (std,%p0+1,%B1) CR_TAB + AS2 (st,%p0,%A1) CR_TAB + AS2 (adiw,%r0,2)); + } + } + + *l = 2; + return (AS2 (st,%0,%A1) CR_TAB + AS2 (st,%0,%B1)); + } fatal_insn ("unknown move insn:",insn); return ""; } @@ -2728,6 +2785,13 @@ out_shift_with_cnt (const char *template, rtx insn, rtx operands[], int count = INTVAL (operands[2]); int max_len = 10; /* If larger than this, always use a loop. */ + if (count <= 0) + { + if (len) + *len = 0; + return; + } + if (count < 8 && !scratch) use_zero_reg = 1; @@ -2850,6 +2914,9 @@ ashlqi3_out (rtx insn, rtx operands[], int *len) switch (INTVAL (operands[2])) { default: + if (INTVAL (operands[2]) < 8) + break; + *len = 1; return AS1 (clr,%0); @@ -2946,6 +3013,14 @@ ashlhi3_out (rtx insn, rtx operands[], int *len) switch (INTVAL (operands[2])) { + default: + if (INTVAL (operands[2]) < 16) + break; + + *len = 2; + return (AS1 (clr,%B0) CR_TAB + AS1 (clr,%A0)); + case 4: if (optimize_size && scratch) break; /* 5 */ @@ -3197,6 +3272,20 @@ ashlsi3_out (rtx insn, rtx operands[], int *len) switch (INTVAL (operands[2])) { + default: + if (INTVAL (operands[2]) < 32) + break; + + if (AVR_ENHANCED) + return *len = 3, (AS1 (clr,%D0) CR_TAB + AS1 (clr,%C0) CR_TAB + AS2 (movw,%A0,%C0)); + *len = 4; + return (AS1 (clr,%D0) CR_TAB + AS1 (clr,%C0) CR_TAB + AS1 (clr,%B0) CR_TAB + AS1 (clr,%A0)); + case 8: { int reg0 = true_regnum (operands[0]); @@ -3335,6 +3424,11 @@ ashrqi3_out (rtx insn, rtx operands[], int *len) AS2 (bld,%0,0)); default: + if (INTVAL (operands[2]) < 8) + break; + + /* fall through */ + case 7: *len = 2; return (AS1 (lsl,%0) CR_TAB @@ -3498,6 +3592,12 @@ ashrhi3_out (rtx insn, rtx operands[], int *len) AS2 (mov,%B0,%A0) CR_TAB AS1 (rol,%A0)); + default: + if (INTVAL (operands[2]) < 16) + break; + + /* fall through */ + case 15: return *len = 3, (AS1 (lsl,%B0) CR_TAB AS2 (sbc,%A0,%A0) CR_TAB @@ -3605,6 +3705,12 @@ ashrsi3_out (rtx insn, rtx operands[], int *len) AS2 (mov,%B0,%D0) CR_TAB AS2 (mov,%C0,%D0)); + default: + if (INTVAL (operands[2]) < 32) + break; + + /* fall through */ + case 31: if (AVR_ENHANCED) return *len = 4, (AS1 (lsl,%D0) CR_TAB @@ -3643,6 +3749,9 @@ lshrqi3_out (rtx insn, rtx operands[], int *len) switch (INTVAL (operands[2])) { default: + if (INTVAL (operands[2]) < 8) + break; + *len = 1; return AS1 (clr,%0); @@ -3737,6 +3846,14 @@ lshrhi3_out (rtx insn, rtx operands[], int *len) switch (INTVAL (operands[2])) { + default: + if (INTVAL (operands[2]) < 16) + break; + + *len = 2; + return (AS1 (clr,%B0) CR_TAB + AS1 (clr,%A0)); + case 4: if (optimize_size && scratch) break; /* 5 */ @@ -3987,6 +4104,20 @@ lshrsi3_out (rtx insn, rtx operands[], int *len) switch (INTVAL (operands[2])) { + default: + if (INTVAL (operands[2]) < 32) + break; + + if (AVR_ENHANCED) + return *len = 3, (AS1 (clr,%D0) CR_TAB + AS1 (clr,%C0) CR_TAB + AS2 (movw,%A0,%C0)); + *len = 4; + return (AS1 (clr,%D0) CR_TAB + AS1 (clr,%C0) CR_TAB + AS1 (clr,%B0) CR_TAB + AS1 (clr,%A0)); + case 8: { int reg0 = true_regnum (operands[0]); |