From: Marek Michalkiewicz Date: Mon, 3 Jul 2000 16:51:38 +0000 (+0200) Subject: avr.c (out_adj_frame_ptr): Make "frame pointer change too big for -mtiny-stack" a... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c4984bad36ef142b95331ca1552b7498fa78f019;p=platform%2Fupstream%2Fgcc.git avr.c (out_adj_frame_ptr): Make "frame pointer change too big for -mtiny-stack" a warning, if larger than 63. * config/avr/avr.c (out_adj_frame_ptr): Make "frame pointer change too big for -mtiny-stack" a warning, if larger than 63. (out_set_stack_ptr): Change the logic so -mno-interrupts is always safe to use on possible future devices. (function_prologue): Write SPH before SPL, for consistency. If interrupt_func_p true, we know we have enabled interrupts. (avr_num_arg_regs): New function. Round up to even number of bytes if no -mpack-args or if calling a libgcc function. (function_arg, function_arg_advance): Use it. (output_movsisf, ashlsi3_out, ashrsi3_out, lshrsi3_out): Output "movw" if available. (out_tsthi, out_tstsi, ashlqi3_out, lshrqi3_out): Change uses of TEST_HARD_REG_CLASS macro to test_hard_reg_class function. (asm_output_section_name): Add blanks for consistent output. (encode_section_info): Set TREE_READONLY for progmem data to avoid gas warnings about changed section attributes. (avr_hard_regno_mode_ok): Force non-QImode data to start in even numbered registers on devices with "movw". * config/avr/avr.h (MASK_*): Define bits for target_flags. (TARGET_SWITCHES): Mark help strings for translation. Add new -mpack-args and -menhanced switches. (TARGET_OPTIONS): Mark help strings for translation. (progmem_section): Add section attributes. * config/avr/avr.md (*movhi, call_insn, call_value_insn): Output "movw" if available. (mulqi3, mulqihi3, umulqihi3, mulhi3, *tablejump_enh): New patterns. * config/avr/libgcc.S (_mulqi3, _divqi3): Update to the new call convention (arguments aligned on even registers). (_cleanup, _exit): Make weak symbols libc can override. From-SVN: r34847 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 04e7c14..b046a72 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,36 @@ +2000-07-01 Marek Michalkiewicz + + * config/avr/avr.c (out_adj_frame_ptr): Make "frame pointer + change too big for -mtiny-stack" a warning, if larger than 63. + (out_set_stack_ptr): Change the logic so -mno-interrupts is + always safe to use on possible future devices. + (function_prologue): Write SPH before SPL, for consistency. + If interrupt_func_p true, we know we have enabled interrupts. + (avr_num_arg_regs): New function. Round up to even number of + bytes if no -mpack-args or if calling a libgcc function. + (function_arg, function_arg_advance): Use it. + (output_movsisf, ashlsi3_out, ashrsi3_out, lshrsi3_out): + Output "movw" if available. + (out_tsthi, out_tstsi, ashlqi3_out, lshrqi3_out): Change uses + of TEST_HARD_REG_CLASS macro to test_hard_reg_class function. + (asm_output_section_name): Add blanks for consistent output. + (encode_section_info): Set TREE_READONLY for progmem data to + avoid gas warnings about changed section attributes. + (avr_hard_regno_mode_ok): Force non-QImode data to start in + even numbered registers on devices with "movw". + * config/avr/avr.h (MASK_*): Define bits for target_flags. + (TARGET_SWITCHES): Mark help strings for translation. + Add new -mpack-args and -menhanced switches. + (TARGET_OPTIONS): Mark help strings for translation. + (progmem_section): Add section attributes. + * config/avr/avr.md (*movhi, call_insn, call_value_insn): + Output "movw" if available. + (mulqi3, mulqihi3, umulqihi3, mulhi3, *tablejump_enh): + New patterns. + * config/avr/libgcc.S (_mulqi3, _divqi3): Update to the new + call convention (arguments aligned on even registers). + (_cleanup, _exit): Make weak symbols libc can override. + 2000-07-03 Kaveh R. Ghazi * fp-bit.h: New file. diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 4e58c72..ac07707 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -49,6 +49,7 @@ static int signal_function_p PARAMS ((tree)); static int sequent_regs_live PARAMS ((void)); static char * ptrreg_to_str PARAMS ((int)); static char * cond_string PARAMS ((enum rtx_code)); +static int avr_num_arg_regs PARAMS ((enum machine_mode, tree)); static int out_adj_frame_ptr PARAMS ((FILE *, int)); static int out_set_stack_ptr PARAMS ((FILE *, int, int)); @@ -347,30 +348,23 @@ out_adj_frame_ptr (file, adj) if (adj) { - /* For -mtiny-stack, the high byte (r29) does not change - - prefer "subi" (1 cycle) over "sbiw" (2 cycles). */ - - if (adj < -63 || adj > 63 || TARGET_TINY_STACK) + if (TARGET_TINY_STACK) { - fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB), adj); - size++; + if (adj < -63 || adj > 63) + warning ("large frame pointer change (%d) with -mtiny-stack", adj); - if (TARGET_TINY_STACK) - { - /* In addition to any local data, each level of function calls - needs at least 4 more bytes of stack space for the saved - frame pointer and return address. So, (255 - 16) leaves - room for 4 levels of function calls. */ - - if (adj < -(255 - 16) || adj > (255 - 16)) - fatal ("Frame pointer change (%d) too big for -mtiny-stack", - adj); - } - else - { - fprintf (file, (AS2 (sbci, r29, hi8(%d)) CR_TAB), adj); - size++; - } + /* The high byte (r29) doesn't change - prefer "subi" (1 cycle) + over "sbiw" (2 cycles, same size). */ + + fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj); + size++; + } + else if (adj < -63 || adj > 63) + { + fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB + AS2 (sbci, r29, hi8(%d)) CR_TAB), + adj, adj); + size += 2; } else if (adj < 0) { @@ -398,17 +392,18 @@ out_set_stack_ptr (file, before, after) int before; int after; { - int do_sph, do_cli, do_save, size; + int do_sph, do_cli, do_save, do_sei, lock_sph, size; - if (TARGET_NO_INTERRUPTS) - { - before = 0; - after = 0; - } + /* The logic here is so that -mno-interrupts actually means + "it is safe to write SPH in one instruction, then SPL in the + next instruction, without disabling interrupts first". + The after != -1 case (interrupt/signal) is not affected. */ do_sph = !TARGET_TINY_STACK; - do_cli = (before != 0 && (after == 0 || do_sph)); - do_save = (before == -1 && after == -1 && do_cli); + lock_sph = do_sph && !TARGET_NO_INTERRUPTS; + do_cli = (before != 0 && (after == 0 || lock_sph)); + do_save = (do_cli && before == -1 && after == -1); + do_sei = ((do_cli || before != 1) && after == 1); size = 1; if (do_save) @@ -424,8 +419,8 @@ out_set_stack_ptr (file, before, after) } /* Do SPH first - maybe this will disable interrupts for one instruction - someday, much like x86 does when changing SS (a suggestion has been - sent to avr@atmel.com for consideration in future devices). */ + someday (a suggestion has been sent to avr@atmel.com for consideration + in future devices - that would make -mno-interrupts always safe). */ if (do_sph) { fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB); @@ -440,7 +435,7 @@ out_set_stack_ptr (file, before, after) fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB); size++; } - else if (after == 1 && (before != 1 || do_cli)) + else if (do_sei) { fprintf (file, "sei" CR_TAB); size++; @@ -503,8 +498,8 @@ function_prologue (FILE *file, int size) fprintf (file, ("\t" AS2 (ldi, r28, lo8(%s - %d)) CR_TAB AS2 (ldi, r29, hi8(%s - %d)) CR_TAB - AS2 (out,__SP_L__,r28) CR_TAB - AS2 (out,__SP_H__,r29) "\n"), + AS2 (out, __SP_H__, r29) CR_TAB + AS2 (out, __SP_L__, r28) "\n"), initial_stack, size, initial_stack, size); prologue_size += 4; @@ -569,7 +564,7 @@ function_prologue (FILE *file, int size) if (interrupt_func_p) { - prologue_size += out_set_stack_ptr (file, -1, 1); + prologue_size += out_set_stack_ptr (file, 1, 1); } else if (signal_func_p) { @@ -1288,6 +1283,33 @@ init_cumulative_args (cum, fntype, libname, indirect) } } +/* Returns the number of registers to allocate for a function argument. */ + +static int +avr_num_arg_regs (mode, type) + enum machine_mode mode; + tree type; +{ + int size; + + if (mode == BLKmode) + size = int_size_in_bytes (type); + else + size = GET_MODE_SIZE (mode); + + /* Align all function arguments to start in even-numbered registers, + for "movw" on the enhanced core (to keep call conventions the same + on all devices, do it even if "movw" is not available). Odd-sized + arguments leave holes above them - registers still available for + other uses. Use -mpack-args for compatibility with old asm code + (the new convention will still be used for libgcc calls). */ + + if (!(type && TARGET_PACK_ARGS)) + size += size & 1; + + return size; +} + /* Controls whether a function argument is passed in a register, and which register. */ @@ -1298,12 +1320,11 @@ function_arg (cum, mode, type, named) tree type; int named ATTRIBUTE_UNUSED; { - int bytes; - - bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + int bytes = avr_num_arg_regs (mode, type); if (cum->nregs && bytes <= cum->nregs) return gen_rtx (REG, mode, cum->regno - bytes); + return NULL_RTX; } @@ -1317,9 +1338,8 @@ function_arg_advance (cum, mode, type, named) tree type; /* type of the argument or 0 if lib support */ int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */ { - int bytes; + int bytes = avr_num_arg_regs (mode, type); - bytes = (mode == BLKmode ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); cum->nregs -= bytes; cum->regno -= bytes; @@ -1328,8 +1348,6 @@ function_arg_advance (cum, mode, type, named) cum->nregs = 0; cum->regno = FIRST_CUM_REG; } - - return; } /*********************************************************************** @@ -1788,16 +1806,33 @@ output_movsisf(insn, operands, which_alternative) { case 0: /* mov r,r */ if (true_regnum (operands[0]) > true_regnum (operands[1])) - return (AS2 (mov,%D0,%D1) CR_TAB - AS2 (mov,%C0,%C1) CR_TAB - AS2 (mov,%B0,%B1) CR_TAB - AS2 (mov,%A0,%A1)); + { + if (TARGET_ENHANCED) + return (AS2 (movw,%C0,%C1) CR_TAB + AS2 (movw,%A0,%A1)); /* FIXME: length = 4 -> 2 */ + else + return (AS2 (mov,%D0,%D1) CR_TAB + AS2 (mov,%C0,%C1) CR_TAB + AS2 (mov,%B0,%B1) CR_TAB + AS2 (mov,%A0,%A1)); + } else - return (AS2 (mov,%A0,%A1) CR_TAB - AS2 (mov,%B0,%B1) CR_TAB - AS2 (mov,%C0,%C1) CR_TAB - AS2 (mov,%D0,%D1)); + { + if (TARGET_ENHANCED) + return (AS2 (movw,%A0,%A1) CR_TAB + AS2 (movw,%C0,%C1)); /* FIXME: length = 4 -> 2 */ + else + return (AS2 (mov,%A0,%A1) CR_TAB + AS2 (mov,%B0,%B1) CR_TAB + AS2 (mov,%C0,%C1) CR_TAB + AS2 (mov,%D0,%D1)); + } case 1: /* mov r,L */ + if (TARGET_ENHANCED) + return (AS1 (clr,%A0) CR_TAB + AS1 (clr,%B0) CR_TAB + AS2 (movw,%C0,%A0)); /* FIXME: length = 4 -> 3 */ + return (AS1 (clr,%A0) CR_TAB AS1 (clr,%B0) CR_TAB AS1 (clr,%C0) CR_TAB @@ -2052,7 +2087,7 @@ out_tsthi (insn,l) if (l) *l = 1; return AS1 (tst,%B0); } - if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn))))) + if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn)))) { if (l) *l = 1; return AS2 (sbiw,%0,0); @@ -2080,7 +2115,7 @@ out_tstsi (insn,l) if (l) *l = 1; return AS1 (tst,%D0); } - if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn))))) + if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn)))) { if (l) *l = 3; return (AS2 (sbiw,%A0,0) CR_TAB @@ -2142,7 +2177,7 @@ out_shift_with_cnt (template,insn,operands,len) *len = mov_len + 1; } } - else if (register_operand (operands[2],QImode)) + else if (register_operand (operands[2], QImode)) { if (reg_unused_after (insn, operands[2])) op[3] = op[2]; @@ -2211,7 +2246,7 @@ ashlqi3_out (insn,operands,len) AS1 (lsl,%0)); case 4: - if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0]))) + if (test_hard_reg_class (LD_REGS, operands[0])) { *len = 2; return (AS1 (swap,%0) CR_TAB @@ -2224,7 +2259,7 @@ ashlqi3_out (insn,operands,len) AS1 (lsl,%0)); case 5: - if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0]))) + if (test_hard_reg_class (LD_REGS, operands[0])) { *len = 3; return (AS1 (swap,%0) CR_TAB @@ -2239,7 +2274,7 @@ ashlqi3_out (insn,operands,len) AS1 (lsl,%0)); case 6: - if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0]))) + if (test_hard_reg_class (LD_REGS, operands[0])) { *len = 4; return (AS1 (swap,%0) CR_TAB @@ -2376,6 +2411,13 @@ ashlsi3_out (insn,operands,len) int reg0 = true_regnum (operands[0]); int reg1 = true_regnum (operands[1]); *len = 4; + if (TARGET_ENHANCED && (reg0 + 2 != reg1)) + { + *len = 3; + return (AS2 (movw,%C0,%A1) CR_TAB + AS1 (clr,%B0) CR_TAB + AS1 (clr,%A0)); + } if (reg0 + 1 >= reg1) return (AS2 (mov,%D0,%B1) CR_TAB AS2 (mov,%C0,%A1) CR_TAB @@ -2610,6 +2652,15 @@ ashrsi3_out (insn,operands,len) int reg0 = true_regnum (operands[0]); int reg1 = true_regnum (operands[1]); *len=6; + if (TARGET_ENHANCED && (reg0 != reg1 + 2)) + { + *len = 5; + return (AS2 (movw,%A0,%C1) CR_TAB + AS1 (clr,%D0) CR_TAB + AS2 (sbrc,%B0,7) CR_TAB + AS1 (com,%D0) CR_TAB + AS2 (mov,%C0,%D0)); + } if (reg0 <= reg1 + 1) return (AS2 (mov,%A0,%C1) CR_TAB AS2 (mov,%B0,%D1) CR_TAB @@ -2693,7 +2744,7 @@ lshrqi3_out (insn,operands,len) AS1 (lsr,%0)); case 4: - if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0]))) + if (test_hard_reg_class (LD_REGS, operands[0])) { *len=2; return (AS1 (swap,%0) CR_TAB @@ -2706,7 +2757,7 @@ lshrqi3_out (insn,operands,len) AS1 (lsr,%0)); case 5: - if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0]))) + if (test_hard_reg_class (LD_REGS, operands[0])) { *len = 3; return (AS1 (swap,%0) CR_TAB @@ -2721,7 +2772,7 @@ lshrqi3_out (insn,operands,len) AS1 (lsr,%0)); case 6: - if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0]))) + if (test_hard_reg_class (LD_REGS, operands[0])) { *len = 4; return (AS1 (swap,%0) CR_TAB @@ -2860,6 +2911,13 @@ lshrsi3_out (insn,operands,len) int reg0 = true_regnum (operands[0]); int reg1 = true_regnum (operands[1]); *len = 4; + if (TARGET_ENHANCED && (reg0 != reg1 + 2)) + { + *len = 3; + return (AS2 (movw,%A0,%C1) CR_TAB + AS1 (clr,%C0) CR_TAB + AS1 (clr,%D0)); + } if (reg0 <= reg1 + 1) return (AS2 (mov,%A0,%C1) CR_TAB AS2 (mov,%B0,%D1) CR_TAB @@ -3275,7 +3333,7 @@ asm_output_section_name(file, decl, name, reloc) const char *name; int reloc ATTRIBUTE_UNUSED; { - fprintf (file, ".section\t%s,\"%s\",@progbits\n", name, \ + fprintf (file, ".section %s, \"%s\", @progbits\n", name, decl && TREE_CODE (decl) == FUNCTION_DECL ? "ax" : decl && TREE_READONLY (decl) ? "a" : "aw"); } @@ -3407,9 +3465,9 @@ valid_machine_type_attribute(type, attributes, identifier, args) Valid attributes: progmem - put data to program memory; signal - make a function to be hardware interrupt. After function - epilogue interrupts are disabled; + prologue interrupts are disabled; interrupt - make a function to be hardware interrupt. After function - epilogue interrupts are enabled; + prologue interrupts are enabled; naked - don't generate function prologue/epilogue and `ret' command. */ int @@ -3440,7 +3498,7 @@ valid_machine_decl_attribute (decl, attributes, attr, args) /* Look for attribute `progmem' in DECL - founded - 1 otherwise 0 */ + if found return 1, otherwise 0. */ int avr_progmem_p (decl) @@ -3481,6 +3539,7 @@ encode_section_info (decl) { char * dsec = ".progmem.data"; DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec); + TREE_READONLY (decl) = 1; } } @@ -3864,7 +3923,7 @@ avr_function_value (type,func) return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs); } -/* Returns non-zero if number MASK have only one setted bit */ +/* Returns non-zero if the number MASK has only one bit set. */ int mask_one_bit_p (mask) @@ -3892,7 +3951,7 @@ mask_one_bit_p (mask) in class CLASS. */ enum reg_class -preferred_reload_class(x,class) +preferred_reload_class (x, class) rtx x; enum reg_class class; { @@ -3908,7 +3967,7 @@ preferred_reload_class(x,class) } int -test_hard_reg_class(class, x) +test_hard_reg_class (class, x) enum reg_class class; rtx x; { @@ -3946,9 +4005,9 @@ jump_over_one_insn_p (insn, dest) } /* Returns 1 if a value of mode MODE can be stored starting with hard - register number REGNO. On the enhanced core, it should be a win to - align modes larger than QI on even register numbers (even if < 24). - so that the "movw" instruction can be used on them. */ + register number REGNO. On the enhanced core, anything larger than + 1 byte must start in even numbered register for "movw" to work + (this way we don't have to check for odd registers everywhere). */ int avr_hard_regno_mode_ok (regno, mode) @@ -3957,7 +4016,7 @@ avr_hard_regno_mode_ok (regno, mode) { if (mode == QImode) return 1; - if (regno < 24 /* && !TARGET_ENHANCED */ ) + if (regno < 24 && !TARGET_ENHANCED) return 1; return !(regno & 1); } diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 4d2451e..1d8d100 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -249,6 +249,9 @@ switch (which_alternative) { case 0: /* mov r,r */ + if (TARGET_ENHANCED) + return (AS2 (movw,%0,%1)); /* FIXME: length = 2 -> 1 */ + if (true_regnum (operands[0]) > true_regnum (operands[1])) return (AS2 (mov,%B0,%B1) CR_TAB AS2 (mov,%A0,%A1)); @@ -653,6 +656,57 @@ [(set_attr "length" "4,4") (set_attr "cc" "set_czn,set_czn")]) +;****************************************************************************** +; mul + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (mult:QI (match_operand:QI 1 "register_operand" "r") + (match_operand:QI 2 "register_operand" "r")))] + "TARGET_ENHANCED" + "mul %1,%2 + mov %0,r0 + clr r1" + [(set_attr "length" "3") + (set_attr "cc" "clobber")]) + +(define_insn "mulqihi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d")) + (sign_extend:HI (match_operand:QI 2 "register_operand" "d"))))] + "TARGET_ENHANCED" + "muls %1,%2 + movw %0,r0 + clr r1" + [(set_attr "length" "3") + (set_attr "cc" "clobber")]) + +(define_insn "umulqihi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r")) + (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))] + "TARGET_ENHANCED" + "mul %1,%2 + movw %0,r0 + clr r1" + [(set_attr "length" "3") + (set_attr "cc" "clobber")]) + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "register_operand" "=&r") + (mult:HI (match_operand:HI 1 "register_operand" "r") + (match_operand:HI 2 "register_operand" "r")))] + "TARGET_ENHANCED" + "mul %A1,%A2 + movw %0,r0 + mul %A1,%B2 + add %B0,r0 + mul %B1,%A2 + add %B0,r0 + clr r1" + [(set_attr "length" "7") + (set_attr "cc" "clobber")]) + ;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ; and @@ -1604,9 +1658,15 @@ if (which_alternative==0) return \"icall\"; else if (which_alternative==1) - return (AS2 (mov, r30,%A0) CR_TAB - AS2 (mov, r31,%B0) CR_TAB - \"icall\"); + { + if (TARGET_ENHANCED) + return (AS2 (movw, r30, %0) CR_TAB + \"icall\"); + else + return (AS2 (mov, r30, %A0) CR_TAB + AS2 (mov, r31, %B0) CR_TAB + \"icall\"); + } else if (!AVR_MEGA) return AS1(rcall,%c0); return AS1(call,%c0); @@ -1634,9 +1694,15 @@ if (which_alternative==0) return \"icall\"; else if (which_alternative==1) - return (AS2 (mov, r30,%A1) CR_TAB - AS2 (mov, r31,%B1) CR_TAB - \"icall\"); + { + if (TARGET_ENHANCED) + return (AS2 (movw, r30, %1) CR_TAB + \"icall\"); + else + return (AS2 (mov, r30, %A1) CR_TAB + AS2 (mov, r31, %B1) CR_TAB + \"icall\"); + } else if (!AVR_MEGA) return AS1(rcall,%c1); return AS1(call,%c1); @@ -1676,6 +1742,21 @@ "optimize" "") +(define_insn "*tablejump_enh" + [(set (pc) (mem:HI + (plus:HI (match_operand:HI 0 "register_operand" "=&z") + (label_ref (match_operand 2 "" ""))))) + (use (label_ref (match_operand 1 "" "")))] + "TARGET_ENHANCED" + "subi r30,lo8(-(%2)) + sbci r31,hi8(-(%2)) + lpm __tmp_reg__,Z+ + lpm r31,Z + mov r30,__tmp_reg__ + ijmp" + [(set_attr "length" "6") + (set_attr "cc" "clobber")]) + (define_insn "*tablejump" [(set (pc) (mem:HI (plus:HI (match_operand:HI 0 "register_operand" "=&z") @@ -1686,10 +1767,10 @@ sbci r31,hi8(-(%2)) lpm push r0 - adiw r30,1 + adiw r30,1 lpm push r0 - ret" + ret" [(set_attr "length" "8") (set_attr "cc" "clobber")]) diff --git a/gcc/config/avr/libgcc.S b/gcc/config/avr/libgcc.S index 00aa50b..e5ecbff 100644 --- a/gcc/config/avr/libgcc.S +++ b/gcc/config/avr/libgcc.S @@ -39,7 +39,7 @@ Boston, MA 02111-1307, USA. */ *******************************************************/ #if defined (Lmulqi3) -#define r_arg2 r25 /* multiplicand */ +#define r_arg2 r22 /* multiplicand */ #define r_arg1 r24 /* multiplier */ #define r_res __tmp_reg__ /* result */ @@ -201,8 +201,8 @@ __mulsi3_exit: Division 8 / 8 => (result + remainder) *******************************************************/ #define r_rem r26 /* remainder */ -#define r_arg1 r25 /* dividend */ -#define r_arg2 r24 /* divisor */ +#define r_arg1 r24 /* dividend */ +#define r_arg2 r22 /* divisor */ #define r_cnt r27 /* loop count */ #if defined (Lumodqi3) @@ -272,8 +272,7 @@ __divqi3_1: sbrc __tmp_reg__,7 neg r_arg1 ; correct result sign __divqi3_exit: - mov r24,r_arg1 ; put result to return register - ret + ret ; result already in r24 (r_arg1) .endfunc #endif /* defined (Ldivqi3) */ @@ -434,8 +433,6 @@ _umodsi3_ret: mov r24,r_remHL mov r23,r_remH mov r22,r_remL - .global _cleanup -_cleanup: ret .endfunc #endif /* defined (Lumodsi3) */ @@ -630,9 +627,12 @@ __epilogue_restores__: #endif /* defined (Lepilogue) */ #ifdef L__exit - .global _exit + .weak _exit .func _exit _exit: rjmp _exit + .weak _cleanup +_cleanup: + ret .endfunc #endif