diff options
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/avr/avr-arch.h | 4 | ||||
-rw-r--r-- | gcc/config/avr/avr-c.c | 22 | ||||
-rw-r--r-- | gcc/config/avr/avr-devices.c | 46 | ||||
-rw-r--r-- | gcc/config/avr/avr-mcus.def | 8 | ||||
-rw-r--r-- | gcc/config/avr/avr-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/avr/avr-tables.opt | 3 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 905 | ||||
-rw-r--r-- | gcc/config/avr/avr.h | 4 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 98 | ||||
-rw-r--r-- | gcc/config/avr/t-multilib | 7 |
10 files changed, 996 insertions, 102 deletions
diff --git a/gcc/config/avr/avr-arch.h b/gcc/config/avr/avr-arch.h index 4e368af..168793e 100644 --- a/gcc/config/avr/avr-arch.h +++ b/gcc/config/avr/avr-arch.h @@ -37,6 +37,7 @@ enum avr_arch ARCH_AVR5, ARCH_AVR51, ARCH_AVR6, + ARCH_AVRTINY, ARCH_AVRXMEGA2, ARCH_AVRXMEGA4, ARCH_AVRXMEGA5, @@ -77,6 +78,9 @@ typedef struct and thus also the RAMPX, RAMPY and RAMPZ registers. */ int have_rampd; + /* This is a TINY core. */ + int tiny_p; + /* Default start of data section address for architecture. */ int default_data_section_start; diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c index d5c40e6..f66f361 100644 --- a/gcc/config/avr/avr-c.c +++ b/gcc/config/avr/avr-c.c @@ -321,6 +321,23 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile) } if (AVR_XMEGA) cpp_define (pfile, "__AVR_XMEGA__"); + + if (AVR_TINY) + { + cpp_define (pfile, "__AVR_TINY__"); + + /* Define macro "__AVR_TINY_PM_BASE_ADDRESS__" with mapped program memory + start address. This macro shall be referred where mapped program memory + is accessed. (Eg. copying data section (do_copy_data) contents to data + memory region. + NOTE: + Program memory of AVR_TINY devices can not be accessed directly, it has + been mapped to the data memory. For AVR_TINY devices (ATtiny4/ 5/ 9/ 10/ + 20 and 40) mapped program memory starts at 0x4000. + */ + cpp_define (pfile, "__AVR_TINY_PM_BASE_ADDRESS__=0x4000"); + } + if (avr_current_arch->have_eijmp_eicall) { cpp_define (pfile, "__AVR_HAVE_EIJMP_EICALL__"); @@ -376,7 +393,10 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile) /* Only supply __FLASH<n> macro if the address space is reasonable for this target. The address space qualifier itself is still supported, but using it will throw an error. */ - && avr_addrspace[i].segment < avr_n_flash) + && avr_addrspace[i].segment < avr_n_flash + /* Only support __MEMX macro if we have LPM. */ + && (AVR_HAVE_LPM || avr_addrspace[i].pointer_size <= 2)) + { const char *name = avr_addrspace[i].name; char *Name = (char*) alloca (1 + strlen (name)); diff --git a/gcc/config/avr/avr-devices.c b/gcc/config/avr/avr-devices.c index 9044d71..a926d20 100644 --- a/gcc/config/avr/avr-devices.c +++ b/gcc/config/avr/avr-devices.c @@ -31,29 +31,30 @@ const avr_arch_t avr_arch_types[] = { /* unknown device specified */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, NULL, "avr2" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, NULL, "avr2" }, /* - A M J LM E E E X R d S S O A - S U M PO L L I M A a t F ff r - M L P MV P P J E M t a R s c - XW M M M G P a r e h - X P A D t t ID */ - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "1", "avr1" }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "2", "avr2" }, - { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, "25", "avr25" }, - { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "3", "avr3" }, - { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 32, "31", "avr31" }, - { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, "35", "avr35" }, - { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, "4", "avr4" }, - { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, "5", "avr5" }, - { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, "51", "avr51" }, - { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 32, "6", "avr6" }, + A M J LM E E E X R T d S S O A + S U M PO L L I M A I a t F ff r + M L P MV P P J E M N t a R s c + XW M M M G P Y a r e h + X P A D t t ID */ + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "1", "avr1" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "2", "avr2" }, + { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "25", "avr25" }, + { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "3", "avr3" }, + { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, "31", "avr31" }, + { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "35", "avr35" }, + { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "4", "avr4" }, + { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "5", "avr5" }, + { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0x0060, 32, "51", "avr51" }, + { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, "6", "avr6" }, - { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0x2000, 0, "102", "avrxmega2" }, - { 0, 1, 1, 1, 1, 1, 0, 1, 0, 0x2000, 0, "104", "avrxmega4" }, - { 0, 1, 1, 1, 1, 1, 0, 1, 1, 0x2000, 0, "105", "avrxmega5" }, - { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0x2000, 0, "106", "avrxmega6" }, - { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0x2000, 0, "107", "avrxmega7" } + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0x0040, 0, "100", "avrtiny" }, + { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0x2000, 0, "102", "avrxmega2" }, + { 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0x2000, 0, "104", "avrxmega4" }, + { 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0x2000, 0, "105", "avrxmega5" }, + { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0x2000, 0, "106", "avrxmega6" }, + { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0x2000, 0, "107", "avrxmega7" } }; const avr_arch_info_t @@ -85,6 +86,9 @@ avr_texinfo[] = { ARCH_AVR6, "``Enhanced'' devices with 3-byte PC, i.e.@: with more than 128@tie{}KiB " "of program memory." }, + { ARCH_AVRTINY, + "``TINY'' Tiny core devices with 512@tie{}B up to 4@tie{}KiB of " + "program memory." }, { ARCH_AVRXMEGA2, "``XMEGA'' devices with more than 8@tie{}KiB and up to 64@tie{}KiB " "of program memory." }, diff --git a/gcc/config/avr/avr-mcus.def b/gcc/config/avr/avr-mcus.def index acec6a5..e890149 100644 --- a/gcc/config/avr/avr-mcus.def +++ b/gcc/config/avr/avr-mcus.def @@ -326,6 +326,14 @@ AVR_MCU ("avrxmega7", ARCH_AVRXMEGA7, AVR_ISA_NONE, NULL, AVR_MCU ("atxmega128a1", ARCH_AVRXMEGA7, AVR_ISA_NONE, "__AVR_ATxmega128A1__", 0x2000, 0x0, 3, "x128a1") AVR_MCU ("atxmega128a1u", ARCH_AVRXMEGA7, AVR_ISA_RMW, "__AVR_ATxmega128A1U__", 0x2000, 0x0, 3, "x128a1u") AVR_MCU ("atxmega128a4u", ARCH_AVRXMEGA7, AVR_ISA_RMW, "__AVR_ATxmega128A4U__", 0x2000, 0x0, 3, "x128a4u") +/* Tiny family */ +AVR_MCU ("avrtiny", ARCH_AVRTINY, AVR_ISA_NONE, NULL, 0x0040, 0x0, 1, "tn10") +AVR_MCU ("attiny4", ARCH_AVRTINY, AVR_ISA_NONE, "__AVR_ATtiny4__", 0x0040, 0x0, 1, "tn4") +AVR_MCU ("attiny5", ARCH_AVRTINY, AVR_ISA_NONE, "__AVR_ATtiny5__", 0x0040, 0x0, 1, "tn5") +AVR_MCU ("attiny9", ARCH_AVRTINY, AVR_ISA_NONE, "__AVR_ATtiny9__", 0x0040, 0x0, 1, "tn9") +AVR_MCU ("attiny10", ARCH_AVRTINY, AVR_ISA_NONE, "__AVR_ATtiny10__", 0x0040, 0x0, 1, "tn10") +AVR_MCU ("attiny20", ARCH_AVRTINY, AVR_ISA_NONE, "__AVR_ATtiny20__", 0x0040, 0x0, 1, "tn20") +AVR_MCU ("attiny40", ARCH_AVRTINY, AVR_ISA_NONE, "__AVR_ATtiny40__", 0x0040, 0x0, 1, "tn40") /* Assembler only. */ AVR_MCU ("avr1", ARCH_AVR1, AVR_ISA_NONE, NULL, 0x0060, 0x0, 1, "s1200") AVR_MCU ("at90s1200", ARCH_AVR1, AVR_ISA_NONE, "__AVR_AT90S1200__", 0x0060, 0x0, 1, "s1200") diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index d078404..6342c08 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -46,6 +46,7 @@ extern void avr_init_cumulative_args (CUMULATIVE_ARGS*, tree, rtx, tree); #ifdef RTX_CODE extern int avr_hard_regno_call_part_clobbered (unsigned, enum machine_mode); +extern bool tiny_valid_direct_memory_access_range(rtx, enum machine_mode); extern const char *output_movqi (rtx_insn *insn, rtx operands[], int *l); extern const char *output_movhi (rtx_insn *insn, rtx operands[], int *l); extern const char *output_movsisf (rtx_insn *insn, rtx operands[], int *l); diff --git a/gcc/config/avr/avr-tables.opt b/gcc/config/avr/avr-tables.opt index 4de0dbd..c7e72c2 100644 --- a/gcc/config/avr/avr-tables.opt +++ b/gcc/config/avr/avr-tables.opt @@ -66,5 +66,8 @@ EnumValue Enum(avr_arch) String(avrxmega7) Value(ARCH_AVRXMEGA7) EnumValue +Enum(avr_arch) String(avrtiny) Value(ARCH_AVRTINY) + +EnumValue Enum(avr_arch) String(avr1) Value(ARCH_AVR1) diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 704c6f7..6c781c9 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -88,6 +88,17 @@ ((SYMBOL_REF_FLAGS (sym) & AVR_SYMBOL_FLAG_PROGMEM) \ / SYMBOL_FLAG_MACH_DEP) +#define TINY_ADIW(REG1, REG2, I) \ + "subi " #REG1 ",lo8(-(" #I "))" CR_TAB \ + "sbci " #REG2 ",hi8(-(" #I "))" + +#define TINY_SBIW(REG1, REG2, I) \ + "subi " #REG1 ",lo8((" #I "))" CR_TAB \ + "sbci " #REG2 ",hi8((" #I "))" + +#define AVR_TMP_REGNO (AVR_TINY ? TMP_REGNO_TINY : TMP_REGNO) +#define AVR_ZERO_REGNO (AVR_TINY ? ZERO_REGNO_TINY : ZERO_REGNO) + /* Known address spaces. The order must be the same as in the respective enum from avr.h (or designated initialized must be used). */ const avr_addrspace_t avr_addrspace[ADDR_SPACE_COUNT] = @@ -156,6 +167,9 @@ static bool avr_rtx_costs (rtx, int, int, int, int*, bool); /* Allocate registers from r25 to r8 for parameters for function calls. */ #define FIRST_CUM_REG 26 +/* Last call saved register */ +#define LAST_CALLEE_SAVED_REG (AVR_TINY ? 19 : 17) + /* Implicit target register of LPM instruction (R0) */ extern GTY(()) rtx lpm_reg_rtx; rtx lpm_reg_rtx; @@ -365,7 +379,7 @@ avr_option_override (void) avr_addr.rampy = 0x3A + avr_current_arch->sfr_offset; avr_addr.rampx = 0x39 + avr_current_arch->sfr_offset; avr_addr.rampd = 0x38 + avr_current_arch->sfr_offset; - avr_addr.ccp = 0x34 + avr_current_arch->sfr_offset; + avr_addr.ccp = (AVR_TINY ? 0x3C : 0x34) + avr_current_arch->sfr_offset; /* SP: Stack Pointer (SP_H:SP_L) */ avr_addr.sp_l = 0x3D + avr_current_arch->sfr_offset; @@ -397,8 +411,8 @@ avr_init_expanders (void) all_regs_rtx[regno] = gen_rtx_REG (QImode, regno); lpm_reg_rtx = all_regs_rtx[LPM_REGNO]; - tmp_reg_rtx = all_regs_rtx[TMP_REGNO]; - zero_reg_rtx = all_regs_rtx[ZERO_REGNO]; + tmp_reg_rtx = all_regs_rtx[AVR_TMP_REGNO]; + zero_reg_rtx = all_regs_rtx[AVR_ZERO_REGNO]; lpm_addr_reg_rtx = gen_rtx_REG (HImode, REG_Z); @@ -410,6 +424,11 @@ avr_init_expanders (void) xstring_empty = gen_rtx_CONST_STRING (VOIDmode, ""); xstring_e = gen_rtx_CONST_STRING (VOIDmode, "e"); + + /* TINY core does not have regs r10-r16, but avr-dimode.md expects them + to be present */ + if (AVR_TINY) + avr_have_dimode = false; } @@ -918,7 +937,7 @@ sequent_regs_live (void) int live_seq = 0; int cur_seq = 0; - for (reg = 0; reg < 18; ++reg) + for (reg = 0; reg <= LAST_CALLEE_SAVED_REG; ++reg) { if (fixed_regs[reg]) { @@ -1031,7 +1050,7 @@ emit_push_sfr (rtx sfr, bool frame_related_p, bool clr_p) RTX_FRAME_RELATED_P (insn) = 1; /* PUSH __tmp_reg__ */ - emit_push_byte (TMP_REGNO, frame_related_p); + emit_push_byte (AVR_TMP_REGNO, frame_related_p); if (clr_p) { @@ -1057,7 +1076,8 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) && live_seq && !isr_p && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main); + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (frame_pointer_needed @@ -1094,11 +1114,11 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) /* Note that live_seq always contains r28+r29, but the other registers to be saved are all below 18. */ - first_reg = 18 - (live_seq - 2); + first_reg = (LAST_CALLEE_SAVED_REG + 1) - (live_seq - 2); for (reg = 29, offset = -live_seq + 1; reg >= first_reg; - reg = (reg == 28 ? 17 : reg - 1), ++offset) + reg = (reg == 28 ? LAST_CALLEE_SAVED_REG : reg - 1), ++offset) { rtx m, r; @@ -1338,10 +1358,10 @@ avr_expand_prologue (void) emit_insn (gen_enable_interrupt ()); /* Push zero reg. */ - emit_push_byte (ZERO_REGNO, true); + emit_push_byte (AVR_ZERO_REGNO, true); /* Push tmp reg. */ - emit_push_byte (TMP_REGNO, true); + emit_push_byte (AVR_TMP_REGNO, true); /* Push SREG. */ /* ??? There's no dwarf2 column reserved for SREG. */ @@ -1483,7 +1503,8 @@ avr_expand_epilogue (bool sibcall_p) && live_seq && !isr_p && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main); + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (live_seq > 4 @@ -1641,14 +1662,14 @@ avr_expand_epilogue (bool sibcall_p) /* Restore SREG using tmp_reg as scratch. */ - emit_pop_byte (TMP_REGNO); + emit_pop_byte (AVR_TMP_REGNO); emit_move_insn (sreg_rtx, tmp_reg_rtx); /* Restore tmp REG. */ - emit_pop_byte (TMP_REGNO); + emit_pop_byte (AVR_TMP_REGNO); /* Restore zero REG. */ - emit_pop_byte (ZERO_REGNO); + emit_pop_byte (AVR_ZERO_REGNO); } if (!sibcall_p) @@ -2130,10 +2151,14 @@ avr_print_operand_punct_valid_p (unsigned char code) static void avr_print_operand (FILE *file, rtx x, int code) { - int abcd = 0; + int abcd = 0, ef = 0, ij = 0; if (code >= 'A' && code <= 'D') abcd = code - 'A'; + else if (code == 'E' || code == 'F') + ef = code - 'E'; + else if (code == 'I' || code == 'J') + ij = code - 'I'; if (code == '~') { @@ -2170,6 +2195,16 @@ avr_print_operand (FILE *file, rtx x, int code) else fatal_insn ("operands to %T/%t must be reg + const_int:", x); } + else if (code == 'E' || code == 'F') + { + rtx op = XEXP(x, 0); + fprintf (file, reg_names[REGNO (op) + ef]); + } + else if (code == 'I' || code == 'J') + { + rtx op = XEXP(XEXP(x, 0), 0); + fprintf (file, reg_names[REGNO (op) + ij]); + } else if (REG_P (x)) { if (x == zero_reg_rtx) @@ -2196,7 +2231,7 @@ avr_print_operand (FILE *file, rtx x, int code) fprintf (file, "__RAMPX__"); else if (AVR_HAVE_RAMPD && ival == avr_addr.rampd) fprintf (file, "__RAMPD__"); - else if (AVR_XMEGA && ival == avr_addr.ccp) + else if ((AVR_XMEGA || AVR_TINY) && ival == avr_addr.ccp) fprintf (file, "__CCP__"); else if (ival == avr_addr.sreg) fprintf (file, "__SREG__"); else if (ival == avr_addr.sp_l) fprintf (file, "__SP_L__"); @@ -2239,6 +2274,13 @@ avr_print_operand (FILE *file, rtx x, int code) avr_print_operand (file, XEXP (addr, 1), 0); } + else if (code == 'b') + { + if (GET_CODE (addr) != PLUS) + fatal_insn ("bad address, not (reg+disp):", addr); + + avr_print_operand_address (file, XEXP (addr, 0)); + } else if (code == 'p' || code == 'r') { if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC) @@ -2596,7 +2638,7 @@ avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE op, rtx x) int avr_function_arg_regno_p(int r) { - return (r >= 8 && r <= 25); + return (AVR_TINY ? r >= 20 && r <= 25 : r >= 8 && r <= 25); } @@ -2608,7 +2650,7 @@ void avr_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname, tree fndecl ATTRIBUTE_UNUSED) { - cum->nregs = 18; + cum->nregs = AVR_TINY ? 6 : 18; cum->regno = FIRST_CUM_REG; if (!libname && stdarg_p (fntype)) cum->nregs = 0; @@ -3144,6 +3186,35 @@ avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) return ""; } +/* +AVRTC-579 +if operand is symbol or constant expression with value > 0xbf + return false, otherwise true +This check is used to avoid lds/sts instruction with invalid memory +access range (valid range 0x40..0xbf). For io operand range 0x0..0x3f, +in/out instruction will be generated. +*/ +bool tiny_valid_direct_memory_access_range(rtx op, enum machine_mode mode) +{ + rtx x; + + if (!AVR_TINY) + return true; + + x = XEXP(op,0); + + if (MEM_P(op) && x && (GET_CODE(x) == SYMBOL_REF)) + { + return false; + } + if (MEM_P(op) && x && (CONSTANT_ADDRESS_P (x)) && + !(IN_RANGE (INTVAL (x), 0, 0xC0 - GET_MODE_SIZE (mode)))) + { + return false; + } + + return true; +} const char* output_movqi (rtx_insn *insn, rtx operands[], int *plen) @@ -3272,6 +3343,24 @@ output_movhi (rtx_insn *insn, rtx xop[], int *plen) return ""; } +/* Same as out_movqi_r_mr, but TINY does not have ADIW or SBIW */ +static const char* +avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx x = XEXP (src, 0); + + avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB + "ld %0,%b1" , op, plen, -3); + + if (!reg_overlap_mentioned_p (dest, XEXP (x,0)) + && !reg_unused_after (insn, XEXP (x,0))) + avr_asm_len (TINY_SBIW (%I1, %J1, %o1), op, plen, 2); + + return ""; +} + static const char* out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) { @@ -3281,11 +3370,13 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) if (CONSTANT_ADDRESS_P (x)) { + int n_words = AVR_TINY ? 1 : 2; return optimize > 0 && io_address_operand (x, QImode) ? avr_asm_len ("in %0,%i1", op, plen, -1) - : avr_asm_len ("lds %0,%m1", op, plen, -2); + : avr_asm_len ("lds %0,%m1", op, plen, -n_words); } - else if (GET_CODE (x) == PLUS + + if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) { @@ -3293,6 +3384,9 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) int disp = INTVAL (XEXP (x, 1)); + if (AVR_TINY) + return avr_out_movqi_r_mr_reg_disp_tiny (insn, op, plen); + if (disp - GET_MODE_SIZE (GET_MODE (src)) >= 63) { if (REGNO (XEXP (x, 0)) != REG_Y) @@ -3332,6 +3426,82 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) return avr_asm_len ("ld %0,%1", op, plen, -1); } +/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ +static const char* +avr_out_movhi_r_mr_reg_no_disp_tiny (rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + + if (reg_dest == reg_base) /* R = (R) */ + return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB + "ld %B0,%1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -3); + + return avr_asm_len ("ld %A0,%1" CR_TAB + TINY_ADIW (%E1, %F1, 1) CR_TAB + "ld %B0,%1" CR_TAB + TINY_SBIW (%E1, %F1, 1), op, plen, -6); + +} + +/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ +static const char* +avr_out_movhi_r_mr_reg_disp_tiny (rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (XEXP (base, 0)); + + if (reg_base == reg_dest) + { + return avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB + "ld __tmp_reg__,%b1+" CR_TAB + "ld %B0,%b1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -5); + } + else + { + return avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1" CR_TAB + TINY_SBIW (%I1, %J1, %o1+1), op, plen, -6); + } +} + +/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ +static const char* +avr_out_movhi_r_mr_pre_dec_tiny (rtx_insn *insn, rtx op[], int *plen) +{ + int mem_volatile_p = 0; + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + + /* "volatile" forces reading low byte first, even if less efficient, + for correct operation with 16-bit I/O registers. */ + mem_volatile_p = MEM_VOLATILE_P (src); + + if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) + fatal_insn ("incorrect insn:", insn); + + if (!mem_volatile_p) + return avr_asm_len ("ld %B0,%1" CR_TAB + "ld %A0,%1", op, plen, -2); + + return avr_asm_len (TINY_SBIW (%I1, %J1, 2) CR_TAB + "ld %A0,%p1+" CR_TAB + "ld %B0,%p1" CR_TAB + TINY_SBIW (%I1, %J1, 1), op, plen, -6); +} + static const char* out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) { @@ -3346,6 +3516,9 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) if (reg_base > 0) { + if (AVR_TINY) + return avr_out_movhi_r_mr_reg_no_disp_tiny (op, plen); + if (reg_dest == reg_base) /* R = (R) */ return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB "ld %B0,%1" CR_TAB @@ -3368,6 +3541,9 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) int disp = INTVAL (XEXP (base, 1)); int reg_base = true_regnum (XEXP (base, 0)); + if (AVR_TINY) + return avr_out_movhi_r_mr_reg_disp_tiny (op, plen); + if (disp > MAX_LD_OFFSET (GET_MODE (src))) { if (REGNO (XEXP (base, 0)) != REG_Y) @@ -3379,7 +3555,7 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) "ldd %B0,Y+63" CR_TAB "sbiw r28,%o1-62", op, plen, -4) - : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB "sbci r29,hi8(-%o1)" CR_TAB "ld %A0,Y" CR_TAB "ldd %B0,Y+1" CR_TAB @@ -3413,6 +3589,9 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { + if (AVR_TINY) + return avr_out_movhi_r_mr_pre_dec_tiny (insn, op, plen); + if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) fatal_insn ("incorrect insn:", insn); @@ -3440,12 +3619,13 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) } else if (CONSTANT_ADDRESS_P (base)) { + int n_words = AVR_TINY ? 2 : 4; return optimize > 0 && io_address_operand (base, HImode) ? avr_asm_len ("in %A0,%i1" CR_TAB "in %B0,%i1+1", op, plen, -2) : avr_asm_len ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1", op, plen, -4); + "lds %B0,%m1+1", op, plen, -n_words); } fatal_insn ("unknown move insn:",insn); @@ -3453,6 +3633,99 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) } static const char* +avr_out_movsi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + + if (reg_dest == reg_base) + { + /* "ld r26,-X" is undefined */ + return *l=9, (TINY_ADIW (%E1, %F1, 3) CR_TAB + "ld %D0,%1" CR_TAB + "ld %C0,-%1" CR_TAB + "ld __tmp_reg__,-%1" CR_TAB + TINY_SBIW (%E1, %F1, 1) CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__"); + } + else if (reg_dest == reg_base - 2) + { + return *l=5, ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld __tmp_reg__,%1+" CR_TAB + "ld %D0,%1" CR_TAB + "mov %C0,__tmp_reg__"); + } + else if (reg_unused_after (insn, base)) + { + return *l=4, ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld %C0,%1+" CR_TAB + "ld %D0,%1"); + } + else + { + return *l=6, ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld %C0,%1+" CR_TAB + "ld %D0,%1" CR_TAB + TINY_SBIW (%E1, %F1, 3)); + } +} + +static const char* +avr_out_movsi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *l) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (XEXP (base, 0)); + + if (reg_dest == reg_base) + { + /* "ld r26,-X" is undefined */ + return *l=9, (TINY_ADIW (%I1, %J1, %o1+3) CR_TAB + "ld %D0,%b1" CR_TAB + "ld %C0,-%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%I1, %J1, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__"); + } + else if (reg_dest == reg_base - 2) + { + return *l=7, (TINY_ADIW (%I1, %J1, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld __tmp_reg__,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + "mov %C0,__tmp_reg__"); + } + else if (reg_unused_after (insn, XEXP (base, 0))) + { + return *l=6, (TINY_ADIW (%I1, %J1, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1"); + } + else + { + return *l=8, (TINY_ADIW (%I1, %J1, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + TINY_SBIW (%I1, %J1, %o1+3)); + } +} + +static const char* out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -3467,6 +3740,9 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) if (reg_base > 0) { + if (AVR_TINY) + return avr_out_movsi_r_mr_reg_no_disp_tiny (insn, op, l); + if (reg_base == REG_X) /* (R26) */ { if (reg_dest == REG_X) @@ -3521,6 +3797,9 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) { int disp = INTVAL (XEXP (base, 1)); + if (AVR_TINY) + return avr_out_movsi_r_mr_reg_disp_tiny (insn, op, l); + if (disp > MAX_LD_OFFSET (GET_MODE (src))) { if (REGNO (XEXP (base, 0)) != REG_Y) @@ -3604,16 +3883,134 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) "ld %C0,%1" CR_TAB "ld %D0,%1"); else if (CONSTANT_ADDRESS_P (base)) - return *l=8, ("lds %A0,%m1" CR_TAB + { + if (io_address_operand (base, SImode)) + { + *l = 4; + return ("in %A0,%i1" CR_TAB + "in %B0,%i1+1" CR_TAB + "in %C0,%i1+2" CR_TAB + "in %D0,%i1+3"); + } + else + { + *l = AVR_TINY ? 4 : 8; + return ("lds %A0,%m1" CR_TAB "lds %B0,%m1+1" CR_TAB "lds %C0,%m1+2" CR_TAB "lds %D0,%m1+3"); + } + } fatal_insn ("unknown move insn:",insn); return ""; } static const char* +avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = true_regnum (base); + int reg_src = true_regnum (src); + + if (reg_base == reg_src) + { + /* "ld r26,-X" is undefined */ + if (reg_unused_after (insn, base)) + { + return *l=7, ("mov __tmp_reg__, %B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0+,__tmp_reg__" CR_TAB + "st %0+,%C1" CR_TAB + "st %0+,%D1"); + } + else + { + return *l=9, ("mov __tmp_reg__, %B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0+,__tmp_reg__" CR_TAB + "st %0+,%C1" CR_TAB + "st %0+,%D1" CR_TAB + TINY_SBIW (%E0, %F0, 3)); + } + } + else if (reg_base == reg_src + 2) + { + if (reg_unused_after (insn, base)) + return *l=7, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__"); + else + return *l=9, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%E0, %F0, 3)); + } + + return *l=6, ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,%C1" CR_TAB + "st %0,%D1" CR_TAB + TINY_SBIW (%E0, %F0, 3)); +} + +static const char* +avr_out_movsi_mr_r_reg_disp_tiny (rtx op[], int *l) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = REGNO (XEXP (base, 0)); + int reg_src =true_regnum (src); + + if (reg_base == reg_src) + { + *l = 11; + return ("mov __tmp_reg__,%A2" CR_TAB + "mov __zero_reg__,%B2" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0+,%C2" CR_TAB + "st %b0,%D2" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); + } + else if (reg_src == reg_base - 2) + { + *l = 11; + return ("mov __tmp_reg__,%C2" CR_TAB + "mov __zero_reg__,%D2" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A0" CR_TAB + "st %b0+,%B0" CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0,__zero_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); + } + *l = 8; + return (TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0+,%C1" CR_TAB + "st %b0,%D1" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); +} + +static const char* out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -3627,12 +4024,29 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) l = &tmp; if (CONSTANT_ADDRESS_P (base)) - return *l=8,("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1" CR_TAB - "sts %m0+2,%C1" CR_TAB - "sts %m0+3,%D1"); + { + if (io_address_operand (base, SImode)) + { + return *l=4,("out %i0, %A1" CR_TAB + "out %i0+1,%B1" CR_TAB + "out %i0+2,%C1" CR_TAB + "out %i0+3,%D1"); + } + else + { + *l = AVR_TINY ? 4 : 8; + return ("sts %m0,%A1" CR_TAB + "sts %m0+1,%B1" CR_TAB + "sts %m0+2,%C1" CR_TAB + "sts %m0+3,%D1"); + } + } + if (reg_base > 0) /* (r) */ { + if (AVR_TINY) + return avr_out_movsi_mr_r_reg_no_disp_tiny (insn, op, l); + if (reg_base == REG_X) /* (R26) */ { if (reg_src == REG_X) @@ -3689,6 +4103,10 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); + + if (AVR_TINY) + return avr_out_movsi_mr_r_reg_disp_tiny (op, l); + reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) { @@ -3849,6 +4267,73 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l) /* Handle loads of 24-bit types from memory to register. */ static const char* +avr_out_load_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + + if (reg_base == reg_dest) + { + return avr_asm_len (TINY_ADIW (%E1, %F1, 2) CR_TAB + "ld %C0,%1" CR_TAB + "ld __tmp_reg__,-%1" CR_TAB + TINY_SBIW (%E1, %F1, 1) CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); + } + else + { + return avr_asm_len ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld %C0,%1", op, plen, -3); + + if (reg_dest != reg_base - 2 && + !reg_unused_after (insn, base)) + { + avr_asm_len (TINY_SBIW (%E1, %F1, 2), op, plen, 2); + } + return ""; + } +} + +static const char* +avr_out_load_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + + reg_base = true_regnum (XEXP (base, 0)); + if (reg_base == reg_dest) + { + return avr_asm_len (TINY_ADIW (%I1, %J1, %o1+2) CR_TAB + "ld %C0,%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%I1, %J1, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); + } + else + { + avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1", op, plen, -5); + + if (reg_dest != (reg_base - 2) + && !reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len (TINY_SBIW (%I1, %J1, %o1+2), op, plen, 2); + + return ""; + } +} + +static const char* avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -3859,6 +4344,9 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) if (reg_base > 0) { + if (AVR_TINY) + return avr_out_load_psi_reg_no_disp_tiny (insn, op, plen); + if (reg_base == REG_X) /* (R26) */ { if (reg_dest == REG_X) @@ -3901,6 +4389,9 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) { int disp = INTVAL (XEXP (base, 1)); + if (AVR_TINY) + return avr_out_load_psi_reg_disp_tiny (insn, op, plen); + if (disp > MAX_LD_OFFSET (GET_MODE (src))) { if (REGNO (XEXP (base, 0)) != REG_Y) @@ -3969,14 +4460,94 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) "ld %C0,%1", op, plen, -3); else if (CONSTANT_ADDRESS_P (base)) - return avr_asm_len ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1" CR_TAB - "lds %C0,%m1+2", op, plen , -6); + { + int n_words = AVR_TINY ? 3 : 6; + return avr_asm_len ("lds %A0,%m1" CR_TAB + "lds %B0,%m1+1" CR_TAB + "lds %C0,%m1+2", op, plen , -n_words); + } fatal_insn ("unknown move insn:",insn); return ""; } + +static const char* +avr_out_store_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = true_regnum (base); + int reg_src = true_regnum (src); + + if (reg_base == reg_src) + { + avr_asm_len ("st %0,%A1" CR_TAB + "mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB /* st X+, r27 is undefined */ + "st %0+,__tmp_reg__" CR_TAB + "st %0,%C1", op, plen, -6); + + } + else if (reg_src == reg_base - 2) + { + avr_asm_len ("st %0,%A1" CR_TAB + "mov __tmp_reg__,%C1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0+,%B1" CR_TAB + "st %0,__tmp_reg__", op, plen, 6); + } + else + { + avr_asm_len ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0,%C1", op, plen, -3); + } + + if (!reg_unused_after (insn, base)) + avr_asm_len (TINY_SBIW (%E0, %F0, 2), op, plen, 2); + + return ""; +} + +static const char* +avr_out_store_psi_reg_disp_tiny (rtx *op, int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = REGNO (XEXP (base, 0)); + int reg_src = true_regnum (src); + + if (reg_src == reg_base) + { + return avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0,%C1" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+2), op, plen, -10); + } + else if (reg_src == reg_base - 2) + { + return avr_asm_len ("mov __tmp_reg__,%C1" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,__tmp_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+2), op, plen, -8); + } + + return avr_asm_len (TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,%C1" CR_TAB + TINY_SBIW (%I0, %J0, %o0+2), op, plen, -7); +} + /* Handle store of 24-bit type from register or zero to memory. */ static const char* @@ -3988,12 +4559,18 @@ avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen) int reg_base = true_regnum (base); if (CONSTANT_ADDRESS_P (base)) - return avr_asm_len ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1" CR_TAB - "sts %m0+2,%C1", op, plen, -6); + { + int n_words = AVR_TINY ? 3 : 6; + return avr_asm_len ("sts %m0,%A1" CR_TAB + "sts %m0+1,%B1" CR_TAB + "sts %m0+2,%C1", op, plen, -n_words); + } if (reg_base > 0) /* (r) */ { + if (AVR_TINY) + return avr_out_store_psi_reg_no_disp_tiny (insn, op, plen); + if (reg_base == REG_X) /* (R26) */ { gcc_assert (!reg_overlap_mentioned_p (base, src)); @@ -4015,6 +4592,10 @@ avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen) else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); + + if (AVR_TINY) + return avr_out_store_psi_reg_disp_tiny (op, plen); + reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) @@ -4131,6 +4712,30 @@ avr_out_movpsi (rtx_insn *insn, rtx *op, int *plen) return ""; } +static const char* +avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx x = XEXP (dest, 0); + + if (reg_overlap_mentioned_p (src, XEXP (x, 0))) + { + avr_asm_len ("mov __tmp_reg__,%1" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0,__tmp_reg__", op, plen, -4); + } + else + { + avr_asm_len (TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0,%1" , op, plen, -3); + } + + if (!reg_unused_after (insn, XEXP (x,0))) + avr_asm_len (TINY_SBIW (%I0, %J0, %o0), op, plen, 2); + + return ""; +} static const char* out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) @@ -4141,9 +4746,10 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) if (CONSTANT_ADDRESS_P (x)) { + int n_words = AVR_TINY ? 1 : 2; return optimize > 0 && io_address_operand (x, QImode) ? avr_asm_len ("out %i0,%1", op, plen, -1) - : avr_asm_len ("sts %m0,%1", op, plen, -2); + : avr_asm_len ("sts %m0,%1", op, plen, -n_words); } else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) @@ -4153,6 +4759,9 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) int disp = INTVAL (XEXP (x, 1)); + if (AVR_TINY) + return avr_out_movqi_mr_r_reg_disp_tiny (insn, op, plen); + if (disp - GET_MODE_SIZE (GET_MODE (dest)) >= 63) { if (REGNO (XEXP (x, 0)) != REG_Y) @@ -4213,12 +4822,15 @@ avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen) int mem_volatile_p = MEM_VOLATILE_P (dest); if (CONSTANT_ADDRESS_P (base)) - return optimize > 0 && io_address_operand (base, HImode) - ? avr_asm_len ("out %i0,%A1" CR_TAB - "out %i0+1,%B1", op, plen, -2) + { + int n_words = AVR_TINY ? 2 : 4; + return optimize > 0 && io_address_operand (base, HImode) + ? avr_asm_len ("out %i0,%A1" CR_TAB + "out %i0+1,%B1", op, plen, -2) - : avr_asm_len ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1", op, plen, -4); + : avr_asm_len ("sts %m0,%A1" CR_TAB + "sts %m0+1,%B1", op, plen, -n_words); + } if (reg_base > 0) { @@ -4307,6 +4919,70 @@ avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen) return ""; } +static const char* +avr_out_movhi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = true_regnum (base); + int reg_src = true_regnum (src); + int mem_volatile_p = MEM_VOLATILE_P (dest); + + if (reg_base == reg_src) + { + return !mem_volatile_p && reg_unused_after (insn, src) + ? avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0,__tmp_reg__", op, plen, -5) + : avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0,__tmp_reg__" CR_TAB + TINY_SBIW (%E0, %F0, 1) CR_TAB + "st %0, %A1", op, plen, -7); + } + + return !mem_volatile_p && reg_unused_after (insn, base) + ? avr_asm_len ("st %0+,%A1" CR_TAB + "st %0,%B1", op, plen, -2) + : avr_asm_len (TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0,%B1" CR_TAB + "st -%0,%A1", op, plen, -4); +} + +static const char* +avr_out_movhi_mr_r_reg_disp_tiny (rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = REGNO (XEXP (base, 0)); + int reg_src = true_regnum (src); + + return reg_src == reg_base + ? avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%I0, %J0, %o0+1) CR_TAB + "st %b0,__zero_reg__" CR_TAB + "st -%b0,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0), op, plen, -9) + + : avr_asm_len (TINY_ADIW (%I0, %J0, %o0+1) CR_TAB + "st %b0,%B1" CR_TAB + "st -%b0,%A1" CR_TAB + TINY_SBIW (%I0, %J0, %o0), op, plen, -6); +} + +static const char* +avr_out_movhi_mr_r_post_inc_tiny (rtx op[], int *plen) +{ + return avr_asm_len (TINY_ADIW (%I0, %J0, 1) CR_TAB + "st %p0,%B1" CR_TAB + "st -%p0,%A1" CR_TAB + TINY_ADIW (%I0, %J0, 2), op, plen, -6); +} static const char* out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) @@ -4328,15 +5004,21 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) mem_volatile_p = MEM_VOLATILE_P (dest); if (CONSTANT_ADDRESS_P (base)) - return optimize > 0 && io_address_operand (base, HImode) - ? avr_asm_len ("out %i0+1,%B1" CR_TAB - "out %i0,%A1", op, plen, -2) + { + int n_words = AVR_TINY ? 2 : 4; + return optimize > 0 && io_address_operand (base, HImode) + ? avr_asm_len ("out %i0+1,%B1" CR_TAB + "out %i0,%A1", op, plen, -2) - : avr_asm_len ("sts %m0+1,%B1" CR_TAB - "sts %m0,%A1", op, plen, -4); + : avr_asm_len ("sts %m0+1,%B1" CR_TAB + "sts %m0,%A1", op, plen, -n_words); + } if (reg_base > 0) { + if (AVR_TINY) + return avr_out_movhi_mr_r_reg_no_disp_tiny (insn, op, plen); + if (reg_base != REG_X) return avr_asm_len ("std %0+1,%B1" CR_TAB "st %0,%A1", op, plen, -2); @@ -4365,6 +5047,10 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) else if (GET_CODE (base) == PLUS) { int disp = INTVAL (XEXP (base, 1)); + + if (AVR_TINY) + return avr_out_movhi_mr_r_reg_disp_tiny (op, plen); + reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) { @@ -4414,6 +5100,9 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) return avr_asm_len ("st %0,%A1" CR_TAB "st %0,%B1", op, plen, -2); + if (AVR_TINY) + return avr_out_movhi_mr_r_post_inc_tiny (op, plen); + return REGNO (XEXP (base, 0)) == REG_X ? avr_asm_len ("adiw r26,1" CR_TAB "st X,%B1" CR_TAB @@ -4596,7 +5285,11 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) && (val8 == 0 || reg_unused_after (insn, xreg))) { - avr_asm_len ("sbiw %0,%1", xop, plen, 1); + if (AVR_TINY) + avr_asm_len (TINY_SBIW (%A0, %B0, %1), xop, plen, 2); + else + avr_asm_len ("sbiw %0,%1", xop, plen, 1); + i++; continue; } @@ -4606,7 +5299,9 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) && compare_eq_p (insn) && reg_unused_after (insn, xreg)) { - return avr_asm_len ("adiw %0,%n1", xop, plen, 1); + return AVR_TINY + ? avr_asm_len (TINY_ADIW (%A0, %B0, %n1), xop, plen, 2) + : avr_asm_len ("adiw %0,%n1", xop, plen, 1); } } @@ -8070,7 +8765,8 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p) static bool avr_class_likely_spilled_p (reg_class_t c) { - return (c != ALL_REGS && c != ADDW_REGS); + return (c != ALL_REGS && + (AVR_TINY ? 1 : c != ADDW_REGS)); } @@ -8343,7 +9039,9 @@ avr_nonconst_pointer_addrspace (tree typ) if (!ADDR_SPACE_GENERIC_P (as) && (!TYPE_READONLY (target) - || avr_addrspace[as].segment >= avr_n_flash)) + || avr_addrspace[as].segment >= avr_n_flash + /* Also refuse __memx address space if we can't support it. */ + || (!AVR_HAVE_LPM && avr_addrspace[as].pointer_size > 2))) { return as; } @@ -8465,6 +9163,12 @@ avr_insert_attributes (tree node, tree *attributes) " beyond flash of %qs", node, avr_addrspace[as].name, avr_current_device->name); } + else if (!AVR_HAVE_LPM && avr_addrspace[as].pointer_size > 2) + { + error ("variable %q+D located in address space %qs" + " which is not supported by %qs", + node, avr_addrspace[as].name, avr_current_arch->arch_name); + } if (!TYPE_READONLY (node0) && !TREE_READONLY (node)) @@ -8901,10 +9605,10 @@ avr_file_start (void) fprintf (asm_out_file, "__RAMPX__ = 0x%02x\n", avr_addr.rampx - sfr_offset); if (AVR_HAVE_RAMPD) fprintf (asm_out_file, "__RAMPD__ = 0x%02x\n", avr_addr.rampd - sfr_offset); - if (AVR_XMEGA) + if (AVR_XMEGA || AVR_TINY) fprintf (asm_out_file, "__CCP__ = 0x%02x\n", avr_addr.ccp - sfr_offset); - fprintf (asm_out_file, "__tmp_reg__ = %d\n", TMP_REGNO); - fprintf (asm_out_file, "__zero_reg__ = %d\n", ZERO_REGNO); + fprintf (asm_out_file, "__tmp_reg__ = %d\n", AVR_TMP_REGNO); + fprintf (asm_out_file, "__zero_reg__ = %d\n", AVR_ZERO_REGNO); } @@ -8951,6 +9655,18 @@ avr_adjust_reg_alloc_order (void) 0, 1, 32, 33, 34, 35 }; + static const int tiny_order_0[] = { + 20, 21, + 22, 23, + 24, 25, + 30, 31, + 26, 27, + 28, 29, + 19, 18, + 16, 17, + 32, 33, 34, 35, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + }; static const int order_1[] = { 18, 19, 20, 21, 22, 23, 24, 25, @@ -8960,6 +9676,17 @@ avr_adjust_reg_alloc_order (void) 0, 1, 32, 33, 34, 35 }; + static const int tiny_order_1[] = { + 22, 23, + 24, 25, + 30, 31, + 26, 27, + 28, 29, + 21, 20, 19, 18, + 16, 17, + 32, 33, 34, 35, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + }; static const int order_2[] = { 25, 24, 23, 22, 21, 20, 19, 18, @@ -8970,9 +9697,14 @@ avr_adjust_reg_alloc_order (void) 32, 33, 34, 35 }; - const int *order = (TARGET_ORDER_1 ? order_1 : - TARGET_ORDER_2 ? order_2 : - order_0); + /* + Select specific register allocation order. Tiny Core (attiny4/5/9/10/20/40) + devices has only 16 registers, so different allocation order should be used + */ + const int *order = (TARGET_ORDER_1 ? (AVR_TINY ? tiny_order_1 : order_1) : + TARGET_ORDER_2 ? (AVR_TINY ? tiny_order_0 : order_2) : + (AVR_TINY ? tiny_order_0 : order_0)); + for (i = 0; i < ARRAY_SIZE (order_0); ++i) reg_alloc_order[i] = order[i]; } @@ -10657,7 +11389,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) { if (!clear_p) avr_asm_len (ldreg_p ? "ldi %0,0" - : ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" + : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" : "mov %0,__zero_reg__", &xdest[n], len, 1); continue; @@ -10859,6 +11591,49 @@ avr_output_addr_vec_elt (FILE *stream, int value) fprintf (stream, "\trjmp .L%d\n", value); } +static void +avr_conditional_register_usage(void) { + + if (AVR_TINY) { + unsigned int i; + + const int tiny_reg_alloc_order[] = { + 24, 25, + 22, 23, + 30, 31, + 26, 27, + 28, 29, + 21, 20, 19, 18, + 16, 17, + 32, 33, 34, 35, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + }; + + /* Set R0-R17 as fixed registers. Reset R0-R17 in call used register list + - R0-R15 are not available in Tiny Core devices + - R16 and R17 are fixed registers + */ + for (i = 0; i <= 17; i++) { + fixed_regs[i] = 1; + call_used_regs[i] = 1; + } + + /* Set R18 to R21 as callee saved registers + - R18, R19, R20 and R21 are the callee saved registers in Tiny Core devices + */ + for (i = 18; i <= LAST_CALLEE_SAVED_REG; i++) { + call_used_regs[i] = 0; + } + + /*update register allocation order for Tiny Core devices */ + for (i=0; i < ARRAY_SIZE (tiny_reg_alloc_order); i++) { + reg_alloc_order[i] = tiny_reg_alloc_order[i]; + } + + CLEAR_HARD_REG_SET(reg_class_contents[(int)ADDW_REGS]); + CLEAR_HARD_REG_SET(reg_class_contents[(int)NO_LD_REGS]); + } +} /* Implement `TARGET_HARD_REGNO_SCRATCH_OK'. */ /* Returns true if SCRATCH are safe to be allocated as a scratch @@ -11013,13 +11788,20 @@ avr_asm_out_dtor (rtx symbol, int priority) static bool avr_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) { - if (TYPE_MODE (type) == BLKmode) - { - HOST_WIDE_INT size = int_size_in_bytes (type); - return (size == -1 || size > 8); - } + HOST_WIDE_INT size = int_size_in_bytes (type); + HOST_WIDE_INT ret_size_limit = AVR_TINY ? 4 : 8; + + /* In avr, there are 8 return registers. But, for Tiny Core + (attiny4/5/9/10/20/40) devices, only 4 registers available. + Return true if size is unknown or greater than the limit */ + if ((size == -1) || (size > ret_size_limit)) + { + return true; + } else + { return false; + } } @@ -12639,6 +13421,9 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, #undef TARGET_BUILTIN_SETJMP_FRAME_VALUE #define TARGET_BUILTIN_SETJMP_FRAME_VALUE avr_builtin_setjmp_frame_value +#undef TARGET_CONDITIONAL_REGISTER_USAGE +#define TARGET_CONDITIONAL_REGISTER_USAGE avr_conditional_register_usage + #undef TARGET_HARD_REGNO_SCRATCH_OK #define TARGET_HARD_REGNO_SCRATCH_OK avr_hard_regno_scratch_ok #undef TARGET_CASE_VALUES_THRESHOLD diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index de2bcd1..ba31cd0 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -63,6 +63,7 @@ enum #define AVR_HAVE_JMP_CALL (avr_current_arch->have_jmp_call) #define AVR_HAVE_MUL (avr_current_arch->have_mul) #define AVR_HAVE_MOVW (avr_current_arch->have_movw_lpmx) +#define AVR_HAVE_LPM (!AVR_TINY) #define AVR_HAVE_LPMX (avr_current_arch->have_movw_lpmx) #define AVR_HAVE_ELPM (avr_current_arch->have_elpm) #define AVR_HAVE_ELPMX (avr_current_arch->have_elpmx) @@ -99,6 +100,7 @@ FIXME: DRIVER_SELF_SPECS has changed. #define AVR_3_BYTE_PC (AVR_HAVE_EIJMP_EICALL) #define AVR_XMEGA (avr_current_arch->xmega_p) +#define AVR_TINY (avr_current_arch->tiny_p) #define BITS_BIG_ENDIAN 0 #define BYTES_BIG_ENDIAN 0 @@ -305,7 +307,7 @@ enum reg_class { #define ARG_POINTER_REGNUM 34 -#define STATIC_CHAIN_REGNUM 2 +#define STATIC_CHAIN_REGNUM ((AVR_TINY) ? 18 :2) #define ELIMINABLE_REGS { \ {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 3f3d6eb..06e1cb0 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -24,6 +24,10 @@ ;; B Add 1 to REG number, MEM address or CONST_INT. ;; C Add 2. ;; D Add 3. +;; E reg number in XEXP(x, 0). +;; F Add 1 to reg number. +;; I reg number in XEXP(XEXP(x, 0), 0). +;; J Add 1 to reg number. ;; j Branch condition. ;; k Reverse branch condition. ;;..m..Constant Direct Data memory address. @@ -59,6 +63,11 @@ (ZERO_REGNO 1) ; zero register r1 ]) +(define_constants + [ (TMP_REGNO_TINY 16) ; r16 is temp register for AVR_TINY + (ZERO_REGNO_TINY 17) ; r17 is zero register for AVR_TINY + ]) + (define_c_enum "unspec" [UNSPEC_STRLEN UNSPEC_MOVMEM @@ -159,9 +168,10 @@ ;; lpm : ISA has no LPMX lpmx : ISA has LPMX ;; elpm : ISA has ELPM but no ELPMX elpmx : ISA has ELPMX ;; no_xmega: non-XMEGA core xmega : XMEGA core +;; no_tiny: non-TINY core tiny : TINY core (define_attr "isa" - "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega, + "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega, no_tiny,tiny, standard" (const_string "standard")) @@ -213,9 +223,18 @@ (match_test "AVR_XMEGA")) (const_int 1) + (and (eq_attr "isa" "tiny") + (match_test "AVR_TINY")) + (const_int 1) + (and (eq_attr "isa" "no_xmega") (match_test "!AVR_XMEGA")) (const_int 1) + + (and (eq_attr "isa" "no_tiny") + (match_test "!AVR_TINY")) + (const_int 1) + ] (const_int 0))) @@ -620,6 +639,33 @@ emit_insn (gen_load<mode>_libgcc (dest, src)); DONE; } + + /* AVRTC-579 + if the source operand expression is out of range for 'lds' instruction + copy source operand expression to register + For tiny core, LDS instruction's memory access range limited to 0x40..0xbf + */ + if (!tiny_valid_direct_memory_access_range(src,<MODE>mode)) + { + rtx srcx = XEXP(src,0); + operands[1] = src = replace_equiv_address (src,copy_to_mode_reg (GET_MODE(srcx),srcx)); + emit_move_insn(dest,src); + DONE; + } + + /* AVRTC-579 + if the destination operand expression is out of range for 'sts' instruction + copy destination operand expression to register + For tiny core, STS instruction's memory access range limited to 0x40..0xbf + */ + if (!tiny_valid_direct_memory_access_range(dest,<MODE>mode)) + { + rtx destx = XEXP(dest,0); + operands[0] = dest = replace_equiv_address (dest,copy_to_mode_reg (GET_MODE(destx),destx)); + emit_move_insn(dest,src); + DONE; + } + }) ;;======================================================================== @@ -636,8 +682,13 @@ (define_insn "mov<mode>_insn" [(set (match_operand:ALL1 0 "nonimmediate_operand" "=r ,d ,Qm ,r ,q,r,*r") (match_operand:ALL1 1 "nox_general_operand" "r Y00,n Ynn,r Y00,Qm,r,q,i"))] - "register_operand (operands[0], <MODE>mode) - || reg_or_0_operand (operands[1], <MODE>mode)" + "(register_operand (operands[0], <MODE>mode) + || reg_or_0_operand (operands[1], <MODE>mode)) && + /* skip if operands are out of lds/sts memory access range(0x40..0xbf) + though access range is checked during define_expand, it is required + here to avoid merging rtls during combine pass */ + tiny_valid_direct_memory_access_range(operands[0],QImode) && + tiny_valid_direct_memory_access_range(operands[1],QImode)" { return output_movqi (insn, operands, NULL); } @@ -730,8 +781,13 @@ (define_insn "*mov<mode>" [(set (match_operand:ALL2 0 "nonimmediate_operand" "=r,r ,r,m ,d,*r,q,r") (match_operand:ALL2 1 "nox_general_operand" "r,Y00,m,r Y00,i,i ,r,q"))] - "register_operand (operands[0], <MODE>mode) - || reg_or_0_operand (operands[1], <MODE>mode)" + "(register_operand (operands[0], <MODE>mode) + || reg_or_0_operand (operands[1], <MODE>mode)) && + /* skip if operands are out of lds/sts memory access range(0x40..0xbf) + though access range is checked during define_expand, it is required + here to avoid merging rtls during combine pass */ + tiny_valid_direct_memory_access_range(operands[0],HImode) && + tiny_valid_direct_memory_access_range(operands[1],HImode)" { return output_movhi (insn, operands, NULL); } @@ -879,8 +935,13 @@ (define_insn "*mov<mode>" [(set (match_operand:ALL4 0 "nonimmediate_operand" "=r,r ,r ,Qm ,!d,r") (match_operand:ALL4 1 "nox_general_operand" "r,Y00,Qm,r Y00,i ,i"))] - "register_operand (operands[0], <MODE>mode) - || reg_or_0_operand (operands[1], <MODE>mode)" + "(register_operand (operands[0], <MODE>mode) + || reg_or_0_operand (operands[1], <MODE>mode)) && + /* skip if operands are out of lds/sts memory access range(0x40..0xbf) + though access range is checked during define_expand, it is required + here to avoid merging rtls during combine pass */ + tiny_valid_direct_memory_access_range(operands[0],SImode) && + tiny_valid_direct_memory_access_range(operands[1],SImode)" { return output_movsisf (insn, operands, NULL); } @@ -894,8 +955,13 @@ (define_insn "*movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r") (match_operand:SF 1 "nox_general_operand" "r,G,Qm,rG,F ,F"))] - "register_operand (operands[0], SFmode) - || reg_or_0_operand (operands[1], SFmode)" + "(register_operand (operands[0], SFmode) + || reg_or_0_operand (operands[1], SFmode)) && + /* skip if operands are out of lds/sts memory access range(0x40..0xbf) + though access range is checked during define_expand, it is required + here to avoid merging rtls during combine pass */ + tiny_valid_direct_memory_access_range(operands[0],SFmode) && + tiny_valid_direct_memory_access_range(operands[1],SFmode)" { return output_movsisf (insn, operands, NULL); } @@ -5551,18 +5617,18 @@ (set_attr "cc" "clobber")]) (define_insn "delay_cycles_2" - [(unspec_volatile [(match_operand:HI 0 "const_int_operand" "n") + [(unspec_volatile [(match_operand:HI 0 "const_int_operand" "n,n") (const_int 2)] UNSPECV_DELAY_CYCLES) (set (match_operand:BLK 1 "" "") (unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER)) - (clobber (match_scratch:HI 2 "=&w"))] + (clobber (match_scratch:HI 2 "=&w,&d"))] "" - "ldi %A2,lo8(%0) - ldi %B2,hi8(%0) - 1: sbiw %A2,1 - brne 1b" - [(set_attr "length" "4") + "@ + ldi %A2,lo8(%0)\;ldi %B2,hi8(%0)\;1: sbiw %A2,1\;brne 1b + ldi %A2,lo8(%0)\;ldi %B2,hi8(%0)\;1: subi %A2,1\;sbci %B2,0\;brne 1b" + [(set_attr "length" "4,5") + (set_attr "isa" "no_tiny,tiny") (set_attr "cc" "clobber")]) (define_insn "delay_cycles_3" diff --git a/gcc/config/avr/t-multilib b/gcc/config/avr/t-multilib index 9aee17b..89d0036 100644 --- a/gcc/config/avr/t-multilib +++ b/gcc/config/avr/t-multilib @@ -21,9 +21,9 @@ # along with GCC; see the file COPYING3. If not see # <http://www.gnu.org/licenses/>. -MULTILIB_OPTIONS = march=avr2/march=avr25/march=avr3/march=avr31/march=avr35/march=avr4/march=avr5/march=avr51/march=avr6/march=avrxmega2/march=avrxmega4/march=avrxmega5/march=avrxmega6/march=avrxmega7 msp8 +MULTILIB_OPTIONS = march=avr2/march=avr25/march=avr3/march=avr31/march=avr35/march=avr4/march=avr5/march=avr51/march=avr6/march=avrxmega2/march=avrxmega4/march=avrxmega5/march=avrxmega6/march=avrxmega7/march=avrtiny msp8 -MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack avr25/tiny-stack +MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 avrtiny tiny-stack avr25/tiny-stack MULTILIB_EXCEPTIONS = \ march=avr3/msp8 \ @@ -37,4 +37,5 @@ MULTILIB_EXCEPTIONS = \ march=avrxmega4/msp8 \ march=avrxmega5/msp8 \ march=avrxmega6/msp8 \ - march=avrxmega7/msp8 + march=avrxmega7/msp8 \ + march=avrtiny/msp8 |