This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
avr port: support `movw', call convention changed, etc
- To: gcc-patches at gcc dot gnu dot org
- Subject: avr port: support `movw', call convention changed, etc
- From: Denis Chertykov <denisc at overta dot ru>
- Date: Mon, 3 Jul 2000 20:47:42 +0400
2000-07-01 Marek Michalkiewicz <marekm@linux.org.pl>
* 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.
diff -Nrc3p orig/egcs/gcc/config/avr/avr.c egcs/gcc/config/avr/avr.c
*** orig/egcs/gcc/config/avr/avr.c Sat Jun 24 20:33:48 2000
--- egcs/gcc/config/avr/avr.c Sat Jul 1 14:42:38 2000
*************** static int signal_function_p PARAM
*** 49,54 ****
--- 49,55 ----
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));
*************** out_adj_frame_ptr (file, adj)
*** 347,376 ****
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)
{
! fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB), adj);
! size++;
! 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++;
! }
}
else if (adj < 0)
{
--- 348,370 ----
if (adj)
{
! if (TARGET_TINY_STACK)
{
! if (adj < -63 || adj > 63)
! warning ("large frame pointer change (%d) with -mtiny-stack", adj);
! /* 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)
{
*************** out_set_stack_ptr (file, before, after)
*** 398,414 ****
int before;
int after;
{
! int do_sph, do_cli, do_save, size;
! if (TARGET_NO_INTERRUPTS)
! {
! before = 0;
! after = 0;
! }
do_sph = !TARGET_TINY_STACK;
! do_cli = (before != 0 && (after == 0 || do_sph));
! do_save = (before == -1 && after == -1 && do_cli);
size = 1;
if (do_save)
--- 392,409 ----
int before;
int after;
{
! int do_sph, do_cli, do_save, do_sei, lock_sph, size;
! /* 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;
! 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)
*************** out_set_stack_ptr (file, before, after)
*** 424,431 ****
}
/* 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). */
if (do_sph)
{
fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
--- 419,426 ----
}
/* Do SPH first - maybe this will disable interrupts for one instruction
! 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);
*************** out_set_stack_ptr (file, before, after)
*** 440,446 ****
fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
size++;
}
! else if (after == 1 && (before != 1 || do_cli))
{
fprintf (file, "sei" CR_TAB);
size++;
--- 435,441 ----
fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
size++;
}
! else if (do_sei)
{
fprintf (file, "sei" CR_TAB);
size++;
*************** function_prologue (FILE *file, int size)
*** 503,510 ****
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"),
initial_stack, size, initial_stack, size);
prologue_size += 4;
--- 498,505 ----
fprintf (file, ("\t"
AS2 (ldi, r28, lo8(%s - %d)) CR_TAB
AS2 (ldi, r29, hi8(%s - %d)) CR_TAB
! AS2 (out, __SP_H__, r29) CR_TAB
! AS2 (out, __SP_L__, r28) "\n"),
initial_stack, size, initial_stack, size);
prologue_size += 4;
*************** function_prologue (FILE *file, int size)
*** 569,575 ****
if (interrupt_func_p)
{
! prologue_size += out_set_stack_ptr (file, -1, 1);
}
else if (signal_func_p)
{
--- 564,570 ----
if (interrupt_func_p)
{
! prologue_size += out_set_stack_ptr (file, 1, 1);
}
else if (signal_func_p)
{
*************** init_cumulative_args (cum, fntype, libna
*** 1288,1293 ****
--- 1283,1315 ----
}
}
+ /* 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. */
*************** function_arg (cum, mode, type, named)
*** 1298,1309 ****
tree type;
int named ATTRIBUTE_UNUSED;
{
! int bytes;
!
! bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
if (cum->nregs && bytes <= cum->nregs)
return gen_rtx (REG, mode, cum->regno - bytes);
return NULL_RTX;
}
--- 1320,1330 ----
tree type;
int named ATTRIBUTE_UNUSED;
{
! 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;
}
*************** function_arg_advance (cum, mode, type, n
*** 1317,1325 ****
tree type; /* type of the argument or 0 if lib support */
int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */
{
! int bytes;
- bytes = (mode == BLKmode ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
cum->nregs -= bytes;
cum->regno -= bytes;
--- 1338,1345 ----
tree type; /* type of the argument or 0 if lib support */
int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */
{
! int bytes = avr_num_arg_regs (mode, type);
cum->nregs -= bytes;
cum->regno -= bytes;
*************** function_arg_advance (cum, mode, type, n
*** 1328,1335 ****
cum->nregs = 0;
cum->regno = FIRST_CUM_REG;
}
-
- return;
}
/***********************************************************************
--- 1348,1353 ----
*************** output_movsisf(insn, operands, which_alt
*** 1788,1803 ****
{
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));
! 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 */
return (AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,%C0) CR_TAB
--- 1806,1838 ----
{
case 0: /* mov r,r */
if (true_regnum (operands[0]) > true_regnum (operands[1]))
! {
! 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
! {
! 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
*************** out_tsthi (insn,l)
*** 2052,2058 ****
if (l) *l = 1;
return AS1 (tst,%B0);
}
! if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
{
if (l) *l = 1;
return AS2 (sbiw,%0,0);
--- 2087,2093 ----
if (l) *l = 1;
return AS1 (tst,%B0);
}
! if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
{
if (l) *l = 1;
return AS2 (sbiw,%0,0);
*************** out_tstsi (insn,l)
*** 2080,2086 ****
if (l) *l = 1;
return AS1 (tst,%D0);
}
! if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
{
if (l) *l = 3;
return (AS2 (sbiw,%A0,0) CR_TAB
--- 2115,2121 ----
if (l) *l = 1;
return AS1 (tst,%D0);
}
! if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
{
if (l) *l = 3;
return (AS2 (sbiw,%A0,0) CR_TAB
*************** out_shift_with_cnt (template,insn,operan
*** 2142,2148 ****
*len = mov_len + 1;
}
}
! else if (register_operand (operands[2],QImode))
{
if (reg_unused_after (insn, operands[2]))
op[3] = op[2];
--- 2177,2183 ----
*len = mov_len + 1;
}
}
! else if (register_operand (operands[2], QImode))
{
if (reg_unused_after (insn, operands[2]))
op[3] = op[2];
*************** ashlqi3_out (insn,operands,len)
*** 2211,2217 ****
AS1 (lsl,%0));
case 4:
! if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
{
*len = 2;
return (AS1 (swap,%0) CR_TAB
--- 2246,2252 ----
AS1 (lsl,%0));
case 4:
! if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 2;
return (AS1 (swap,%0) CR_TAB
*************** ashlqi3_out (insn,operands,len)
*** 2224,2230 ****
AS1 (lsl,%0));
case 5:
! if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
{
*len = 3;
return (AS1 (swap,%0) CR_TAB
--- 2259,2265 ----
AS1 (lsl,%0));
case 5:
! if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 3;
return (AS1 (swap,%0) CR_TAB
*************** ashlqi3_out (insn,operands,len)
*** 2239,2245 ****
AS1 (lsl,%0));
case 6:
! if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
{
*len = 4;
return (AS1 (swap,%0) CR_TAB
--- 2274,2280 ----
AS1 (lsl,%0));
case 6:
! if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 4;
return (AS1 (swap,%0) CR_TAB
*************** ashlsi3_out (insn,operands,len)
*** 2376,2381 ****
--- 2411,2423 ----
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
*************** ashrsi3_out (insn,operands,len)
*** 2610,2615 ****
--- 2652,2666 ----
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
*************** lshrqi3_out (insn,operands,len)
*** 2693,2699 ****
AS1 (lsr,%0));
case 4:
! if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
{
*len=2;
return (AS1 (swap,%0) CR_TAB
--- 2744,2750 ----
AS1 (lsr,%0));
case 4:
! if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len=2;
return (AS1 (swap,%0) CR_TAB
*************** lshrqi3_out (insn,operands,len)
*** 2706,2712 ****
AS1 (lsr,%0));
case 5:
! if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
{
*len = 3;
return (AS1 (swap,%0) CR_TAB
--- 2757,2763 ----
AS1 (lsr,%0));
case 5:
! if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 3;
return (AS1 (swap,%0) CR_TAB
*************** lshrqi3_out (insn,operands,len)
*** 2721,2727 ****
AS1 (lsr,%0));
case 6:
! if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
{
*len = 4;
return (AS1 (swap,%0) CR_TAB
--- 2772,2778 ----
AS1 (lsr,%0));
case 6:
! if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 4;
return (AS1 (swap,%0) CR_TAB
*************** lshrsi3_out (insn,operands,len)
*** 2860,2865 ****
--- 2911,2923 ----
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
*************** asm_output_section_name(file, decl, name
*** 3275,3281 ****
const char *name;
int reloc ATTRIBUTE_UNUSED;
{
! fprintf (file, ".section\t%s,\"%s\",@progbits\n", name, \
decl && TREE_CODE (decl) == FUNCTION_DECL ? "ax" :
decl && TREE_READONLY (decl) ? "a" : "aw");
}
--- 3333,3339 ----
const char *name;
int reloc ATTRIBUTE_UNUSED;
{
! fprintf (file, ".section %s, \"%s\", @progbits\n", name,
decl && TREE_CODE (decl) == FUNCTION_DECL ? "ax" :
decl && TREE_READONLY (decl) ? "a" : "aw");
}
*************** valid_machine_type_attribute(type, attri
*** 3407,3415 ****
Valid attributes:
progmem - put data to program memory;
signal - make a function to be hardware interrupt. After function
! epilogue interrupts are disabled;
interrupt - make a function to be hardware interrupt. After function
! epilogue interrupts are enabled;
naked - don't generate function prologue/epilogue and `ret' command. */
int
--- 3465,3473 ----
Valid attributes:
progmem - put data to program memory;
signal - make a function to be hardware interrupt. After function
! prologue interrupts are disabled;
interrupt - make a function to be hardware interrupt. After function
! prologue interrupts are enabled;
naked - don't generate function prologue/epilogue and `ret' command. */
int
*************** valid_machine_decl_attribute (decl, attr
*** 3440,3446 ****
/* Look for attribute `progmem' in DECL
! founded - 1 otherwise 0 */
int
avr_progmem_p (decl)
--- 3498,3504 ----
/* Look for attribute `progmem' in DECL
! if found return 1, otherwise 0. */
int
avr_progmem_p (decl)
*************** encode_section_info (decl)
*** 3481,3486 ****
--- 3539,3545 ----
{
char * dsec = ".progmem.data";
DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
+ TREE_READONLY (decl) = 1;
}
}
*************** avr_function_value (type,func)
*** 3864,3870 ****
return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
}
! /* Returns non-zero if number MASK have only one setted bit */
int
mask_one_bit_p (mask)
--- 3923,3929 ----
return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
}
! /* Returns non-zero if the number MASK has only one bit set. */
int
mask_one_bit_p (mask)
*************** mask_one_bit_p (mask)
*** 3892,3898 ****
in class CLASS. */
enum reg_class
! preferred_reload_class(x,class)
rtx x;
enum reg_class class;
{
--- 3951,3957 ----
in class CLASS. */
enum reg_class
! preferred_reload_class (x, class)
rtx x;
enum reg_class class;
{
*************** preferred_reload_class(x,class)
*** 3908,3914 ****
}
int
! test_hard_reg_class(class, x)
enum reg_class class;
rtx x;
{
--- 3967,3973 ----
}
int
! test_hard_reg_class (class, x)
enum reg_class class;
rtx x;
{
*************** jump_over_one_insn_p (insn, dest)
*** 3946,3954 ****
}
/* 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. */
int
avr_hard_regno_mode_ok (regno, mode)
--- 4005,4013 ----
}
/* Returns 1 if a value of mode MODE can be stored starting with hard
! 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)
*************** avr_hard_regno_mode_ok (regno, mode)
*** 3957,3963 ****
{
if (mode == QImode)
return 1;
! if (regno < 24 /* && !TARGET_ENHANCED */ )
return 1;
return !(regno & 1);
}
--- 4016,4022 ----
{
if (mode == QImode)
return 1;
! if (regno < 24 && !TARGET_ENHANCED)
return 1;
return !(regno & 1);
}
diff -Nrc3p orig/egcs/gcc/config/avr/avr.h egcs/gcc/config/avr/avr.h
*** orig/egcs/gcc/config/avr/avr.h Sat Jun 24 20:33:48 2000
--- egcs/gcc/config/avr/avr.h Sat Jul 1 14:42:38 2000
*************** Boston, MA 02111-1307, USA. */
*** 46,64 ****
/* This declaration should be present. */
extern int target_flags;
! #define TARGET_ORDER_1 (target_flags & 0x1000)
! #define TARGET_ORDER_2 (target_flags & 0x4000)
! #define TARGET_INT8 (target_flags & 0x10000)
! #define TARGET_NO_INTERRUPTS (target_flags & 0x20000)
! #define TARGET_INSN_SIZE_DUMP (target_flags & 0x2000)
! #define TARGET_CALL_PROLOGUES (target_flags & 0x40000)
! #define TARGET_TINY_STACK (target_flags & 0x80000)
/* Dump each assembler insn's rtl into the output file.
This is for debugging the compiler itself. */
! #define TARGET_RTL_DUMP (target_flags & 0x010)
! #define TARGET_ALL_DEBUG (target_flags & 0xfe0)
/* `TARGET_...'
This series of macros is to allow compiler command arguments to
--- 46,78 ----
/* This declaration should be present. */
extern int target_flags;
! #define MASK_RTL_DUMP 0x00000010
! #define MASK_ALL_DEBUG 0x00000FE0
! #define MASK_ORDER_1 0x00001000
! #define MASK_INSN_SIZE_DUMP 0x00002000
! #define MASK_ORDER_2 0x00004000
! #define MASK_INT8 0x00010000
! #define MASK_NO_INTERRUPTS 0x00020000
! #define MASK_CALL_PROLOGUES 0x00040000
! #define MASK_TINY_STACK 0x00080000
! #define MASK_PACK_ARGS 0x00100000
! #define MASK_ENHANCED 0x00200000
!
! #define TARGET_ORDER_1 (target_flags & MASK_ORDER_1)
! #define TARGET_ORDER_2 (target_flags & MASK_ORDER_2)
! #define TARGET_INT8 (target_flags & MASK_INT8)
! #define TARGET_NO_INTERRUPTS (target_flags & MASK_NO_INTERRUPTS)
! #define TARGET_INSN_SIZE_DUMP (target_flags & MASK_INSN_SIZE_DUMP)
! #define TARGET_CALL_PROLOGUES (target_flags & MASK_CALL_PROLOGUES)
! #define TARGET_TINY_STACK (target_flags & MASK_TINY_STACK)
! #define TARGET_PACK_ARGS (target_flags & MASK_PACK_ARGS)
! #define TARGET_ENHANCED (target_flags & MASK_ENHANCED)
/* Dump each assembler insn's rtl into the output file.
This is for debugging the compiler itself. */
! #define TARGET_RTL_DUMP (target_flags & MASK_RTL_DUMP)
! #define TARGET_ALL_DEBUG (target_flags & MASK_ALL_DEBUG)
/* `TARGET_...'
This series of macros is to allow compiler command arguments to
*************** extern int target_flags;
*** 83,99 ****
#define TARGET_SWITCHES { \
! {"order1",0x1000, NULL}, \
! {"order2",0x4000, NULL}, \
! {"int8",0x10000,"Assume int to be 8 bit integer"}, \
! {"no-interrupts",0x20000,"Don't output interrupt compatible code"}, \
! {"call-prologues",0x40000, \
! "Use subroutines for functions prologue/epilogue"}, \
! {"tiny-stack", 0x80000, "Change only low 8 bits of stack pointer"}, \
! {"rtl",0x10, NULL}, \
! {"size",0x2000,"Output instruction size's to the asm file"}, \
! {"deb",0xfe0, NULL}, \
! {"",0, NULL}}
/* This macro defines names of command options to set and clear bits
in `target_flags'. Its definition is an initializer with a
subgrouping for each command option.
--- 97,120 ----
#define TARGET_SWITCHES { \
! { "order1", MASK_ORDER_1, NULL }, \
! { "order2", MASK_ORDER_2, NULL }, \
! { "int8", MASK_INT8, N_("Assume int to be 8 bit integer") }, \
! { "no-interrupts", MASK_NO_INTERRUPTS, \
! N_("Change the stack pointer without disabling interrupts") }, \
! { "call-prologues", MASK_CALL_PROLOGUES, \
! N_("Use subroutines for function prologue/epilogue") }, \
! { "tiny-stack", MASK_TINY_STACK, \
! N_("Change only the low 8 bits of the stack pointer") }, \
! { "pack-args", MASK_PACK_ARGS, \
! N_("Do not align function arguments on even numbered registers") }, \
! { "enhanced", MASK_ENHANCED, \
! N_("Generate code for the enhanced AVR core") }, \
! { "rtl", MASK_RTL_DUMP, NULL }, \
! { "size", MASK_INSN_SIZE_DUMP, \
! N_("Output instruction sizes to the asm file") }, \
! { "deb", MASK_ALL_DEBUG, NULL }, \
! { "", 0, NULL } }
/* This macro defines names of command options to set and clear bits
in `target_flags'. Its definition is an initializer with a
subgrouping for each command option.
*************** extern struct mcu_type_s *avr_mcu_type;
*** 129,137 ****
#define AVR_MEGA (avr_mcu_type->mega)
#define TARGET_OPTIONS { \
! {"init-stack=",&avr_ram_end,"Specify the initial stack address" }, \
! {"mcu=", &avr_mcu_name, \
! "Specify the MCU name (at90s23xx,attiny22,at90s44xx,at90s85xx,atmega603,atmega103)"}}
/* This macro is similar to `TARGET_SWITCHES' but defines names of
command options that have values. Its definition is an
initializer with a subgrouping for each command option.
--- 150,157 ----
#define AVR_MEGA (avr_mcu_type->mega)
#define TARGET_OPTIONS { \
! { "init-stack=", &avr_ram_end, N_("Specify the initial stack address") }, \
! { "mcu=", &avr_mcu_name, N_("Specify the MCU name") } }
/* This macro is similar to `TARGET_SWITCHES' but defines names of
command options that have values. Its definition is an
initializer with a subgrouping for each command option.
*************** progmem_section (void) \
*** 1984,1990 ****
{ \
if (in_section != in_progmem) \
{ \
! fprintf (asm_out_file, ".section .progmem.gcc_sw_table\n"); \
in_section = in_progmem; \
} \
}
--- 2004,2011 ----
{ \
if (in_section != in_progmem) \
{ \
! fprintf (asm_out_file, \
! ".section .progmem.gcc_sw_table, \"a\", @progbits\n"); \
in_section = in_progmem; \
} \
}
diff -Nrc3p orig/egcs/gcc/config/avr/avr.md egcs/gcc/config/avr/avr.md
*** orig/egcs/gcc/config/avr/avr.md Sat Jun 24 20:33:48 2000
--- egcs/gcc/config/avr/avr.md Sat Jul 1 14:42:38 2000
***************
*** 249,254 ****
--- 249,257 ----
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,658 ****
--- 656,712 ----
[(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,1612 ****
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\");
else if (!AVR_MEGA)
return AS1(rcall,%c0);
return AS1(call,%c0);
--- 1658,1672 ----
if (which_alternative==0)
return \"icall\";
else if (which_alternative==1)
! {
! 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,1642 ****
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\");
else if (!AVR_MEGA)
return AS1(rcall,%c1);
return AS1(call,%c1);
--- 1694,1708 ----
if (which_alternative==0)
return \"icall\";
else if (which_alternative==1)
! {
! 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,1681 ****
--- 1742,1762 ----
"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,1695 ****
sbci r31,hi8(-(%2))
lpm
push r0
! adiw r30,1
lpm
push r0
! ret"
[(set_attr "length" "8")
(set_attr "cc" "clobber")])
--- 1767,1776 ----
sbci r31,hi8(-(%2))
lpm
push r0
! adiw r30,1
lpm
push r0
! ret"
[(set_attr "length" "8")
(set_attr "cc" "clobber")])
diff -Nrc3p orig/egcs/gcc/config/avr/libgcc.S egcs/gcc/config/avr/libgcc.S
*** orig/egcs/gcc/config/avr/libgcc.S Sat Jun 24 20:33:49 2000
--- egcs/gcc/config/avr/libgcc.S Sat Jul 1 14:42:38 2000
*************** Boston, MA 02111-1307, USA. */
*** 39,45 ****
*******************************************************/
#if defined (Lmulqi3)
! #define r_arg2 r25 /* multiplicand */
#define r_arg1 r24 /* multiplier */
#define r_res __tmp_reg__ /* result */
--- 39,45 ----
*******************************************************/
#if defined (Lmulqi3)
! #define r_arg2 r22 /* multiplicand */
#define r_arg1 r24 /* multiplier */
#define r_res __tmp_reg__ /* result */
*************** __mulsi3_exit:
*** 201,208 ****
Division 8 / 8 => (result + remainder)
*******************************************************/
#define r_rem r26 /* remainder */
! #define r_arg1 r25 /* dividend */
! #define r_arg2 r24 /* divisor */
#define r_cnt r27 /* loop count */
#if defined (Lumodqi3)
--- 201,208 ----
Division 8 / 8 => (result + remainder)
*******************************************************/
#define r_rem r26 /* remainder */
! #define r_arg1 r24 /* dividend */
! #define r_arg2 r22 /* divisor */
#define r_cnt r27 /* loop count */
#if defined (Lumodqi3)
*************** __divqi3_1:
*** 272,279 ****
sbrc __tmp_reg__,7
neg r_arg1 ; correct result sign
__divqi3_exit:
! mov r24,r_arg1 ; put result to return register
! ret
.endfunc
#endif /* defined (Ldivqi3) */
--- 272,278 ----
sbrc __tmp_reg__,7
neg r_arg1 ; correct result sign
__divqi3_exit:
! ret ; result already in r24 (r_arg1)
.endfunc
#endif /* defined (Ldivqi3) */
*************** _umodsi3_ret:
*** 434,441 ****
mov r24,r_remHL
mov r23,r_remH
mov r22,r_remL
- .global _cleanup
- _cleanup:
ret
.endfunc
#endif /* defined (Lumodsi3) */
--- 433,438 ----
*************** __epilogue_restores__:
*** 630,638 ****
#endif /* defined (Lepilogue) */
#ifdef L__exit
! .global _exit
.func _exit
_exit:
rjmp _exit
.endfunc
#endif
--- 627,638 ----
#endif /* defined (Lepilogue) */
#ifdef L__exit
! .weak _exit
.func _exit
_exit:
rjmp _exit
+ .weak _cleanup
+ _cleanup:
+ ret
.endfunc
#endif