2 This patch optimizes the function prologue and epilogue generation for ColdFire
3 targets, where the movem instructions lacks addressing modes with post-increment
6 (based on Peter Barada's CVS tree for ColdFire targets)
8 diff -Nru gcc-3.3.1.orig/gcc/config/m68k/m68k-protos.h gcc-3.3.1/gcc/config/m68k/m68k-protos.h
9 --- gcc-3.3.1.orig/gcc/config/m68k/m68k-protos.h 2002-10-21 00:37:11.000000000 +0200
10 +++ gcc-3.3.1/gcc/config/m68k/m68k-protos.h 2003-07-25 00:29:04.000000000 +0200
12 /* Define functions defined in aux-output.c and used in templates. */
15 +extern HOST_WIDE_INT m68k_initial_elimination_offset PARAMS ((int, int));
16 extern const char *output_move_const_into_data_reg PARAMS ((rtx *));
17 extern const char *output_move_simode_const PARAMS ((rtx *));
18 extern const char *output_move_simode PARAMS ((rtx *));
19 diff -Nru gcc-3.3.1.orig/gcc/config/m68k/m68k.c gcc-3.3.1/gcc/config/m68k/m68k.c
20 --- gcc-3.3.1.orig/gcc/config/m68k/m68k.c 2003-07-25 00:28:46.000000000 +0200
21 +++ gcc-3.3.1/gcc/config/m68k/m68k.c 2003-07-25 00:29:04.000000000 +0200
23 /* Needed for use_return_insn. */
26 +/* Return nonzero if FUNC is an interrupt function as specified by the
27 + "interrupt_handler" attribute. */
30 +m68k_interrupt_function_p(func)
35 + if (TREE_CODE (func) != FUNCTION_DECL)
38 + a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
39 + return (a != NULL_TREE);
42 +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
43 + struct attribute_spec.handler. */
45 +m68k_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
48 + tree args ATTRIBUTE_UNUSED;
49 + int flags ATTRIBUTE_UNUSED;
52 + if (TREE_CODE (*node) != FUNCTION_DECL)
54 + warning ("`%s' attribute only applies to functions",
55 + IDENTIFIER_POINTER (name));
56 + *no_add_attrs = true;
62 +const struct attribute_spec m68k_attribute_table[] =
64 + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
65 + { "interrupt_handler", 0, 0, true, false, false, m68k_handle_fndecl_attribute },
66 + { NULL, 0, 0, false, false, false, NULL }
69 #ifdef SUPPORT_SUN_FPA
71 /* Index into this array by (register number >> 3) to find the
74 static void m68k_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
75 HOST_WIDE_INT, tree));
76 -static int m68k_save_reg PARAMS ((unsigned int));
77 +static int m68k_save_reg PARAMS ((unsigned int, int));
80 /* Alignment to use for loops and jumps */
82 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
83 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
85 +#undef TARGET_ATTRIBUTE_TABLE
86 +#define TARGET_ATTRIBUTE_TABLE m68k_attribute_table
88 struct gcc_target targetm = TARGET_INITIALIZER;
90 /* Sometimes certain combinations of command options do not make
91 @@ -208,10 +254,116 @@
92 real_format_for_mode[XFmode - QFmode] = &ieee_extended_motorola_format;
95 +/* Structure describing stack frame layout. */
97 + HOST_WIDE_INT offset;
99 + /* data and address register */
101 + unsigned int reg_mask;
102 + unsigned int reg_rev_mask;
103 + /* fpu registers */
105 + unsigned int fpu_mask;
106 + unsigned int fpu_rev_mask;
107 + /* fpa registers */
109 + /* offsets relative to ARG_POINTER. */
110 + HOST_WIDE_INT frame_pointer_offset;
111 + HOST_WIDE_INT hard_frame_pointer_offset;
112 + HOST_WIDE_INT stack_pointer_offset;
116 +m68k_compute_frame_layout (frame)
117 + struct m68k_frame *frame;
120 + unsigned int mask, rmask;
121 + int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
123 + frame->size = (get_frame_size () + 3) & -4;
125 + mask = rmask = saved = 0;
126 + for (regno = 0; regno < 16; regno++)
127 + if (m68k_save_reg (regno, interrupt_handler))
129 + mask |= 1 << regno;
130 + rmask |= 1 << (15 - regno);
133 + frame->offset = saved * 4;
134 + frame->reg_no = saved;
135 + frame->reg_mask = mask;
136 + frame->reg_rev_mask = rmask;
140 + mask = rmask = saved = 0;
141 + for (regno = 16; regno < 24; regno++)
142 + if (regs_ever_live[regno] && ! call_used_regs[regno])
144 + mask |= 1 << (23 - regno);
145 + rmask |= 1 << (regno - 16);
148 + frame->offset += saved * 12;
149 + frame->fpu_no = saved;
150 + frame->fpu_mask = mask;
151 + frame->fpu_rev_mask = rmask;
153 + if (0 /* || TARGET_CFV4E */)
155 + mask = rmask = saved = 0;
156 + for (regno = 16; regno < 24; regno++)
157 + if (regs_ever_live[regno] && ! call_used_regs[regno])
159 + mask |= 1 << (23 - regno);
160 + rmask |= 1 << (regno - 16);
163 + frame->offset += saved * 8;
164 + frame->fpu_no = saved;
165 + frame->fpu_mask = mask;
166 + frame->fpu_rev_mask = rmask;
168 + else if (TARGET_FPA)
170 + mask = rmask = saved = 0;
171 + for (regno = 24; regno < 56; regno++)
172 + if (regs_ever_live[regno] && ! call_used_regs[regno])
174 + frame->offset += saved * 8;
175 + frame->fpa_no = saved;
180 +m68k_initial_elimination_offset (from, to)
184 + struct m68k_frame frame;
186 + m68k_compute_frame_layout (&frame);
188 + if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
190 + else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
191 + return frame.offset + frame.size + (frame_pointer_needed ? -UNITS_PER_WORD * 2 : -UNITS_PER_WORD);
192 + else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
193 + return frame.offset + frame.size;
194 + else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
200 /* Return 1 if we need to save REGNO. */
202 -m68k_save_reg (regno)
203 +m68k_save_reg (regno, interrupt_handler)
205 + int interrupt_handler;
207 if (flag_pic && current_function_uses_pic_offset_table
208 && regno == PIC_OFFSET_TABLE_REGNUM)
213 - return (regs_ever_live[regno]
214 - && !call_used_regs[regno]
216 + ((regs_ever_live[regno] && !call_used_regs[regno])
217 + || (interrupt_handler
218 + && (regs_ever_live[regno]
219 + || (call_used_regs[regno] && !current_function_is_leaf)
223 && !fixed_regs[regno]
224 && !(regno == FRAME_POINTER_REGNUM && frame_pointer_needed));
228 register int mask = 0;
229 HOST_WIDE_INT fsize = ((size) + 3) & -4;
230 + int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
232 /* unos stack probe */
237 for (regno = 16; regno < 24; regno++)
238 - if (m68k_save_reg (regno))
239 + if (m68k_save_reg (regno, interrupt_handler))
240 mask |= 1 << (regno - 16);
242 if ((mask & 0xff) != 0)
246 for (regno = 0; regno < 16; regno++)
247 - if (m68k_save_reg (regno))
248 + if (m68k_save_reg (regno, interrupt_handler))
249 mask |= 1 << (15 - regno);
251 if (exact_log2 (mask) >= 0)
253 HOST_WIDE_INT fsize = (size + 3) & -4;
254 HOST_WIDE_INT cfa_offset = INCOMING_FRAME_SP_OFFSET;
255 HOST_WIDE_INT cfa_store_offset = cfa_offset;
256 + int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
258 /* If the stack limit is a symbol, we can check it here,
259 before actually allocating the space. */
262 else if (fsize < 0x8000)
264 + if (TARGET_COLDFIRE)
266 + /* on Coldfire add register save into initial stack frame setup, if possible */
267 + for (regno = 0; regno < 16; regno++)
268 + if (m68k_save_reg (regno, interrupt_handler))
271 + if ( ( fsize + num_saved_regs * 4 >= 0x8000 ) || ( num_saved_regs <= 2 ) )
272 + num_saved_regs = 0;
274 + asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
275 + reg_names[FRAME_POINTER_REGNUM], -fsize - num_saved_regs * 4);
277 + asm_fprintf (stream, "\tlink %s,%0I%d\n",
278 + reg_names[FRAME_POINTER_REGNUM], -fsize - num_saved_regs * 4 );
280 + num_saved_regs = 0;
285 asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
286 reg_names[FRAME_POINTER_REGNUM], -fsize);
288 asm_fprintf (stream, "\tlink %s,%0I%d\n",
289 reg_names[FRAME_POINTER_REGNUM], -fsize);
293 else if (TARGET_68020)
297 #ifdef SUPPORT_SUN_FPA
298 for (regno = 24; regno < 56; regno++)
299 - if (m68k_save_reg (regno))
300 + if (m68k_save_reg (regno, interrupt_handler))
303 asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
307 for (regno = 16; regno < 24; regno++)
308 - if (m68k_save_reg (regno))
309 + if (m68k_save_reg (regno, interrupt_handler))
311 mask |= 1 << (regno - 16);
316 for (regno = 0; regno < 16; regno++)
317 - if (m68k_save_reg (regno))
318 + if (m68k_save_reg (regno, interrupt_handler))
320 mask |= 1 << (15 - regno);
323 then use the plain address register indirect mode. We also
324 have to invert the register save mask to use the new mode.
326 - FIXME: if num_saved_regs was calculated earlier, we could
327 - combine the stack pointer adjustment with any adjustment
328 - done when the initial stack frame is created. This would
329 - save an instruction */
330 + The required register save space was combined earlier with
331 + the fsize amount if possible. Check for this and don't add
336 @@ -614,11 +794,17 @@
338 newmask |= (1 << (15-i));
340 + if ( fsize + num_saved_regs * 4 >= 0x8000 )
343 asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", -num_saved_regs*4);
344 - asm_fprintf (stream, "\tmovm.l %0I0x%x,(%Rsp)\n", newmask);
346 asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", -num_saved_regs*4);
350 + asm_fprintf (stream, "\tmovm.l %0I0x%x,(%Rsp)\n", newmask);
352 asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@\n", newmask);
355 @@ -669,12 +855,13 @@
359 + int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
361 if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
364 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
365 - if (m68k_save_reg (regno))
366 + if (m68k_save_reg (regno, interrupt_handler))
370 @@ -701,10 +888,11 @@
371 HOST_WIDE_INT offset, foffset, fpoffset;
372 HOST_WIDE_INT fsize = ((size) + 3) & -4;
374 + int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
376 nregs = 0; fmask = 0; fpoffset = 0;
377 for (regno = 16; regno < 24; regno++)
378 - if (m68k_save_reg (regno))
379 + if (m68k_save_reg (regno, interrupt_handler))
382 fmask |= 1 << (23 - regno);
386 for (regno = 0; regno < 16; regno++)
387 - if (m68k_save_reg (regno))
388 + if (m68k_save_reg (regno, interrupt_handler))
395 for (regno = 55; regno >= 24; regno--)
396 - if (m68k_save_reg (regno))
397 + if (m68k_save_reg (regno, interrupt_handler))
400 fprintf(stream, "\tfpmoved -%d(a6,a0.l), %s\n",
402 if (current_function_calls_eh_return)
403 fprintf (stream, "\tadd.l a0,sp\n");
405 - if (current_function_pops_args)
406 + if (interrupt_handler)
407 + fprintf (stream, "\trte\n");
408 + else if (current_function_pops_args)
409 fprintf (stream, "\trtd $%d\n", current_function_pops_args);
411 fprintf (stream, "\trts\n");
414 rtx insn = get_last_insn ();
415 int restore_from_sp = 0;
416 + int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
418 /* If the last insn was a BARRIER, we don't have to write any code. */
419 if (GET_CODE (insn) == NOTE)
421 nregs = 0; fmask = 0; fpoffset = 0;
422 #ifdef SUPPORT_SUN_FPA
423 for (regno = 24 ; regno < 56 ; regno++)
424 - if (m68k_save_reg (regno))
425 + if (m68k_save_reg (regno, interrupt_handler))
427 fpoffset = nregs * 8;
432 for (regno = 16; regno < 24; regno++)
433 - if (m68k_save_reg (regno))
434 + if (m68k_save_reg (regno, interrupt_handler))
437 fmask |= 1 << (23 - regno);
439 foffset = fpoffset + nregs * 12;
441 for (regno = 0; regno < 16; regno++)
442 - if (m68k_save_reg (regno))
443 + if (m68k_save_reg (regno, interrupt_handler))
447 @@ -926,39 +1117,82 @@
453 + /* The ColdFire requires special handling due to its limited moveml insn */
454 + if (TARGET_COLDFIRE)
460 - asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n",
462 - reg_names[FRAME_POINTER_REGNUM],
464 + asm_fprintf (stream, "\tadd.l %s,%Ra1\n", reg_names[FRAME_POINTER_REGNUM]);
465 + asm_fprintf (stream, "\tmovm.l (%Ra1),%0I0x%x\n", mask);
467 - asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n",
468 - reg_names[FRAME_POINTER_REGNUM],
469 - offset + fsize, mask);
470 + asm_fprintf (stream, "\taddl %s,%Ra1\n", reg_names[FRAME_POINTER_REGNUM]);
471 + asm_fprintf (stream, "\tmoveml %Ra1@,%0I0x%x\n", mask);
474 - else if (restore_from_sp)
477 + else if (restore_from_sp)
480 - asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);
481 + asm_fprintf (stream, "\tmovm.l (%Rsp),%0I0x%x\n", mask);
482 + asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", nregs*4);
484 - asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask);
485 + asm_fprintf (stream, "\tmoveml %Rsp@,%0I0x%x\n", mask);
486 + asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", nregs*4);
494 + asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n",
496 + reg_names[FRAME_POINTER_REGNUM],
499 + asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n",
500 + reg_names[FRAME_POINTER_REGNUM],
501 + offset + fsize, mask);
512 - asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n",
514 - reg_names[FRAME_POINTER_REGNUM],
516 + asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n",
518 + reg_names[FRAME_POINTER_REGNUM],
521 - asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n",
522 - reg_names[FRAME_POINTER_REGNUM],
523 - offset + fsize, mask);
524 + asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n",
525 + reg_names[FRAME_POINTER_REGNUM],
526 + offset + fsize, mask);
529 + else if (restore_from_sp)
532 + asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);
534 + asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask);
540 + asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n",
542 + reg_names[FRAME_POINTER_REGNUM],
545 + asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n",
546 + reg_names[FRAME_POINTER_REGNUM],
547 + offset + fsize, mask);
553 @@ -1000,7 +1234,7 @@
556 for (regno = 55; regno >= 24; regno--)
557 - if (m68k_save_reg (regno))
558 + if (m68k_save_reg (regno, interrupt_handler))
562 @@ -1118,7 +1352,9 @@
563 asm_fprintf (stream, "\taddl %Ra0,%Rsp\n");
566 - if (current_function_pops_args)
567 + if (interrupt_handler)
568 + fprintf (stream, "\trte\n");
569 + else if (current_function_pops_args)
570 asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args);
572 fprintf (stream, "\trts\n");
573 diff -Nru gcc-3.3.1.orig/gcc/config/m68k/m68k.h gcc-3.3.1/gcc/config/m68k/m68k.h
574 --- gcc-3.3.1.orig/gcc/config/m68k/m68k.h 2003-07-25 00:28:46.000000000 +0200
575 +++ gcc-3.3.1/gcc/config/m68k/m68k.h 2003-07-25 00:29:04.000000000 +0200
576 @@ -1124,32 +1124,6 @@
577 You should override this if you define FUNCTION_EXTRA_EPILOGUE. */
578 #define USE_RETURN_INSN use_return_insn ()
580 -/* Store in the variable DEPTH the initial difference between the
581 - frame pointer reg contents and the stack pointer reg contents,
582 - as of the start of the function body. This depends on the layout
583 - of the fixed parts of the stack frame and on how registers are saved.
585 - On the 68k, if we have a frame, we must add one word to its length
586 - to allow for the place that a6 is stored when we do have a frame pointer.
587 - Otherwise, we would need to compute the offset from the frame pointer
588 - of a local variable as a function of frame_pointer_needed, which
591 -#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \
594 - for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \
595 - if (regs_ever_live[regno] && ! call_used_regs[regno]) \
597 - for (regno = 0; regno < 16; regno++) \
598 - if (regs_ever_live[regno] && ! call_used_regs[regno]) \
600 - if (flag_pic && current_function_uses_pic_offset_table) \
602 - (DEPTH) = (offset + ((get_frame_size () + 3) & -4) \
603 - + (get_frame_size () == 0 ? 0 : 4)); \
606 /* Output assembler code for a block containing the constant parts
607 of a trampoline, leaving space for the variable parts. */
609 @@ -1227,6 +1201,39 @@
613 +/* Definitions for register eliminations.
615 + This is an array of structures. Each structure initializes one pair
616 + of eliminable registers. The "from" register number is given first,
617 + followed by "to". Eliminations of the same "from" register are listed
618 + in order of preference.
620 + There are two registers that can always be eliminated on the i386.
621 + The frame pointer and the arg pointer can be replaced by either the
622 + hard frame pointer or to the stack pointer, depending upon the
623 + circumstances. The hard frame pointer is not used before reload and
624 + so it is not eligible for elimination. */
626 +#define ELIMINABLE_REGS \
627 +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
628 + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
629 + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
630 + { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} \
632 +/* Given FROM and TO register numbers, say whether this elimination is
633 + allowed. Frame pointer elimination is automatically handled.
635 + All other eliminations are valid. */
637 +#define CAN_ELIMINATE(FROM, TO) \
638 + ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1)
640 +/* Define the offset between two registers, one to be eliminated, and the other
641 + its replacement, at the start of a routine. */
643 +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
644 + (OFFSET) = m68k_initial_elimination_offset(FROM, TO)
646 /* Addressing modes, and classification of registers for them. */
648 #define HAVE_POST_INCREMENT 1