]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/m68k/m68k.c
darwin.h (SUBTARGET_OVERRIDE_OPTIONS): Define.
[thirdparty/gcc.git] / gcc / config / m68k / m68k.c
CommitLineData
79e68feb 1/* Subroutines for insn-output.c for Motorola 68000 family.
400500c4 2 Copyright (C) 1987, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
4592bdcb 3 Free Software Foundation, Inc.
79e68feb
RS
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING. If not, write to
0e29e3c9
RK
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
79e68feb 21
79e68feb 22#include "config.h"
f5220a5d 23#include "system.h"
da932f04 24#include "tree.h"
79e68feb 25#include "rtl.h"
49ad7cfa 26#include "function.h"
79e68feb
RS
27#include "regs.h"
28#include "hard-reg-set.h"
29#include "real.h"
30#include "insn-config.h"
31#include "conditions.h"
79e68feb
RS
32#include "output.h"
33#include "insn-attr.h"
1d8eaa6b 34#include "recog.h"
f5220a5d 35#include "toplev.h"
6d5f49b2
RH
36#include "expr.h"
37#include "reload.h"
5505f548 38#include "tm_p.h"
672a6f42
NB
39#include "target.h"
40#include "target-def.h"
2cc07db4 41#include "debug.h"
79e68feb
RS
42
43/* Needed for use_return_insn. */
44#include "flags.h"
45
46#ifdef SUPPORT_SUN_FPA
47
48/* Index into this array by (register number >> 3) to find the
49 smallest class which contains that register. */
50enum reg_class regno_reg_class[]
51 = { DATA_REGS, ADDR_REGS, FP_REGS,
52 LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };
53
54#endif /* defined SUPPORT_SUN_FPA */
55
9eb4f6fc
RS
56/* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END,
57 if SGS_SWITCH_TABLE. */
58int switch_table_difference_label_flag;
59
5505f548 60static rtx find_addr_reg PARAMS ((rtx));
5505f548 61static const char *singlemove_string PARAMS ((rtx *));
08c148a8
NB
62static void m68k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
63static void m68k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
715bdd29 64static void m68k_coff_asm_named_section PARAMS ((const char *, unsigned int));
d67c7dd8 65#ifdef CTOR_LIST_BEGIN
2cc07db4
RH
66static void m68k_svr3_asm_out_constructor PARAMS ((rtx, int));
67#endif
79e68feb
RS
68\f
69
ef1dbfb0 70/* Alignment to use for loops and jumps */
7a1929e1 71/* Specify power of two alignment used for loops. */
577c6ece 72const char *m68k_align_loops_string;
7a1929e1 73/* Specify power of two alignment used for non-loop jumps. */
577c6ece 74const char *m68k_align_jumps_string;
7a1929e1 75/* Specify power of two alignment used for functions. */
577c6ece 76const char *m68k_align_funcs_string;
ef1dbfb0 77
7a1929e1 78/* Specify power of two alignment used for loops. */
ef1dbfb0 79int m68k_align_loops;
7a1929e1 80/* Specify power of two alignment used for non-loop jumps. */
ef1dbfb0 81int m68k_align_jumps;
7a1929e1 82/* Specify power of two alignment used for functions. */
ef1dbfb0
RK
83int m68k_align_funcs;
84
2b3600ac
JL
85/* Nonzero if the last compare/test insn had FP operands. The
86 sCC expanders peek at this to determine what to do for the
87 68060, which has no fsCC instructions. */
88int m68k_last_compare_had_fp_operands;
672a6f42
NB
89\f
90/* Initialize the GCC target structure. */
08c148a8
NB
91#undef TARGET_ASM_FUNCTION_PROLOGUE
92#define TARGET_ASM_FUNCTION_PROLOGUE m68k_output_function_prologue
93#undef TARGET_ASM_FUNCTION_EPILOGUE
94#define TARGET_ASM_FUNCTION_EPILOGUE m68k_output_function_epilogue
ef1dbfb0 95
f6897b10 96struct gcc_target targetm = TARGET_INITIALIZER;
672a6f42 97\f
ef1dbfb0
RK
98/* Sometimes certain combinations of command options do not make
99 sense on a particular target machine. You can define a macro
100 `OVERRIDE_OPTIONS' to take account of this. This macro, if
101 defined, is executed once just after all the command options have
102 been parsed.
103
104 Don't use this macro to turn on various extra optimizations for
105 `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
106
107void
108override_options ()
109{
110 int def_align;
400500c4 111 int i;
ef1dbfb0
RK
112
113 def_align = 1;
114
115 /* Validate -malign-loops= value, or provide default */
400500c4 116 m68k_align_loops = def_align;
ef1dbfb0
RK
117 if (m68k_align_loops_string)
118 {
400500c4
RK
119 i = atoi (m68k_align_loops_string);
120 if (i < 1 || i > MAX_CODE_ALIGN)
121 error ("-malign-loops=%d is not between 1 and %d", i, MAX_CODE_ALIGN);
122 else
123 m68k_align_loops = i;
ef1dbfb0 124 }
ef1dbfb0
RK
125
126 /* Validate -malign-jumps= value, or provide default */
400500c4 127 m68k_align_jumps = def_align;
ef1dbfb0
RK
128 if (m68k_align_jumps_string)
129 {
400500c4
RK
130 i = atoi (m68k_align_jumps_string);
131 if (i < 1 || i > MAX_CODE_ALIGN)
132 error ("-malign-jumps=%d is not between 1 and %d", i, MAX_CODE_ALIGN);
133 else
134 m68k_align_jumps = i;
ef1dbfb0 135 }
ef1dbfb0
RK
136
137 /* Validate -malign-functions= value, or provide default */
400500c4 138 m68k_align_funcs = def_align;
ef1dbfb0
RK
139 if (m68k_align_funcs_string)
140 {
400500c4
RK
141 i = atoi (m68k_align_funcs_string);
142 if (i < 1 || i > MAX_CODE_ALIGN)
143 error ("-malign-functions=%d is not between 1 and %d",
144 i, MAX_CODE_ALIGN);
145 else
146 m68k_align_funcs = i;
ef1dbfb0 147 }
ef1dbfb0 148}
79e68feb
RS
149\f
150/* This function generates the assembly code for function entry.
151 STREAM is a stdio stream to output the code to.
152 SIZE is an int: how many units of temporary storage to allocate.
153 Refer to the array `regs_ever_live' to determine which registers
154 to save; `regs_ever_live[I]' is nonzero if register number I
155 is ever used in the function. This function is responsible for
156 knowing which registers should not be saved even if used. */
157
158
159/* Note that the order of the bit mask for fmovem is the opposite
160 of the order for movem! */
161
08c148a8 162#ifdef CRDS
79e68feb 163
08c148a8
NB
164static void
165m68k_output_function_prologue (stream, size)
166 FILE *stream;
167 HOST_WIDE_INT size;
168{
169 register int regno;
170 register int mask = 0;
171 extern char call_used_regs[];
172 HOST_WIDE_INT fsize = ((size) + 3) & -4;
173
174 /* unos stack probe */
175 if (fsize > 30000)
176 {
177 fprintf (stream, "\tmovel sp,a0\n");
178 fprintf (stream, "\taddl $-%d,a0\n", 2048 + fsize);
179 fprintf (stream, "\ttstb (a0)\n");
180 }
181 else
182 fprintf (stream, "\ttstb -%d(sp)\n", 2048 + fsize);
183
184 if (frame_pointer_needed)
185 {
186 if (TARGET_68020 || fsize < 0x8000)
187 fprintf (stream, "\tlink a6,$%d\n", -fsize);
188 else
189 fprintf (stream, "\tlink a6,$0\n\tsubl $%d,sp\n", fsize);
190 }
191 else if (fsize)
192 {
193 /* Adding negative number is faster on the 68040. */
194 if (fsize + 4 < 0x8000)
195 fprintf (stream, "\tadd.w #%d,sp\n", - (fsize + 4));
196 else
197 fprintf (stream, "\tadd.l #%d,sp\n", - (fsize + 4));
198 }
199
200 for (regno = 16; regno < 24; regno++)
201 if (regs_ever_live[regno] && ! call_used_regs[regno])
202 mask |= 1 << (regno - 16);
203
204 if ((mask & 0xff) != 0)
205 fprintf (stream, "\tfmovem $0x%x,-(sp)\n", mask & 0xff);
206
207 mask = 0;
208 for (regno = 0; regno < 16; regno++)
209 if (regs_ever_live[regno] && ! call_used_regs[regno])
210 mask |= 1 << (15 - regno);
211 if (frame_pointer_needed)
212 mask &= ~ (1 << (15-FRAME_POINTER_REGNUM));
213
214 if (exact_log2 (mask) >= 0)
215 fprintf (stream, "\tmovel %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]);
216 else if (mask)
217 fprintf (stream, "\tmovem $0x%x,-(sp)\n", mask);
218}
219
220#else
221#if defined (DPX2) && defined (MOTOROLA)
222
223static void
224m68k_output_function_prologue (stream, size)
225 FILE *stream;
226 HOST_WIDE_INT size;
227{
228 register int regno;
229 register int mask = 0;
230 int num_saved_regs = 0, first = 1;
231 extern char call_used_regs[];
232 HOST_WIDE_INT fsize = ((size) + 3) & -4;
233
234 if (frame_pointer_needed)
235 {
236 /* Adding negative number is faster on the 68040. */
237 if (fsize < 0x8000 && !TARGET_68040)
238 fprintf (stream, "\tlink %s,#%d\n",
239 reg_names[FRAME_POINTER_REGNUM], -fsize);
240 else if (TARGET_68020)
241 fprintf (stream, "\tlink %s,#%d\n",
242 reg_names[FRAME_POINTER_REGNUM], -fsize);
243 else
244 fprintf (stream, "\tlink %s,#0\n\tadd.l #%d,sp\n",
245 reg_names[FRAME_POINTER_REGNUM], -fsize);
246 }
247 else if (fsize)
248 {
249 /* Adding negative number is faster on the 68040. */
250 if (fsize + 4 < 0x8000)
251 fprintf (stream, "\tadd.w #%d,sp\n", - (fsize + 4));
252 else
253 fprintf (stream, "\tadd.l #%d,sp\n", - (fsize + 4));
254 }
255
256 for (regno = 23; regno >= 16; regno--)
257 if (regs_ever_live[regno] && ! call_used_regs[regno])
258 {
259 if (first)
260 {
261 fprintf (stream, "\tfmovem.x %s", reg_names[regno]);
262 first = 0;
263 }
264 else
265 fprintf (stream, "/%s", reg_names[regno]);
266 }
267 if (!first)
268 fprintf (stream, ",-(sp)\n");
269
270 mask = 0;
271 for (regno = 0; regno < 16; regno++)
272 if (regs_ever_live[regno] && ! call_used_regs[regno])
273 {
274 mask |= 1 << (15 - regno);
275 num_saved_regs++;
276 }
277
278 if (frame_pointer_needed)
279 {
280 mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
281 num_saved_regs--;
282 }
283
284 if (num_saved_regs <= 2)
285 {
286 /* Store each separately in the same order moveml uses.
287 Using two movel instructions instead of a single moveml
288 is about 15% faster for the 68020 and 68030 at no expense
289 in code size */
290
291 int i;
292
7a1929e1 293 /* Undo the work from above. */
08c148a8
NB
294 for (i = 0; i< 16; i++)
295 if (mask & (1 << i))
296 fprintf (stream, "\tmove.l %s,-(sp)\n", reg_names[15 - i]);
297 }
298 else if (mask)
299 {
300 first = 1;
301 for (regno = 0; regno < 16; regno++)
302 if (mask & (1 << regno))
303 {
304 if (first)
305 {
306 fprintf (stream, "\tmovem.l %s", reg_names[15 - regno]);
307 first = 0;
308 }
309 else
310 fprintf (stream, "/%s", reg_names[15 - regno]);
311 }
312 fprintf (stream, ",-(sp)\n");
313 }
314
315 if (flag_pic && current_function_uses_pic_offset_table)
316 {
317 fprintf (stream, "\tmove.l #__GLOBAL_OFFSET_TABLE_, %s\n",
318 reg_names[PIC_OFFSET_TABLE_REGNUM]);
319 fprintf (stream, "\tlea.l (pc,%s.l),%s\n",
320 reg_names[PIC_OFFSET_TABLE_REGNUM],
321 reg_names[PIC_OFFSET_TABLE_REGNUM]);
322 }
323}
324
325#else
326#if defined (NEWS) && defined (MOTOROLA)
327
328static void
329m68k_output_function_prologue (stream, size)
79e68feb 330 FILE *stream;
08c148a8
NB
331 HOST_WIDE_INT size;
332{
333 register int regno;
334 register int mask = 0;
335 extern char call_used_regs[];
336 HOST_WIDE_INT fsize = ((size) + 3) & -4;
337
338 if (frame_pointer_needed)
339 {
340 if (fsize < 0x8000)
341 fprintf (stream, "\tlink fp,#%d\n", -fsize);
342 else if (TARGET_68020)
343 fprintf (stream, "\tlink.l fp,#%d\n", -fsize);
344 else
345 fprintf (stream, "\tlink fp,#0\n\tsub.l #%d,sp\n", fsize);
346 }
347 else if (fsize)
348 {
349 int amt = fsize + 4;
350 /* Adding negative number is faster on the 68040. */
351 if (fsize + 4 < 0x8000)
352 asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - amt);
353 else
354 asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - amt);
355 }
356
357 for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++)
358 if (regs_ever_live[regno] && ! call_used_regs[regno])
359 mask |= 1 << (regno - 16);
360
361 if (mask != 0)
362 fprintf (stream, "\tfmovem.x #0x%x,-(sp)\n", mask & 0xff);
363
364 mask = 0;
365 for (regno = 0; regno < 16; regno++)
366 if (regs_ever_live[regno] && ! call_used_regs[regno])
367 mask |= 1 << (15 - regno);
368
369 if (frame_pointer_needed)
370 mask &= ~ (1 << (15-FRAME_POINTER_REGNUM));
371
372 if (exact_log2 (mask) >= 0)
373 fprintf (stream, "\tmove.l %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]);
374 else
375 if (mask) fprintf (stream, "\tmovem.l #0x%x,-(sp)\n", mask);
376}
377
378#else /* !CRDS && ! (NEWS && MOTOROLA) && ! (DPX2 && MOTOROLA) */
379
380static void
381m68k_output_function_prologue (stream, size)
382 FILE *stream;
383 HOST_WIDE_INT size;
79e68feb
RS
384{
385 register int regno;
386 register int mask = 0;
387 int num_saved_regs = 0;
388 extern char call_used_regs[];
08c148a8
NB
389 HOST_WIDE_INT fsize = (size + 3) & -4;
390 HOST_WIDE_INT cfa_offset = INCOMING_FRAME_SP_OFFSET;
391 HOST_WIDE_INT cfa_store_offset = cfa_offset;
79e68feb 392
a157febd
GK
393 /* If the stack limit is a symbol, we can check it here,
394 before actually allocating the space. */
395 if (current_function_limit_stack
396 && GET_CODE (stack_limit_rtx) == SYMBOL_REF)
397 {
398#if defined (MOTOROLA)
399 asm_fprintf (stream, "\tcmp.l %0I%s+%d,%Rsp\n\ttrapcs\n",
400 XSTR (stack_limit_rtx, 0), fsize + 4);
401#else
402 asm_fprintf (stream, "\tcmpl %0I%s+%d,%Rsp\n\ttrapcs\n",
403 XSTR (stack_limit_rtx, 0), fsize + 4);
404#endif
405 }
79e68feb
RS
406
407 if (frame_pointer_needed)
408 {
2d0933a2 409 if (fsize == 0 && TARGET_68040)
e4e873f1
RK
410 {
411 /* on the 68040, pea + move is faster than link.w 0 */
412#ifdef MOTOROLA
413 asm_fprintf (stream, "\tpea (%s)\n\tmove.l %s,%s\n",
414 reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM],
415 reg_names[FRAME_POINTER_REGNUM]);
416#else
2d0933a2 417 asm_fprintf (stream, "\tpea %s@\n\tmovel %s,%s\n",
e4e873f1
RK
418 reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM],
419 reg_names[FRAME_POINTER_REGNUM]);
420#endif
421 }
422 else if (fsize < 0x8000)
79e68feb
RS
423 {
424#ifdef MOTOROLA
338818c7 425 asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
79e68feb
RS
426 reg_names[FRAME_POINTER_REGNUM], -fsize);
427#else
338818c7 428 asm_fprintf (stream, "\tlink %s,%0I%d\n",
79e68feb
RS
429 reg_names[FRAME_POINTER_REGNUM], -fsize);
430#endif
431 }
432 else if (TARGET_68020)
433 {
434#ifdef MOTOROLA
338818c7 435 asm_fprintf (stream, "\tlink.l %s,%0I%d\n",
79e68feb
RS
436 reg_names[FRAME_POINTER_REGNUM], -fsize);
437#else
338818c7 438 asm_fprintf (stream, "\tlink %s,%0I%d\n",
79e68feb
RS
439 reg_names[FRAME_POINTER_REGNUM], -fsize);
440#endif
441 }
442 else
443 {
e4e873f1 444 /* Adding negative number is faster on the 68040. */
79e68feb 445#ifdef MOTOROLA
cffd0d74 446 asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n",
79e68feb
RS
447 reg_names[FRAME_POINTER_REGNUM], -fsize);
448#else
cffd0d74 449 asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n",
79e68feb
RS
450 reg_names[FRAME_POINTER_REGNUM], -fsize);
451#endif
452 }
078e983e
AS
453 if (dwarf2out_do_frame ())
454 {
f5c4bc60
BM
455 char *l;
456 l = (char *) dwarf2out_cfi_label ();
078e983e
AS
457 cfa_store_offset += 4;
458 cfa_offset = cfa_store_offset;
078e983e 459 dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, -cfa_store_offset);
67935d3f 460 dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, cfa_offset);
078e983e
AS
461 cfa_store_offset += fsize;
462 }
79e68feb
RS
463 }
464 else if (fsize)
465 {
afaff477 466 if (fsize + 4 < 0x8000)
79e68feb 467 {
b0e982be 468#ifndef NO_ADDSUB_Q
7bc88d49 469 if (fsize + 4 <= 8)
afaff477 470 {
7bc88d49
RK
471 if (!TARGET_5200)
472 {
7a1929e1 473 /* asm_fprintf() cannot handle %. */
2d0933a2 474#ifdef MOTOROLA
b0e982be 475 asm_fprintf (stream, "\tsubq.w %0I%d,%Rsp\n", fsize + 4);
2d0933a2 476#else
b0e982be 477 asm_fprintf (stream, "\tsubqw %0I%d,%Rsp\n", fsize + 4);
2d0933a2 478#endif
7bc88d49
RK
479 }
480 else
481 {
7a1929e1 482 /* asm_fprintf() cannot handle %. */
7bc88d49 483#ifdef MOTOROLA
b0e982be 484 asm_fprintf (stream, "\tsubq.l %0I%d,%Rsp\n", fsize + 4);
7bc88d49 485#else
b0e982be 486 asm_fprintf (stream, "\tsubql %0I%d,%Rsp\n", fsize + 4);
7bc88d49
RK
487#endif
488 }
afaff477 489 }
7bc88d49
RK
490 else if (fsize + 4 <= 16 && TARGET_CPU32)
491 {
492 /* On the CPU32 it is faster to use two subqw instructions to
7a1929e1
KH
493 subtract a small integer (8 < N <= 16) to a register. */
494 /* asm_fprintf() cannot handle %. */
7bc88d49 495#ifdef MOTOROLA
b0e982be 496 asm_fprintf (stream, "\tsubq.w %0I8,%Rsp\n\tsubq.w %0I%d,%Rsp\n",
63429dd7 497 fsize + 4 - 8);
7bc88d49 498#else
b0e982be 499 asm_fprintf (stream, "\tsubqw %0I8,%Rsp\n\tsubqw %0I%d,%Rsp\n",
63429dd7 500 fsize + 4 - 8);
7bc88d49
RK
501#endif
502 }
503 else
b0e982be 504#endif /* not NO_ADDSUB_Q */
7bc88d49 505 if (TARGET_68040)
afaff477 506 {
7bc88d49 507 /* Adding negative number is faster on the 68040. */
7a1929e1 508 /* asm_fprintf() cannot handle %. */
afaff477
RK
509#ifdef MOTOROLA
510 asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
511#else
512 asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
7bc88d49
RK
513#endif
514 }
515 else
516 {
7bc88d49
RK
517#ifdef MOTOROLA
518 asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", - (fsize + 4));
519#else
520 asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", - (fsize + 4));
afaff477
RK
521#endif
522 }
79e68feb
RS
523 }
524 else
525 {
7a1929e1 526 /* asm_fprintf() cannot handle %. */
2d0933a2
RK
527#ifdef MOTOROLA
528 asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));
529#else
530 asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4));
531#endif
79e68feb 532 }
078e983e
AS
533 if (dwarf2out_do_frame ())
534 {
535 cfa_store_offset += fsize;
536 cfa_offset = cfa_store_offset;
537 dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
538 }
79e68feb
RS
539 }
540#ifdef SUPPORT_SUN_FPA
541 for (regno = 24; regno < 56; regno++)
542 if (regs_ever_live[regno] && ! call_used_regs[regno])
543 {
544#ifdef MOTOROLA
545 asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
546 reg_names[regno]);
547#else
548 asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n",
549 reg_names[regno]);
550#endif
078e983e
AS
551 if (dwarf2out_do_frame ())
552 {
a7cc7f29
AS
553 char *l = dwarf2out_cfi_label ();
554
078e983e
AS
555 cfa_store_offset += 8;
556 if (! frame_pointer_needed)
557 {
558 cfa_offset = cfa_store_offset;
559 dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
560 }
561 dwarf2out_reg_save (l, regno, -cfa_store_offset);
562 }
79e68feb
RS
563 }
564#endif
f277471f 565 if (TARGET_68881)
79e68feb 566 {
f277471f
RK
567 for (regno = 16; regno < 24; regno++)
568 if (regs_ever_live[regno] && ! call_used_regs[regno])
078e983e
AS
569 {
570 mask |= 1 << (regno - 16);
571 num_saved_regs++;
572 }
f277471f
RK
573 if ((mask & 0xff) != 0)
574 {
79e68feb 575#ifdef MOTOROLA
f277471f 576 asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
79e68feb 577#else
f277471f 578 asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
79e68feb 579#endif
078e983e
AS
580 if (dwarf2out_do_frame ())
581 {
f5c4bc60 582 char *l = (char *) dwarf2out_cfi_label ();
078e983e 583 int n_regs;
a7cc7f29 584
078e983e
AS
585 cfa_store_offset += num_saved_regs * 12;
586 if (! frame_pointer_needed)
587 {
588 cfa_offset = cfa_store_offset;
589 dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
590 }
591 for (regno = 16, n_regs = 0; regno < 24; regno++)
592 if (mask & (1 << (regno - 16)))
593 dwarf2out_reg_save (l, regno,
594 -cfa_store_offset + n_regs++ * 12);
595 }
f277471f
RK
596 }
597 mask = 0;
078e983e 598 num_saved_regs = 0;
79e68feb 599 }
79e68feb
RS
600 for (regno = 0; regno < 16; regno++)
601 if (regs_ever_live[regno] && ! call_used_regs[regno])
602 {
603 mask |= 1 << (15 - regno);
604 num_saved_regs++;
605 }
606 if (frame_pointer_needed)
607 {
608 mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
609 num_saved_regs--;
610 }
6e8313fe 611 if (flag_pic && current_function_uses_pic_offset_table)
df59fef7
JL
612 {
613 mask |= 1 << (15 - PIC_OFFSET_TABLE_REGNUM);
614 num_saved_regs++;
615 }
99df2465
RS
616
617#if NEED_PROBE
a7e2b014 618#ifdef MOTOROLA
a7e2b014 619 asm_fprintf (stream, "\ttst.l %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);
a7e2b014 620#else
81bd5278 621 asm_fprintf (stream, "\ttstl %Rsp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
a7e2b014 622#endif
99df2465
RS
623#endif
624
a157febd
GK
625 /* If the stack limit is not a symbol, check it here.
626 This has the disadvantage that it may be too late... */
627 if (current_function_limit_stack)
628 {
629 if (REG_P (stack_limit_rtx))
630 {
631#if defined (MOTOROLA)
632 asm_fprintf (stream, "\tcmp.l %s,%Rsp\n\ttrapcs\n",
633 reg_names[REGNO (stack_limit_rtx)]);
634#else
635 asm_fprintf (stream, "\tcmpl %s,%Rsp\n\ttrapcs\n",
636 reg_names[REGNO (stack_limit_rtx)]);
637#endif
638 }
639 else if (GET_CODE (stack_limit_rtx) != SYMBOL_REF)
640 warning ("stack limit expression is not supported");
641 }
642
79e68feb
RS
643 if (num_saved_regs <= 2)
644 {
645 /* Store each separately in the same order moveml uses.
646 Using two movel instructions instead of a single moveml
647 is about 15% faster for the 68020 and 68030 at no expense
648 in code size */
649
650 int i;
651
7a1929e1 652 /* Undo the work from above. */
79e68feb
RS
653 for (i = 0; i< 16; i++)
654 if (mask & (1 << i))
078e983e
AS
655 {
656 asm_fprintf (stream,
79e68feb 657#ifdef MOTOROLA
078e983e 658 "\t%Omove.l %s,-(%Rsp)\n",
79e68feb 659#else
078e983e 660 "\tmovel %s,%Rsp@-\n",
79e68feb 661#endif
078e983e
AS
662 reg_names[15 - i]);
663 if (dwarf2out_do_frame ())
664 {
f5c4bc60 665 char *l = (char *) dwarf2out_cfi_label ();
a7cc7f29 666
078e983e
AS
667 cfa_store_offset += 4;
668 if (! frame_pointer_needed)
669 {
670 cfa_offset = cfa_store_offset;
671 dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
672 }
673 dwarf2out_reg_save (l, 15 - i, -cfa_store_offset);
674 }
675 }
79e68feb
RS
676 }
677 else if (mask)
678 {
afaff477
RK
679 if (TARGET_5200)
680 {
681 /* The coldfire does not support the predecrement form of the
682 movml instruction, so we must adjust the stack pointer and
683 then use the plain address register indirect mode. We also
684 have to invert the register save mask to use the new mode.
685
686 FIXME: if num_saved_regs was calculated earlier, we could
687 combine the stack pointer adjustment with any adjustment
688 done when the initial stack frame is created. This would
689 save an instruction */
690
691 int newmask = 0;
692 int i;
693
694 for (i = 0; i < 16; i++)
695 if (mask & (1 << i))
696 newmask |= (1 << (15-i));
697
698#ifdef MOTOROLA
de649959 699 asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", -num_saved_regs*4);
afaff477
RK
700 asm_fprintf (stream, "\tmovm.l %0I0x%x,(%Rsp)\n", newmask);
701#else
de649959 702 asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", -num_saved_regs*4);
afaff477
RK
703 asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@\n", newmask);
704#endif
705 }
706 else
707 {
79e68feb 708#ifdef MOTOROLA
afaff477 709 asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
79e68feb 710#else
afaff477 711 asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
79e68feb 712#endif
afaff477 713 }
078e983e
AS
714 if (dwarf2out_do_frame ())
715 {
f5c4bc60 716 char *l = (char *) dwarf2out_cfi_label ();
078e983e 717 int n_regs;
a7cc7f29 718
078e983e
AS
719 cfa_store_offset += num_saved_regs * 4;
720 if (! frame_pointer_needed)
721 {
722 cfa_offset = cfa_store_offset;
723 dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
724 }
725 for (regno = 0, n_regs = 0; regno < 16; regno++)
726 if (mask & (1 << (15 - regno)))
727 dwarf2out_reg_save (l, regno,
728 -cfa_store_offset + n_regs++ * 4);
729 }
79e68feb
RS
730 }
731 if (flag_pic && current_function_uses_pic_offset_table)
732 {
733#ifdef MOTOROLA
66c432a7 734 asm_fprintf (stream, "\t%Olea (%Rpc, %U_GLOBAL_OFFSET_TABLE_@GOTPC), %s\n",
79e68feb
RS
735 reg_names[PIC_OFFSET_TABLE_REGNUM]);
736#else
cffd0d74 737 asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n",
79e68feb
RS
738 reg_names[PIC_OFFSET_TABLE_REGNUM]);
739 asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n",
740 reg_names[PIC_OFFSET_TABLE_REGNUM],
741 reg_names[PIC_OFFSET_TABLE_REGNUM]);
742#endif
743 }
744}
08c148a8
NB
745#endif /* ! (DPX2 && MOTOROLA) */
746#endif /* ! (NEWS && MOTOROLA) */
747#endif /* !CRDS */
79e68feb
RS
748\f
749/* Return true if this function's epilogue can be output as RTL. */
750
751int
752use_return_insn ()
753{
754 int regno;
755
756 if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
757 return 0;
758
759 /* Copied from output_function_epilogue (). We should probably create a
760 separate layout routine to perform the common work. */
761
762 for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
763 if (regs_ever_live[regno] && ! call_used_regs[regno])
764 return 0;
125ed86f
AS
765
766 if (flag_pic && current_function_uses_pic_offset_table)
767 return 0;
768
79e68feb
RS
769 return 1;
770}
771
772/* This function generates the assembly code for function exit,
08c148a8 773 on machines that need it.
79e68feb
RS
774
775 The function epilogue should not depend on the current stack pointer!
776 It should use the frame pointer only, if there is a frame pointer.
777 This is mandatory because of alloca; we also take advantage of it to
778 omit stack adjustments before returning. */
779
08c148a8
NB
780#ifdef CRDS
781
782static void
783m68k_output_function_epilogue (stream, size)
79e68feb 784 FILE *stream;
08c148a8 785 HOST_WIDE_INT size;
79e68feb
RS
786{
787 register int regno;
788 register int mask, fmask;
789 register int nregs;
08c148a8 790 HOST_WIDE_INT offset, foffset, fpoffset;
79e68feb 791 extern char call_used_regs[];
08c148a8
NB
792 HOST_WIDE_INT fsize = ((size) + 3) & -4;
793 int big = 0;
794
795 nregs = 0; fmask = 0; fpoffset = 0;
796 for (regno = 16; regno < 24; regno++)
797 if (regs_ever_live[regno] && ! call_used_regs[regno])
798 {
799 nregs++;
800 fmask |= 1 << (23 - regno);
801 }
802
803 foffset = fpoffset + nregs * 12;
804 nregs = 0; mask = 0;
805 if (frame_pointer_needed)
806 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
807
808 for (regno = 0; regno < 16; regno++)
809 if (regs_ever_live[regno] && ! call_used_regs[regno])
810 {
811 nregs++;
812 mask |= 1 << regno;
813 }
814
815 offset = foffset + nregs * 4;
816 if (offset + fsize >= 0x8000
817 && frame_pointer_needed
818 && (mask || fmask || fpoffset))
819 {
820 fprintf (stream, "\tmovel $%d,a0\n", -fsize);
821 fsize = 0, big = 1;
822 }
823
824 if (exact_log2 (mask) >= 0)
825 {
826 if (big)
827 fprintf (stream, "\tmovel -%d(a6,a0.l),%s\n",
828 offset + fsize, reg_names[exact_log2 (mask)]);
829 else if (! frame_pointer_needed)
830 fprintf (stream, "\tmovel (sp)+,%s\n",
831 reg_names[exact_log2 (mask)]);
832 else
833 fprintf (stream, "\tmovel -%d(a6),%s\n",
834 offset + fsize, reg_names[exact_log2 (mask)]);
835 }
836 else if (mask)
837 {
838 if (big)
839 fprintf (stream, "\tmovem -%d(a6,a0.l),$0x%x\n",
840 offset + fsize, mask);
841 else if (! frame_pointer_needed)
842 fprintf (stream, "\tmovem (sp)+,$0x%x\n", mask);
843 else
844 fprintf (stream, "\tmovem -%d(a6),$0x%x\n",
845 offset + fsize, mask);
846 }
847
848 if (fmask)
849 {
850 if (big)
851 fprintf (stream, "\tfmovem -%d(a6,a0.l),$0x%x\n",
852 foffset + fsize, fmask);
853 else if (! frame_pointer_needed)
854 fprintf (stream, "\tfmovem (sp)+,$0x%x\n", fmask);
855 else
856 fprintf (stream, "\tfmovem -%d(a6),$0x%x\n",
857 foffset + fsize, fmask);
858 }
859
860 if (fpoffset != 0)
861 for (regno = 55; regno >= 24; regno--)
862 if (regs_ever_live[regno] && ! call_used_regs[regno])
863 {
864 if (big)
865 fprintf(stream, "\tfpmoved -%d(a6,a0.l), %s\n",
866 fpoffset + fsize, reg_names[regno]);
867 else if (! frame_pointer_needed)
868 fprintf(stream, "\tfpmoved (sp)+, %s\n",
869 reg_names[regno]);
870 else
871 fprintf(stream, "\tfpmoved -%d(a6), %s\n",
872 fpoffset + fsize, reg_names[regno]);
873 fpoffset -= 8;
874 }
875
876 if (frame_pointer_needed)
877 fprintf (stream, "\tunlk a6\n");
878 else if (fsize)
879 {
880 if (fsize + 4 < 0x8000)
881 fprintf (stream, "\tadd.w #%d,sp\n", fsize + 4);
882 else
883 fprintf (stream, "\tadd.l #%d,sp\n", fsize + 4);
884 }
885
886 if (current_function_pops_args)
887 fprintf (stream, "\trtd $%d\n", current_function_pops_args);
888 else
889 fprintf (stream, "\trts\n");
890}
891
892#else
893#if defined (DPX2) && defined (MOTOROLA)
894
895static void
896m68k_output_function_epilogue (stream, size)
897 FILE *stream;
898 HOST_WIDE_INT size;
899{
900 register int regno;
901 register int mask, fmask;
902 register int nregs;
903 HOST_WIDE_INT offset, foffset, fpoffset, first = 1;
904 extern char call_used_regs[];
905 HOST_WIDE_INT fsize = ((size) + 3) & -4;
906 int big = 0;
907 rtx insn = get_last_insn ();
908
909 /* If the last insn was a BARRIER, we don't have to write any code. */
910 if (GET_CODE (insn) == NOTE)
911 insn = prev_nonnote_insn (insn);
912 if (insn && GET_CODE (insn) == BARRIER)
913 {
914 /* Output just a no-op so that debuggers don't get confused
915 about which function the pc is in at this address. */
916 fprintf (stream, "\tnop\n");
917 return;
918 }
919
920 nregs = 0; fmask = 0; fpoffset = 0;
921 for (regno = 16; regno < 24; regno++)
922 if (regs_ever_live[regno] && ! call_used_regs[regno])
923 {
924 nregs++;
925 fmask |= 1 << (23 - regno);
926 }
927
928 foffset = fpoffset + nregs * 12;
929 nregs = 0; mask = 0;
930 if (frame_pointer_needed)
931 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
932
933 for (regno = 0; regno < 16; regno++)
934 if (regs_ever_live[regno] && ! call_used_regs[regno])
935 {
936 nregs++;
937 mask |= 1 << regno;
938 }
939
940 offset = foffset + nregs * 4;
941 if (offset + fsize >= 0x8000
942 && frame_pointer_needed
943 && (mask || fmask || fpoffset))
944 {
945 fprintf (stream, "\tmove.l #%d,a0\n", -fsize);
946 fsize = 0, big = 1;
947 }
948
949 if (nregs <= 2)
950 {
951 /* Restore each separately in the same order moveml does.
952 Using two movel instructions instead of a single moveml
953 is about 15% faster for the 68020 and 68030 at no expense
7a1929e1 954 in code size. */
08c148a8
NB
955
956 int i;
957
7a1929e1 958 /* Undo the work from above. */
08c148a8
NB
959 for (i = 0; i< 16; i++)
960 if (mask & (1 << i))
961 {
962 if (big)
963 fprintf (stream, "\tmove.l -%d(%s,a0.l),%s\n",
964 offset + fsize,
965 reg_names[FRAME_POINTER_REGNUM],
966 reg_names[i]);
967 else if (! frame_pointer_needed)
968 fprintf (stream, "\tmove.l (sp)+,%s\n",
969 reg_names[i]);
970 else
971 fprintf (stream, "\tmove.l -%d(%s),%s\n",
972 offset + fsize,
973 reg_names[FRAME_POINTER_REGNUM],
974 reg_names[i]);
975 offset = offset - 4;
976 }
977 }
978 else if (mask)
979 {
980 first = 1;
981 for (regno = 0; regno < 16; regno++)
982 if (mask & (1 << regno))
983 {
984 if (first && big)
985 {
986 fprintf (stream, "\tmovem.l -%d(%s,a0.l),%s",
987 offset + fsize,
988 reg_names[FRAME_POINTER_REGNUM],
989 reg_names[regno]);
990 first = 0;
991 }
992 else if (first && ! frame_pointer_needed)
993 {
994 fprintf (stream, "\tmovem.l (sp)+,%s",
995 reg_names[regno]);
996 first = 0;
997 }
998 else if (first)
999 {
1000 fprintf (stream, "\tmovem.l -%d(%s),%s",
1001 offset + fsize,
1002 reg_names[FRAME_POINTER_REGNUM],
1003 reg_names[regno]);
1004 first = 0;
1005 }
1006 else
1007 fprintf (stream, "/%s", reg_names[regno]);
1008 }
1009 fprintf (stream, "\n");
1010 }
1011
1012 if (fmask)
1013 {
1014 first = 1;
1015 for (regno = 16; regno < 24; regno++)
1016 if (fmask & (1 << (23 - regno)))
1017 {
1018 if (first && big)
1019 {
1020 fprintf (stream, "\tfmovem.x -%d(%s,a0.l),%s",
1021 foffset + fsize,
1022 reg_names[FRAME_POINTER_REGNUM],
1023 reg_names[regno]);
1024 first = 0;
1025 }
1026 else if (first && ! frame_pointer_needed)
1027 {
1028 fprintf (stream, "\tfmovem.x (sp)+,%s",
1029 reg_names[regno]);
1030 first = 0;
1031 }
1032 else if (first)
1033 {
1034 fprintf (stream, "\tfmovem.x -%d(%s),%s",
1035 foffset + fsize,
1036 reg_names[FRAME_POINTER_REGNUM],
1037 reg_names[regno]);
1038 first = 0;
1039 }
1040 else
1041 fprintf (stream, "/%s", reg_names[regno]);
1042 }
1043 fprintf (stream, "\n");
1044 }
1045
1046 if (frame_pointer_needed)
1047 fprintf (stream, "\tunlk %s\n",
1048 reg_names[FRAME_POINTER_REGNUM]);
1049 else if (fsize)
1050 {
1051 if (fsize + 4 < 0x8000)
1052 fprintf (stream, "\tadd.w #%d,sp\n", fsize + 4);
1053 else
1054 fprintf (stream, "\tadd.l #%d,sp\n", fsize + 4);
1055 }
1056
1057 if (current_function_pops_args)
1058 fprintf (stream, "\trtd #%d\n", current_function_pops_args);
1059 else
1060 fprintf (stream, "\trts\n");
1061}
1062
1063#else
1064#if defined (NEWS) && defined (MOTOROLA)
1065
1066static void
1067m68k_output_function_epilogue (stream, size)
1068 FILE *stream;
1069 HOST_WIDE_INT size;
1070{
1071 register int regno;
1072 register int mask, fmask;
1073 register int nregs;
1074 HOST_WIDE_INT offset, foffset;
1075 extern char call_used_regs[];
1076 HOST_WIDE_INT fsize = ((size) + 3) & -4;
1077 int big = 0;
1078
1079 nregs = 0; fmask = 0;
1080 for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++)
1081 if (regs_ever_live[regno] && ! call_used_regs[regno])
1082 {
1083 nregs++;
1084 fmask |= 1 << (23 - regno);
1085 }
1086
1087 foffset = nregs * 12;
1088 nregs = 0; mask = 0;
1089 if (frame_pointer_needed)
1090 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
1091
1092 for (regno = 0; regno < 16; regno++)
1093 if (regs_ever_live[regno] && ! call_used_regs[regno])
1094 {
1095 nregs++;
1096 mask |= 1 << regno;
1097 }
1098
1099 offset = foffset + nregs * 4;
1100 if (offset + fsize >= 0x8000
1101 && frame_pointer_needed
1102 && (mask || fmask))
1103 {
1104 fprintf (stream, "\tmove.l #%d,a0\n", -fsize);
1105 fsize = 0, big = 1;
1106 }
1107
1108 if (exact_log2 (mask) >= 0)
1109 {
1110 if (big)
1111 fprintf (stream, "\tmove.l (-%d,fp,a0.l),%s\n",
1112 offset + fsize, reg_names[exact_log2 (mask)]);
1113 else if (! frame_pointer_needed)
1114 fprintf (stream, "\tmove.l (sp)+,%s\n",
1115 reg_names[exact_log2 (mask)]);
1116 else
1117 fprintf (stream, "\tmove.l (-%d,fp),%s\n",
1118 offset + fsize, reg_names[exact_log2 (mask)]);
1119 }
1120 else if (mask)
1121 {
1122 if (big)
1123 fprintf (stream, "\tmovem.l (-%d,fp,a0.l),#0x%x\n",
1124 offset + fsize, mask);
1125 else if (! frame_pointer_needed)
1126 fprintf (stream, "\tmovem.l (sp)+,#0x%x\n", mask);
1127 else
1128 fprintf (stream, "\tmovem.l (-%d,fp),#0x%x\n",
1129 offset + fsize, mask);
1130 }
1131
1132 if (fmask)
1133 {
1134 if (big)
1135 fprintf (stream, "\tfmovem.x (-%d,fp,a0.l),#0x%x\n",
1136 foffset + fsize, fmask);
1137 else if (! frame_pointer_needed)
1138 fprintf (stream, "\tfmovem.x (sp)+,#0x%x\n", fmask);
1139 else
1140 fprintf (stream, "\tfmovem.x (-%d,fp),#0x%x\n",
1141 foffset + fsize, fmask);
1142 }
1143
1144 if (frame_pointer_needed)
1145 fprintf (stream, "\tunlk fp\n");
1146 else if (fsize)
1147 {
1148 if (fsize + 4 < 0x8000)
1149 fprintf (stream, "\tadd.w #%d,sp\n", fsize + 4);
1150 else
1151 fprintf (stream, "\tadd.l #%d,sp\n", fsize + 4);
1152 }
1153
1154 if (current_function_pops_args)
1155 fprintf (stream, "\trtd #%d\n", current_function_pops_args);
1156 else
1157 fprintf (stream, "\trts\n");
1158}
1159
1160#else /* !CRDS && ! (NEWS && MOTOROLA) && ! (DPX2 && MOTOROLA) */
1161
1162static void
1163m68k_output_function_epilogue (stream, size)
1164 FILE *stream;
1165 HOST_WIDE_INT size;
1166{
1167 register int regno;
1168 register int mask, fmask;
1169 register int nregs;
1170 HOST_WIDE_INT offset, foffset, fpoffset;
1171 extern char call_used_regs[];
1172 HOST_WIDE_INT fsize = (size + 3) & -4;
79e68feb
RS
1173 int big = 0;
1174 rtx insn = get_last_insn ();
6910dd70 1175 int restore_from_sp = 0;
79e68feb
RS
1176
1177 /* If the last insn was a BARRIER, we don't have to write any code. */
1178 if (GET_CODE (insn) == NOTE)
1179 insn = prev_nonnote_insn (insn);
1180 if (insn && GET_CODE (insn) == BARRIER)
cffd0d74
RS
1181 {
1182 /* Output just a no-op so that debuggers don't get confused
1183 about which function the pc is in at this address. */
1184 asm_fprintf (stream, "\tnop\n");
1185 return;
1186 }
79e68feb
RS
1187
1188#ifdef FUNCTION_EXTRA_EPILOGUE
1189 FUNCTION_EXTRA_EPILOGUE (stream, size);
1190#endif
1191 nregs = 0; fmask = 0; fpoffset = 0;
1192#ifdef SUPPORT_SUN_FPA
1193 for (regno = 24 ; regno < 56 ; regno++)
1194 if (regs_ever_live[regno] && ! call_used_regs[regno])
1195 nregs++;
1196 fpoffset = nregs * 8;
1197#endif
1198 nregs = 0;
f277471f
RK
1199 if (TARGET_68881)
1200 {
1201 for (regno = 16; regno < 24; regno++)
1202 if (regs_ever_live[regno] && ! call_used_regs[regno])
1203 {
1204 nregs++;
1205 fmask |= 1 << (23 - regno);
1206 }
1207 }
79e68feb
RS
1208 foffset = fpoffset + nregs * 12;
1209 nregs = 0; mask = 0;
1210 if (frame_pointer_needed)
1211 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
1212 for (regno = 0; regno < 16; regno++)
1213 if (regs_ever_live[regno] && ! call_used_regs[regno])
1214 {
1215 nregs++;
1216 mask |= 1 << regno;
1217 }
6e8313fe 1218 if (flag_pic && current_function_uses_pic_offset_table)
8f9f5b12
RH
1219 {
1220 nregs++;
1221 mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
1222 }
79e68feb 1223 offset = foffset + nregs * 4;
c67ddce5
RK
1224 /* FIXME : leaf_function_p below is too strong.
1225 What we really need to know there is if there could be pending
7a1929e1 1226 stack adjustment needed at that point. */
6910dd70
RK
1227 restore_from_sp = ! frame_pointer_needed
1228 || (! current_function_calls_alloca && leaf_function_p ());
79e68feb 1229 if (offset + fsize >= 0x8000
6910dd70 1230 && ! restore_from_sp
79e68feb
RS
1231 && (mask || fmask || fpoffset))
1232 {
1233#ifdef MOTOROLA
e7eefaec 1234 asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize);
79e68feb 1235#else
e7eefaec 1236 asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize);
79e68feb
RS
1237#endif
1238 fsize = 0, big = 1;
1239 }
afaff477 1240 if (TARGET_5200 || nregs <= 2)
79e68feb
RS
1241 {
1242 /* Restore each separately in the same order moveml does.
1243 Using two movel instructions instead of a single moveml
1244 is about 15% faster for the 68020 and 68030 at no expense
7a1929e1 1245 in code size. */
79e68feb
RS
1246
1247 int i;
1248
7a1929e1 1249 /* Undo the work from above. */
79e68feb
RS
1250 for (i = 0; i< 16; i++)
1251 if (mask & (1 << i))
1252 {
1253 if (big)
1254 {
1255#ifdef MOTOROLA
e7eefaec 1256 asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra1.l),%s\n",
79e68feb
RS
1257 offset + fsize,
1258 reg_names[FRAME_POINTER_REGNUM],
1259 reg_names[i]);
1260#else
e7eefaec 1261 asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n",
79e68feb
RS
1262 reg_names[FRAME_POINTER_REGNUM],
1263 offset + fsize, reg_names[i]);
1264#endif
1265 }
6910dd70 1266 else if (restore_from_sp)
79e68feb
RS
1267 {
1268#ifdef MOTOROLA
64a184e9 1269 asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n",
79e68feb
RS
1270 reg_names[i]);
1271#else
1272 asm_fprintf (stream, "\tmovel %Rsp@+,%s\n",
1273 reg_names[i]);
1274#endif
1275 }
1276 else
1277 {
1278#ifdef MOTOROLA
64a184e9 1279 asm_fprintf (stream, "\t%Omove.l -%d(%s),%s\n",
79e68feb
RS
1280 offset + fsize,
1281 reg_names[FRAME_POINTER_REGNUM],
1282 reg_names[i]);
1283#else
1284 asm_fprintf (stream, "\tmovel %s@(-%d),%s\n",
1285 reg_names[FRAME_POINTER_REGNUM],
1286 offset + fsize, reg_names[i]);
1287#endif
1288 }
1289 offset = offset - 4;
1290 }
1291 }
1292 else if (mask)
1293 {
1294 if (big)
1295 {
1296#ifdef MOTOROLA
e7eefaec 1297 asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n",
79e68feb
RS
1298 offset + fsize,
1299 reg_names[FRAME_POINTER_REGNUM],
1300 mask);
1301#else
e7eefaec 1302 asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n",
79e68feb
RS
1303 reg_names[FRAME_POINTER_REGNUM],
1304 offset + fsize, mask);
1305#endif
1306 }
6910dd70 1307 else if (restore_from_sp)
79e68feb
RS
1308 {
1309#ifdef MOTOROLA
cffd0d74 1310 asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);
79e68feb 1311#else
cffd0d74 1312 asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask);
79e68feb
RS
1313#endif
1314 }
1315 else
1316 {
1317#ifdef MOTOROLA
cffd0d74 1318 asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n",
79e68feb
RS
1319 offset + fsize,
1320 reg_names[FRAME_POINTER_REGNUM],
1321 mask);
1322#else
cffd0d74 1323 asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n",
79e68feb
RS
1324 reg_names[FRAME_POINTER_REGNUM],
1325 offset + fsize, mask);
1326#endif
1327 }
1328 }
1329 if (fmask)
1330 {
1331 if (big)
1332 {
1333#ifdef MOTOROLA
e7eefaec 1334 asm_fprintf (stream, "\tfmovm -%d(%s,%Ra1.l),%0I0x%x\n",
79e68feb
RS
1335 foffset + fsize,
1336 reg_names[FRAME_POINTER_REGNUM],
1337 fmask);
1338#else
e7eefaec 1339 asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n",
79e68feb
RS
1340 reg_names[FRAME_POINTER_REGNUM],
1341 foffset + fsize, fmask);
1342#endif
1343 }
6910dd70 1344 else if (restore_from_sp)
79e68feb
RS
1345 {
1346#ifdef MOTOROLA
cffd0d74 1347 asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask);
79e68feb 1348#else
cffd0d74 1349 asm_fprintf (stream, "\tfmovem %Rsp@+,%0I0x%x\n", fmask);
79e68feb
RS
1350#endif
1351 }
1352 else
1353 {
1354#ifdef MOTOROLA
cffd0d74 1355 asm_fprintf (stream, "\tfmovm -%d(%s),%0I0x%x\n",
79e68feb
RS
1356 foffset + fsize,
1357 reg_names[FRAME_POINTER_REGNUM],
1358 fmask);
1359#else
cffd0d74 1360 asm_fprintf (stream, "\tfmovem %s@(-%d),%0I0x%x\n",
79e68feb
RS
1361 reg_names[FRAME_POINTER_REGNUM],
1362 foffset + fsize, fmask);
1363#endif
1364 }
1365 }
1366 if (fpoffset != 0)
1367 for (regno = 55; regno >= 24; regno--)
1368 if (regs_ever_live[regno] && ! call_used_regs[regno])
1369 {
1370 if (big)
1371 {
1372#ifdef MOTOROLA
e7eefaec 1373 asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra1.l), %s\n",
79e68feb
RS
1374 fpoffset + fsize,
1375 reg_names[FRAME_POINTER_REGNUM],
1376 reg_names[regno]);
1377#else
e7eefaec 1378 asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n",
79e68feb
RS
1379 reg_names[FRAME_POINTER_REGNUM],
1380 fpoffset + fsize, reg_names[regno]);
1381#endif
1382 }
6910dd70 1383 else if (restore_from_sp)
79e68feb
RS
1384 {
1385#ifdef MOTOROLA
1386 asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n",
1387 reg_names[regno]);
1388#else
1389 asm_fprintf (stream, "\tfpmoved %Rsp@+, %s\n",
1390 reg_names[regno]);
1391#endif
1392 }
1393 else
1394 {
1395#ifdef MOTOROLA
1396 asm_fprintf (stream, "\tfpmovd -%d(%s), %s\n",
1397 fpoffset + fsize,
1398 reg_names[FRAME_POINTER_REGNUM],
1399 reg_names[regno]);
1400#else
1401 asm_fprintf (stream, "\tfpmoved %s@(-%d), %s\n",
1402 reg_names[FRAME_POINTER_REGNUM],
1403 fpoffset + fsize, reg_names[regno]);
1404#endif
1405 }
1406 fpoffset -= 8;
1407 }
1408 if (frame_pointer_needed)
1409 fprintf (stream, "\tunlk %s\n",
1410 reg_names[FRAME_POINTER_REGNUM]);
1411 else if (fsize)
1412 {
b0e982be 1413#ifndef NO_ADDSUB_Q
7bc88d49 1414 if (fsize + 4 <= 8)
79e68feb 1415 {
7bc88d49
RK
1416 if (!TARGET_5200)
1417 {
2d0933a2 1418#ifdef MOTOROLA
b0e982be 1419 asm_fprintf (stream, "\taddq.w %0I%d,%Rsp\n", fsize + 4);
2d0933a2 1420#else
b0e982be 1421 asm_fprintf (stream, "\taddqw %0I%d,%Rsp\n", fsize + 4);
2d0933a2 1422#endif
afaff477
RK
1423 }
1424 else
1425 {
7bc88d49 1426#ifdef MOTOROLA
b0e982be 1427 asm_fprintf (stream, "\taddq.l %0I%d,%Rsp\n", fsize + 4);
7bc88d49 1428#else
b0e982be 1429 asm_fprintf (stream, "\taddql %0I%d,%Rsp\n", fsize + 4);
7bc88d49
RK
1430#endif
1431 }
1432 }
1433 else if (fsize + 4 <= 16 && TARGET_CPU32)
1434 {
1435 /* On the CPU32 it is faster to use two addqw instructions to
7a1929e1
KH
1436 add a small integer (8 < N <= 16) to a register. */
1437 /* asm_fprintf() cannot handle %. */
7bc88d49 1438#ifdef MOTOROLA
b0e982be 1439 asm_fprintf (stream, "\taddq.w %0I8,%Rsp\n\taddq.w %0I%d,%Rsp\n",
63429dd7 1440 fsize + 4 - 8);
7bc88d49 1441#else
b0e982be 1442 asm_fprintf (stream, "\taddqw %0I8,%Rsp\n\taddqw %0I%d,%Rsp\n",
63429dd7 1443 fsize + 4 - 8);
7bc88d49
RK
1444#endif
1445 }
1446 else
b0e982be 1447#endif /* not NO_ADDSUB_Q */
7bc88d49
RK
1448 if (fsize + 4 < 0x8000)
1449 {
1450 if (TARGET_68040)
1451 {
7a1929e1 1452 /* asm_fprintf() cannot handle %. */
afaff477
RK
1453#ifdef MOTOROLA
1454 asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4);
1455#else
1456 asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4);
7bc88d49
RK
1457#endif
1458 }
1459 else
1460 {
7bc88d49
RK
1461#ifdef MOTOROLA
1462 asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", fsize + 4);
1463#else
1464 asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", fsize + 4);
afaff477
RK
1465#endif
1466 }
79e68feb
RS
1467 }
1468 else
1469 {
7a1929e1 1470 /* asm_fprintf() cannot handle %. */
2d0933a2
RK
1471#ifdef MOTOROLA
1472 asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4);
1473#else
1474 asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", fsize + 4);
1475#endif
79e68feb
RS
1476 }
1477 }
1478 if (current_function_pops_args)
338818c7 1479 asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args);
79e68feb
RS
1480 else
1481 fprintf (stream, "\trts\n");
1482}
08c148a8
NB
1483
1484#endif /* ! (DPX2 && MOTOROLA) */
1485#endif /* ! (NEWS && MOTOROLA) */
1486#endif /* !CRDS */
79e68feb
RS
1487\f
1488/* Similar to general_operand, but exclude stack_pointer_rtx. */
1489
1490int
1491not_sp_operand (op, mode)
1492 register rtx op;
1493 enum machine_mode mode;
1494{
8406d023 1495 return op != stack_pointer_rtx && nonimmediate_operand (op, mode);
79e68feb
RS
1496}
1497
64a184e9
RS
1498/* Return TRUE if X is a valid comparison operator for the dbcc
1499 instruction.
1500
1501 Note it rejects floating point comparison operators.
1502 (In the future we could use Fdbcc).
1503
1504 It also rejects some comparisons when CC_NO_OVERFLOW is set. */
1505
1506int
1507valid_dbcc_comparison_p (x, mode)
1508 rtx x;
f5220a5d 1509 enum machine_mode mode ATTRIBUTE_UNUSED;
64a184e9 1510{
64a184e9
RS
1511 switch (GET_CODE (x))
1512 {
64a184e9
RS
1513 case EQ: case NE: case GTU: case LTU:
1514 case GEU: case LEU:
1515 return 1;
1516
1517 /* Reject some when CC_NO_OVERFLOW is set. This may be over
1518 conservative */
1519 case GT: case LT: case GE: case LE:
1520 return ! (cc_prev_status.flags & CC_NO_OVERFLOW);
1521 default:
1522 return 0;
1523 }
1524}
1525
6a0f85e3
TG
1526/* Return non-zero if flags are currently in the 68881 flag register. */
1527int
1528flags_in_68881 ()
1529{
1530 /* We could add support for these in the future */
1531 return cc_status.flags & CC_IN_68881;
1532}
1533
64a184e9
RS
1534/* Output a dbCC; jCC sequence. Note we do not handle the
1535 floating point version of this sequence (Fdbcc). We also
1536 do not handle alternative conditions when CC_NO_OVERFLOW is
6a0f85e3
TG
1537 set. It is assumed that valid_dbcc_comparison_p and flags_in_68881 will
1538 kick those out before we get here. */
64a184e9 1539
1d8eaa6b 1540void
64a184e9
RS
1541output_dbcc_and_branch (operands)
1542 rtx *operands;
1543{
64a184e9
RS
1544 switch (GET_CODE (operands[3]))
1545 {
1546 case EQ:
1547#ifdef MOTOROLA
1548 output_asm_insn ("dbeq %0,%l1\n\tjbeq %l2", operands);
1549#else
1550 output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands);
1551#endif
1552 break;
1553
1554 case NE:
1555#ifdef MOTOROLA
1556 output_asm_insn ("dbne %0,%l1\n\tjbne %l2", operands);
1557#else
1558 output_asm_insn ("dbne %0,%l1\n\tjne %l2", operands);
1559#endif
1560 break;
1561
1562 case GT:
1563#ifdef MOTOROLA
1564 output_asm_insn ("dbgt %0,%l1\n\tjbgt %l2", operands);
1565#else
1566 output_asm_insn ("dbgt %0,%l1\n\tjgt %l2", operands);
1567#endif
1568 break;
1569
1570 case GTU:
1571#ifdef MOTOROLA
1572 output_asm_insn ("dbhi %0,%l1\n\tjbhi %l2", operands);
1573#else
1574 output_asm_insn ("dbhi %0,%l1\n\tjhi %l2", operands);
1575#endif
1576 break;
1577
1578 case LT:
1579#ifdef MOTOROLA
1580 output_asm_insn ("dblt %0,%l1\n\tjblt %l2", operands);
1581#else
1582 output_asm_insn ("dblt %0,%l1\n\tjlt %l2", operands);
1583#endif
1584 break;
1585
1586 case LTU:
1587#ifdef MOTOROLA
1588 output_asm_insn ("dbcs %0,%l1\n\tjbcs %l2", operands);
1589#else
1590 output_asm_insn ("dbcs %0,%l1\n\tjcs %l2", operands);
1591#endif
1592 break;
1593
1594 case GE:
1595#ifdef MOTOROLA
1596 output_asm_insn ("dbge %0,%l1\n\tjbge %l2", operands);
1597#else
1598 output_asm_insn ("dbge %0,%l1\n\tjge %l2", operands);
1599#endif
1600 break;
1601
1602 case GEU:
1603#ifdef MOTOROLA
1604 output_asm_insn ("dbcc %0,%l1\n\tjbcc %l2", operands);
1605#else
1606 output_asm_insn ("dbcc %0,%l1\n\tjcc %l2", operands);
1607#endif
1608 break;
1609
1610 case LE:
1611#ifdef MOTOROLA
1612 output_asm_insn ("dble %0,%l1\n\tjble %l2", operands);
1613#else
1614 output_asm_insn ("dble %0,%l1\n\tjle %l2", operands);
1615#endif
1616 break;
1617
1618 case LEU:
1619#ifdef MOTOROLA
1620 output_asm_insn ("dbls %0,%l1\n\tjbls %l2", operands);
1621#else
1622 output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands);
1623#endif
1624 break;
1625
1626 default:
1627 abort ();
1628 }
1629
1630 /* If the decrement is to be done in SImode, then we have
7a1929e1 1631 to compensate for the fact that dbcc decrements in HImode. */
64a184e9
RS
1632 switch (GET_MODE (operands[0]))
1633 {
1634 case SImode:
1635#ifdef MOTOROLA
1636 output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjbpl %l1", operands);
1637#else
1638 output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjpl %l1", operands);
1639#endif
1640 break;
1641
1642 case HImode:
1643 break;
1644
1645 default:
1646 abort ();
1647 }
1648}
1649
5505f548 1650const char *
c59c3b1c
RK
1651output_scc_di(op, operand1, operand2, dest)
1652 rtx op;
1653 rtx operand1;
1654 rtx operand2;
1655 rtx dest;
1656{
1657 rtx loperands[7];
d9832fd2 1658 enum rtx_code op_code = GET_CODE (op);
c59c3b1c 1659
f710504c 1660 /* This does not produce a useful cc. */
906a2d3c
RK
1661 CC_STATUS_INIT;
1662
d9832fd2
RK
1663 /* The m68k cmp.l instruction requires operand1 to be a reg as used
1664 below. Swap the operands and change the op if these requirements
1665 are not fulfilled. */
1666 if (GET_CODE (operand2) == REG && GET_CODE (operand1) != REG)
1667 {
1668 rtx tmp = operand1;
1669
1670 operand1 = operand2;
1671 operand2 = tmp;
1672 op_code = swap_condition (op_code);
1673 }
c59c3b1c
RK
1674 loperands[0] = operand1;
1675 if (GET_CODE (operand1) == REG)
1d8eaa6b 1676 loperands[1] = gen_rtx_REG (SImode, REGNO (operand1) + 1);
c59c3b1c 1677 else
b72f00af 1678 loperands[1] = adjust_address (operand1, SImode, 4);
c59c3b1c
RK
1679 if (operand2 != const0_rtx)
1680 {
1681 loperands[2] = operand2;
1682 if (GET_CODE (operand2) == REG)
1d8eaa6b 1683 loperands[3] = gen_rtx_REG (SImode, REGNO (operand2) + 1);
c59c3b1c 1684 else
b72f00af 1685 loperands[3] = adjust_address (operand2, SImode, 4);
c59c3b1c
RK
1686 }
1687 loperands[4] = gen_label_rtx();
1688 if (operand2 != const0_rtx)
4a8c52e0 1689 {
c59c3b1c 1690#ifdef MOTOROLA
f2121711 1691#ifdef SGS_CMP_ORDER
4a8c52e0 1692 output_asm_insn ("cmp%.l %0,%2\n\tjbne %l4\n\tcmp%.l %1,%3", loperands);
c59c3b1c 1693#else
4a8c52e0 1694 output_asm_insn ("cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1", loperands);
f2121711
RK
1695#endif
1696#else
1697#ifdef SGS_CMP_ORDER
4a8c52e0 1698 output_asm_insn ("cmp%.l %0,%2\n\tjne %l4\n\tcmp%.l %1,%3", loperands);
f2121711 1699#else
4a8c52e0 1700 output_asm_insn ("cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands);
f2121711 1701#endif
c59c3b1c 1702#endif
4a8c52e0 1703 }
392582fa 1704 else
4a8c52e0
AS
1705 {
1706 if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[0]))
1707 output_asm_insn ("tst%.l %0", loperands);
1708 else
1709 {
392582fa 1710#ifdef SGS_CMP_ORDER
4a8c52e0 1711 output_asm_insn ("cmp%.w %0,%#0", loperands);
392582fa 1712#else
4a8c52e0 1713 output_asm_insn ("cmp%.w %#0,%0", loperands);
392582fa 1714#endif
4a8c52e0
AS
1715 }
1716
1717#ifdef MOTOROLA
1718 output_asm_insn ("jbne %l4", loperands);
392582fa 1719#else
4a8c52e0
AS
1720 output_asm_insn ("jne %l4", loperands);
1721#endif
1722
1723 if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[1]))
1724 output_asm_insn ("tst%.l %1", loperands);
1725 else
1726 {
392582fa 1727#ifdef SGS_CMP_ORDER
4a8c52e0 1728 output_asm_insn ("cmp%.w %1,%#0", loperands);
392582fa 1729#else
4a8c52e0 1730 output_asm_insn ("cmp%.w %#0,%1", loperands);
c59c3b1c 1731#endif
4a8c52e0
AS
1732 }
1733 }
1734
c59c3b1c
RK
1735 loperands[5] = dest;
1736
d9832fd2 1737 switch (op_code)
c59c3b1c
RK
1738 {
1739 case EQ:
1740 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1741 CODE_LABEL_NUMBER (loperands[4]));
1742 output_asm_insn ("seq %5", loperands);
1743 break;
1744
1745 case NE:
1746 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1747 CODE_LABEL_NUMBER (loperands[4]));
1748 output_asm_insn ("sne %5", loperands);
1749 break;
1750
1751 case GT:
1752 loperands[6] = gen_label_rtx();
1753#ifdef MOTOROLA
1754 output_asm_insn ("shi %5\n\tjbra %l6", loperands);
1755#else
1756 output_asm_insn ("shi %5\n\tjra %l6", loperands);
1757#endif
1758 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1759 CODE_LABEL_NUMBER (loperands[4]));
1760 output_asm_insn ("sgt %5", loperands);
1761 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1762 CODE_LABEL_NUMBER (loperands[6]));
1763 break;
1764
1765 case GTU:
1766 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1767 CODE_LABEL_NUMBER (loperands[4]));
1768 output_asm_insn ("shi %5", loperands);
1769 break;
1770
1771 case LT:
1772 loperands[6] = gen_label_rtx();
1773#ifdef MOTOROLA
1774 output_asm_insn ("scs %5\n\tjbra %l6", loperands);
1775#else
1776 output_asm_insn ("scs %5\n\tjra %l6", loperands);
1777#endif
1778 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1779 CODE_LABEL_NUMBER (loperands[4]));
1780 output_asm_insn ("slt %5", loperands);
1781 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1782 CODE_LABEL_NUMBER (loperands[6]));
1783 break;
1784
1785 case LTU:
1786 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1787 CODE_LABEL_NUMBER (loperands[4]));
1788 output_asm_insn ("scs %5", loperands);
1789 break;
1790
1791 case GE:
1792 loperands[6] = gen_label_rtx();
1793#ifdef MOTOROLA
1794 output_asm_insn ("scc %5\n\tjbra %l6", loperands);
1795#else
1796 output_asm_insn ("scc %5\n\tjra %l6", loperands);
1797#endif
1798 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1799 CODE_LABEL_NUMBER (loperands[4]));
1800 output_asm_insn ("sge %5", loperands);
1801 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1802 CODE_LABEL_NUMBER (loperands[6]));
1803 break;
1804
1805 case GEU:
1806 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1807 CODE_LABEL_NUMBER (loperands[4]));
1808 output_asm_insn ("scc %5", loperands);
1809 break;
1810
1811 case LE:
1812 loperands[6] = gen_label_rtx();
1813#ifdef MOTOROLA
1814 output_asm_insn ("sls %5\n\tjbra %l6", loperands);
1815#else
1816 output_asm_insn ("sls %5\n\tjra %l6", loperands);
1817#endif
1818 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1819 CODE_LABEL_NUMBER (loperands[4]));
1820 output_asm_insn ("sle %5", loperands);
1821 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1822 CODE_LABEL_NUMBER (loperands[6]));
1823 break;
1824
1825 case LEU:
1826 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
1827 CODE_LABEL_NUMBER (loperands[4]));
1828 output_asm_insn ("sls %5", loperands);
1829 break;
1830
1831 default:
1832 abort ();
1833 }
1834 return "";
1835}
1836
5505f548 1837const char *
79e68feb
RS
1838output_btst (operands, countop, dataop, insn, signpos)
1839 rtx *operands;
1840 rtx countop, dataop;
1841 rtx insn;
1842 int signpos;
1843{
1844 operands[0] = countop;
1845 operands[1] = dataop;
1846
1847 if (GET_CODE (countop) == CONST_INT)
1848 {
1849 register int count = INTVAL (countop);
1850 /* If COUNT is bigger than size of storage unit in use,
1851 advance to the containing unit of same size. */
1852 if (count > signpos)
1853 {
1854 int offset = (count & ~signpos) / 8;
1855 count = count & signpos;
b72f00af 1856 operands[1] = dataop = adjust_address (dataop, QImode, offset);
79e68feb
RS
1857 }
1858 if (count == signpos)
1859 cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
1860 else
1861 cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
1862
1863 /* These three statements used to use next_insns_test_no...
1864 but it appears that this should do the same job. */
1865 if (count == 31
1866 && next_insn_tests_no_inequality (insn))
1867 return "tst%.l %1";
1868 if (count == 15
1869 && next_insn_tests_no_inequality (insn))
1870 return "tst%.w %1";
1871 if (count == 7
1872 && next_insn_tests_no_inequality (insn))
1873 return "tst%.b %1";
1874
1875 cc_status.flags = CC_NOT_NEGATIVE;
1876 }
1877 return "btst %0,%1";
1878}
1879\f
1880/* Returns 1 if OP is either a symbol reference or a sum of a symbol
1881 reference and a constant. */
1882
1883int
1884symbolic_operand (op, mode)
1885 register rtx op;
f5220a5d 1886 enum machine_mode mode ATTRIBUTE_UNUSED;
79e68feb
RS
1887{
1888 switch (GET_CODE (op))
1889 {
1890 case SYMBOL_REF:
1891 case LABEL_REF:
1892 return 1;
1893
1894 case CONST:
1895 op = XEXP (op, 0);
1896 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1897 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1898 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1899
1900#if 0 /* Deleted, with corresponding change in m68k.h,
1901 so as to fit the specs. No CONST_DOUBLE is ever symbolic. */
1902 case CONST_DOUBLE:
1903 return GET_MODE (op) == mode;
1904#endif
1905
1906 default:
1907 return 0;
1908 }
1909}
16f323be 1910\f
7a1929e1 1911/* Check for sign_extend or zero_extend. Used for bit-count operands. */
16f323be
RK
1912
1913int
1914extend_operator(x, mode)
1915 rtx x;
1916 enum machine_mode mode;
1917{
c59c3b1c 1918 if (mode != VOIDmode && GET_MODE(x) != mode)
16f323be
RK
1919 return 0;
1920 switch (GET_CODE(x))
1921 {
1922 case SIGN_EXTEND :
1923 case ZERO_EXTEND :
16f323be
RK
1924 return 1;
1925 default :
1926 return 0;
1927 }
1928}
79e68feb
RS
1929
1930\f
1931/* Legitimize PIC addresses. If the address is already
1932 position-independent, we return ORIG. Newly generated
1933 position-independent addresses go to REG. If we need more
1934 than one register, we lose.
1935
1936 An address is legitimized by making an indirect reference
1937 through the Global Offset Table with the name of the symbol
1938 used as an offset.
1939
1940 The assembler and linker are responsible for placing the
1941 address of the symbol in the GOT. The function prologue
1942 is responsible for initializing a5 to the starting address
1943 of the GOT.
1944
1945 The assembler is also responsible for translating a symbol name
1946 into a constant displacement from the start of the GOT.
1947
1948 A quick example may make things a little clearer:
1949
1950 When not generating PIC code to store the value 12345 into _foo
1951 we would generate the following code:
1952
1953 movel #12345, _foo
1954
1955 When generating PIC two transformations are made. First, the compiler
1956 loads the address of foo into a register. So the first transformation makes:
1957
1958 lea _foo, a0
1959 movel #12345, a0@
1960
1961 The code in movsi will intercept the lea instruction and call this
1962 routine which will transform the instructions into:
1963
1964 movel a5@(_foo:w), a0
1965 movel #12345, a0@
1966
1967
1968 That (in a nutshell) is how *all* symbol and label references are
1969 handled. */
1970
1971rtx
1972legitimize_pic_address (orig, mode, reg)
1973 rtx orig, reg;
f5220a5d 1974 enum machine_mode mode ATTRIBUTE_UNUSED;
79e68feb
RS
1975{
1976 rtx pic_ref = orig;
1977
1978 /* First handle a simple SYMBOL_REF or LABEL_REF */
1979 if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
1980 {
1981 if (reg == 0)
1982 abort ();
1983
1d8eaa6b
AS
1984 pic_ref = gen_rtx_MEM (Pmode,
1985 gen_rtx_PLUS (Pmode,
1986 pic_offset_table_rtx, orig));
79e68feb
RS
1987 current_function_uses_pic_offset_table = 1;
1988 RTX_UNCHANGING_P (pic_ref) = 1;
1989 emit_move_insn (reg, pic_ref);
1990 return reg;
1991 }
1992 else if (GET_CODE (orig) == CONST)
1993 {
1d8eaa6b 1994 rtx base;
79e68feb
RS
1995
1996 /* Make sure this is CONST has not already been legitimized */
1997 if (GET_CODE (XEXP (orig, 0)) == PLUS
1998 && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
1999 return orig;
2000
2001 if (reg == 0)
2002 abort ();
2003
2004 /* legitimize both operands of the PLUS */
2005 if (GET_CODE (XEXP (orig, 0)) == PLUS)
2006 {
2007 base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
2008 orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
2009 base == reg ? 0 : reg);
2010 }
2011 else abort ();
2012
2013 if (GET_CODE (orig) == CONST_INT)
ed8908e7 2014 return plus_constant (base, INTVAL (orig));
1d8eaa6b 2015 pic_ref = gen_rtx_PLUS (Pmode, base, orig);
79e68feb
RS
2016 /* Likewise, should we set special REG_NOTEs here? */
2017 }
2018 return pic_ref;
2019}
2020
2021\f
0ce6f9fb
RK
2022typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD;
2023
5505f548
KG
2024static CONST_METHOD const_method PARAMS ((rtx));
2025
6910dd70 2026#define USE_MOVQ(i) ((unsigned)((i) + 128) <= 255)
0ce6f9fb 2027
5505f548 2028static CONST_METHOD
0ce6f9fb
RK
2029const_method (constant)
2030 rtx constant;
2031{
2032 int i;
2033 unsigned u;
2034
2035 i = INTVAL (constant);
6910dd70 2036 if (USE_MOVQ (i))
0ce6f9fb 2037 return MOVQ;
24092242 2038
7a1929e1 2039 /* The Coldfire doesn't have byte or word operations. */
24092242
RK
2040 /* FIXME: This may not be useful for the m68060 either */
2041 if (!TARGET_5200)
2042 {
2043 /* if -256 < N < 256 but N is not in range for a moveq
7a1929e1 2044 N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */
24092242
RK
2045 if (USE_MOVQ (i ^ 0xff))
2046 return NOTB;
2047 /* Likewise, try with not.w */
2048 if (USE_MOVQ (i ^ 0xffff))
2049 return NOTW;
2050 /* This is the only value where neg.w is useful */
2051 if (i == -65408)
2052 return NEGW;
2053 /* Try also with swap */
2054 u = i;
2055 if (USE_MOVQ ((u >> 16) | (u << 16)))
2056 return SWAP;
2057 }
0ce6f9fb
RK
2058 /* Otherwise, use move.l */
2059 return MOVL;
2060}
2061
1d8eaa6b 2062int
0ce6f9fb
RK
2063const_int_cost (constant)
2064 rtx constant;
2065{
2066 switch (const_method (constant))
2067 {
2068 case MOVQ :
2069 /* Constants between -128 and 127 are cheap due to moveq */
2070 return 0;
2071 case NOTB :
2072 case NOTW :
2073 case NEGW :
2074 case SWAP :
2075 /* Constants easily generated by moveq + not.b/not.w/neg.w/swap */
2076 return 1;
2077 case MOVL :
2078 return 2;
2079 default :
2080 abort ();
2081 }
2082}
2083
5505f548 2084const char *
0ce6f9fb
RK
2085output_move_const_into_data_reg (operands)
2086 rtx *operands;
2087{
2088 int i;
2089
2090 i = INTVAL (operands[1]);
2091 switch (const_method (operands[1]))
2092 {
2093 case MOVQ :
2094#if defined (MOTOROLA) && !defined (CRDS)
2095 return "moveq%.l %1,%0";
2096#else
2097 return "moveq %1,%0";
2098#endif
2099 case NOTB :
1d8eaa6b 2100 operands[1] = GEN_INT (i ^ 0xff);
0ce6f9fb
RK
2101#if defined (MOTOROLA) && !defined (CRDS)
2102 return "moveq%.l %1,%0\n\tnot%.b %0";
2103#else
2104 return "moveq %1,%0\n\tnot%.b %0";
2105#endif
2106 case NOTW :
1d8eaa6b 2107 operands[1] = GEN_INT (i ^ 0xffff);
0ce6f9fb
RK
2108#if defined (MOTOROLA) && !defined (CRDS)
2109 return "moveq%.l %1,%0\n\tnot%.w %0";
2110#else
2111 return "moveq %1,%0\n\tnot%.w %0";
2112#endif
2113 case NEGW :
2114#if defined (MOTOROLA) && !defined (CRDS)
2115 return "moveq%.l %#-128,%0\n\tneg%.w %0";
2116#else
2117 return "moveq %#-128,%0\n\tneg%.w %0";
2118#endif
2119 case SWAP :
2120 {
2121 unsigned u = i;
2122
1d8eaa6b 2123 operands[1] = GEN_INT ((u << 16) | (u >> 16));
0ce6f9fb
RK
2124#if defined (MOTOROLA) && !defined (CRDS)
2125 return "moveq%.l %1,%0\n\tswap %0";
2126#else
2127 return "moveq %1,%0\n\tswap %0";
2128#endif
2129 }
2130 case MOVL :
2131 return "move%.l %1,%0";
2132 default :
2133 abort ();
2134 }
2135}
2136
5505f548 2137const char *
02ed0c07
RK
2138output_move_simode_const (operands)
2139 rtx *operands;
2140{
2141 if (operands[1] == const0_rtx
2142 && (DATA_REG_P (operands[0])
2143 || GET_CODE (operands[0]) == MEM)
2144 /* clr insns on 68000 read before writing.
c67ddce5 2145 This isn't so on the 68010, but we have no TARGET_68010. */
0cb7cfed 2146 && ((TARGET_68020 || TARGET_5200)
02ed0c07
RK
2147 || !(GET_CODE (operands[0]) == MEM
2148 && MEM_VOLATILE_P (operands[0]))))
2149 return "clr%.l %0";
38198304
AS
2150 else if (operands[1] == const0_rtx
2151 && ADDRESS_REG_P (operands[0]))
2152 return "sub%.l %0,%0";
02ed0c07
RK
2153 else if (DATA_REG_P (operands[0]))
2154 return output_move_const_into_data_reg (operands);
2155 else if (ADDRESS_REG_P (operands[0])
2156 && INTVAL (operands[1]) < 0x8000
2157 && INTVAL (operands[1]) >= -0x8000)
2158 return "move%.w %1,%0";
2159 else if (GET_CODE (operands[0]) == MEM
2160 && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
2161 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
2162 && INTVAL (operands[1]) < 0x8000
2163 && INTVAL (operands[1]) >= -0x8000)
2164 return "pea %a1";
2165 return "move%.l %1,%0";
2166}
2167
5505f548 2168const char *
f4e80198
RK
2169output_move_simode (operands)
2170 rtx *operands;
2171{
2172 if (GET_CODE (operands[1]) == CONST_INT)
2173 return output_move_simode_const (operands);
2174 else if ((GET_CODE (operands[1]) == SYMBOL_REF
2175 || GET_CODE (operands[1]) == CONST)
2176 && push_operand (operands[0], SImode))
2177 return "pea %a1";
2178 else if ((GET_CODE (operands[1]) == SYMBOL_REF
2179 || GET_CODE (operands[1]) == CONST)
2180 && ADDRESS_REG_P (operands[0]))
2181 return "lea %a1,%0";
2182 return "move%.l %1,%0";
2183}
2184
5505f548 2185const char *
f4e80198
RK
2186output_move_himode (operands)
2187 rtx *operands;
2188{
2189 if (GET_CODE (operands[1]) == CONST_INT)
2190 {
2191 if (operands[1] == const0_rtx
2192 && (DATA_REG_P (operands[0])
2193 || GET_CODE (operands[0]) == MEM)
2194 /* clr insns on 68000 read before writing.
2195 This isn't so on the 68010, but we have no TARGET_68010. */
2196 && ((TARGET_68020 || TARGET_5200)
2197 || !(GET_CODE (operands[0]) == MEM
2198 && MEM_VOLATILE_P (operands[0]))))
2199 return "clr%.w %0";
38198304
AS
2200 else if (operands[1] == const0_rtx
2201 && ADDRESS_REG_P (operands[0]))
2202 return "sub%.l %0,%0";
f4e80198
RK
2203 else if (DATA_REG_P (operands[0])
2204 && INTVAL (operands[1]) < 128
2205 && INTVAL (operands[1]) >= -128)
2206 {
2207#if defined(MOTOROLA) && !defined(CRDS)
2208 return "moveq%.l %1,%0";
2209#else
2210 return "moveq %1,%0";
2211#endif
2212 }
2213 else if (INTVAL (operands[1]) < 0x8000
2214 && INTVAL (operands[1]) >= -0x8000)
2215 return "move%.w %1,%0";
2216 }
2217 else if (CONSTANT_P (operands[1]))
2218 return "move%.l %1,%0";
2219#ifndef SGS_NO_LI
2220 /* Recognize the insn before a tablejump, one that refers
2221 to a table of offsets. Such an insn will need to refer
2222 to a label on the insn. So output one. Use the label-number
2223 of the table of offsets to generate this label. This code,
2224 and similar code below, assumes that there will be at most one
2225 reference to each table. */
2226 if (GET_CODE (operands[1]) == MEM
2227 && GET_CODE (XEXP (operands[1], 0)) == PLUS
2228 && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF
2229 && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS)
2230 {
2231 rtx labelref = XEXP (XEXP (operands[1], 0), 1);
2232#if defined (MOTOROLA) && !defined (SGS_SWITCH_TABLES)
2233#ifdef SGS
2234 asm_fprintf (asm_out_file, "\tset %LLI%d,.+2\n",
2235 CODE_LABEL_NUMBER (XEXP (labelref, 0)));
2236#else /* not SGS */
2237 asm_fprintf (asm_out_file, "\t.set %LLI%d,.+2\n",
2238 CODE_LABEL_NUMBER (XEXP (labelref, 0)));
2239#endif /* not SGS */
2240#else /* SGS_SWITCH_TABLES or not MOTOROLA */
2241 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LI",
2242 CODE_LABEL_NUMBER (XEXP (labelref, 0)));
2243#ifdef SGS_SWITCH_TABLES
2244 /* Set flag saying we need to define the symbol
2245 LD%n (with value L%n-LI%n) at the end of the switch table. */
2246 switch_table_difference_label_flag = 1;
2247#endif /* SGS_SWITCH_TABLES */
2248#endif /* SGS_SWITCH_TABLES or not MOTOROLA */
2249 }
2250#endif /* SGS_NO_LI */
2251 return "move%.w %1,%0";
2252}
2253
5505f548 2254const char *
f4e80198
RK
2255output_move_qimode (operands)
2256 rtx *operands;
2257{
2258 rtx xoperands[4];
2259
2260 /* This is probably useless, since it loses for pushing a struct
2261 of several bytes a byte at a time. */
102701ff
JW
2262 /* 68k family always modifies the stack pointer by at least 2, even for
2263 byte pushes. The 5200 (coldfire) does not do this. */
f4e80198
RK
2264 if (GET_CODE (operands[0]) == MEM
2265 && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
2266 && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx
102701ff
JW
2267 && ! ADDRESS_REG_P (operands[1])
2268 && ! TARGET_5200)
f4e80198
RK
2269 {
2270 xoperands[1] = operands[1];
2271 xoperands[2]
1d8eaa6b
AS
2272 = gen_rtx_MEM (QImode,
2273 gen_rtx_PLUS (VOIDmode, stack_pointer_rtx, const1_rtx));
f4e80198
RK
2274 /* Just pushing a byte puts it in the high byte of the halfword. */
2275 /* We must put it in the low-order, high-numbered byte. */
3879920c
RK
2276 if (!reg_mentioned_p (stack_pointer_rtx, operands[1]))
2277 {
2278 xoperands[3] = stack_pointer_rtx;
2279#ifndef NO_ADDSUB_Q
2280 output_asm_insn ("subq%.l %#2,%3\n\tmove%.b %1,%2", xoperands);
2281#else
2282 output_asm_insn ("sub%.l %#2,%3\n\tmove%.b %1,%2", xoperands);
2283#endif
2284 }
2285 else
2286 output_asm_insn ("move%.b %1,%-\n\tmove%.b %@,%2", xoperands);
f4e80198
RK
2287 return "";
2288 }
2289
2290 /* clr and st insns on 68000 read before writing.
2291 This isn't so on the 68010, but we have no TARGET_68010. */
2292 if (!ADDRESS_REG_P (operands[0])
2293 && ((TARGET_68020 || TARGET_5200)
2294 || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
2295 {
2296 if (operands[1] == const0_rtx)
2297 return "clr%.b %0";
2298 if ((!TARGET_5200 || DATA_REG_P (operands[0]))
2299 && GET_CODE (operands[1]) == CONST_INT
2300 && (INTVAL (operands[1]) & 255) == 255)
2301 {
2302 CC_STATUS_INIT;
2303 return "st %0";
2304 }
2305 }
2306 if (GET_CODE (operands[1]) == CONST_INT
2307 && DATA_REG_P (operands[0])
2308 && INTVAL (operands[1]) < 128
2309 && INTVAL (operands[1]) >= -128)
2310 {
2311#if defined(MOTOROLA) && !defined(CRDS)
2312 return "moveq%.l %1,%0";
2313#else
2314 return "moveq %1,%0";
2315#endif
2316 }
38198304
AS
2317 if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0]))
2318 return "sub%.l %0,%0";
f4e80198
RK
2319 if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))
2320 return "move%.l %1,%0";
37834fc8
JL
2321 /* 68k family (including the 5200 coldfire) does not support byte moves to
2322 from address registers. */
2323 if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))
f4e80198
RK
2324 return "move%.w %1,%0";
2325 return "move%.b %1,%0";
2326}
2327
5505f548 2328const char *
9b55bf04
RK
2329output_move_stricthi (operands)
2330 rtx *operands;
2331{
2332 if (operands[1] == const0_rtx
2333 /* clr insns on 68000 read before writing.
2334 This isn't so on the 68010, but we have no TARGET_68010. */
2335 && ((TARGET_68020 || TARGET_5200)
2336 || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
2337 return "clr%.w %0";
2338 return "move%.w %1,%0";
2339}
2340
5505f548 2341const char *
9b55bf04
RK
2342output_move_strictqi (operands)
2343 rtx *operands;
2344{
2345 if (operands[1] == const0_rtx
2346 /* clr insns on 68000 read before writing.
2347 This isn't so on the 68010, but we have no TARGET_68010. */
2348 && ((TARGET_68020 || TARGET_5200)
2349 || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
2350 return "clr%.b %0";
2351 return "move%.b %1,%0";
2352}
2353
79e68feb
RS
2354/* Return the best assembler insn template
2355 for moving operands[1] into operands[0] as a fullword. */
2356
5505f548 2357static const char *
79e68feb
RS
2358singlemove_string (operands)
2359 rtx *operands;
2360{
2361#ifdef SUPPORT_SUN_FPA
2362 if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))
2363 return "fpmoves %1,%0";
2364#endif
02ed0c07
RK
2365 if (GET_CODE (operands[1]) == CONST_INT)
2366 return output_move_simode_const (operands);
2367 return "move%.l %1,%0";
79e68feb
RS
2368}
2369
2505bc97 2370
79e68feb
RS
2371/* Output assembler code to perform a doubleword move insn
2372 with operands OPERANDS. */
2373
5505f548 2374const char *
79e68feb
RS
2375output_move_double (operands)
2376 rtx *operands;
2377{
2505bc97
RS
2378 enum
2379 {
2380 REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP
2381 } optype0, optype1;
79e68feb 2382 rtx latehalf[2];
2505bc97 2383 rtx middlehalf[2];
7f98eeb6 2384 rtx xops[2];
79e68feb 2385 rtx addreg0 = 0, addreg1 = 0;
7f98eeb6 2386 int dest_overlapped_low = 0;
184916bc 2387 int size = GET_MODE_SIZE (GET_MODE (operands[0]));
2505bc97
RS
2388
2389 middlehalf[0] = 0;
2390 middlehalf[1] = 0;
79e68feb
RS
2391
2392 /* First classify both operands. */
2393
2394 if (REG_P (operands[0]))
2395 optype0 = REGOP;
2396 else if (offsettable_memref_p (operands[0]))
2397 optype0 = OFFSOP;
2398 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
2399 optype0 = POPOP;
2400 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
2401 optype0 = PUSHOP;
2402 else if (GET_CODE (operands[0]) == MEM)
2403 optype0 = MEMOP;
2404 else
2405 optype0 = RNDOP;
2406
2407 if (REG_P (operands[1]))
2408 optype1 = REGOP;
2409 else if (CONSTANT_P (operands[1]))
2410 optype1 = CNSTOP;
2411 else if (offsettable_memref_p (operands[1]))
2412 optype1 = OFFSOP;
2413 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
2414 optype1 = POPOP;
2415 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
2416 optype1 = PUSHOP;
2417 else if (GET_CODE (operands[1]) == MEM)
2418 optype1 = MEMOP;
2419 else
2420 optype1 = RNDOP;
2421
2422 /* Check for the cases that the operand constraints are not
2423 supposed to allow to happen. Abort if we get one,
2424 because generating code for these cases is painful. */
2425
2426 if (optype0 == RNDOP || optype1 == RNDOP)
2427 abort ();
2428
2429 /* If one operand is decrementing and one is incrementing
2430 decrement the former register explicitly
2431 and change that operand into ordinary indexing. */
2432
2433 if (optype0 == PUSHOP && optype1 == POPOP)
2434 {
2435 operands[0] = XEXP (XEXP (operands[0], 0), 0);
2505bc97
RS
2436 if (size == 12)
2437 output_asm_insn ("sub%.l %#12,%0", operands);
2438 else
2439 output_asm_insn ("subq%.l %#8,%0", operands);
2440 if (GET_MODE (operands[1]) == XFmode)
1d8eaa6b 2441 operands[0] = gen_rtx_MEM (XFmode, operands[0]);
2505bc97 2442 else if (GET_MODE (operands[0]) == DFmode)
1d8eaa6b 2443 operands[0] = gen_rtx_MEM (DFmode, operands[0]);
2505bc97 2444 else
1d8eaa6b 2445 operands[0] = gen_rtx_MEM (DImode, operands[0]);
79e68feb
RS
2446 optype0 = OFFSOP;
2447 }
2448 if (optype0 == POPOP && optype1 == PUSHOP)
2449 {
2450 operands[1] = XEXP (XEXP (operands[1], 0), 0);
2505bc97
RS
2451 if (size == 12)
2452 output_asm_insn ("sub%.l %#12,%1", operands);
2453 else
2454 output_asm_insn ("subq%.l %#8,%1", operands);
2455 if (GET_MODE (operands[1]) == XFmode)
1d8eaa6b 2456 operands[1] = gen_rtx_MEM (XFmode, operands[1]);
2505bc97 2457 else if (GET_MODE (operands[1]) == DFmode)
1d8eaa6b 2458 operands[1] = gen_rtx_MEM (DFmode, operands[1]);
2505bc97 2459 else
1d8eaa6b 2460 operands[1] = gen_rtx_MEM (DImode, operands[1]);
79e68feb
RS
2461 optype1 = OFFSOP;
2462 }
2463
2464 /* If an operand is an unoffsettable memory ref, find a register
2465 we can increment temporarily to make it refer to the second word. */
2466
2467 if (optype0 == MEMOP)
2468 addreg0 = find_addr_reg (XEXP (operands[0], 0));
2469
2470 if (optype1 == MEMOP)
2471 addreg1 = find_addr_reg (XEXP (operands[1], 0));
2472
2473 /* Ok, we can do one word at a time.
2474 Normally we do the low-numbered word first,
2475 but if either operand is autodecrementing then we
2476 do the high-numbered word first.
2477
2478 In either case, set up in LATEHALF the operands to use
2479 for the high-numbered word and in some cases alter the
2480 operands in OPERANDS to be suitable for the low-numbered word. */
2481
2505bc97
RS
2482 if (size == 12)
2483 {
2484 if (optype0 == REGOP)
2485 {
1d8eaa6b
AS
2486 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
2487 middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
2505bc97
RS
2488 }
2489 else if (optype0 == OFFSOP)
2490 {
b72f00af
RK
2491 middlehalf[0] = adjust_address (operands[0], SImode, 4);
2492 latehalf[0] = adjust_address (operands[0], SImode, size - 4);
2505bc97
RS
2493 }
2494 else
2495 {
2496 middlehalf[0] = operands[0];
2497 latehalf[0] = operands[0];
2498 }
2499
2500 if (optype1 == REGOP)
2501 {
1d8eaa6b
AS
2502 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
2503 middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
2505bc97
RS
2504 }
2505 else if (optype1 == OFFSOP)
2506 {
b72f00af
RK
2507 middlehalf[1] = adjust_address (operands[1], SImode, 4);
2508 latehalf[1] = adjust_address (operands[1], SImode, size - 4);
2505bc97
RS
2509 }
2510 else if (optype1 == CNSTOP)
2511 {
2512 if (GET_CODE (operands[1]) == CONST_DOUBLE)
2513 {
2514 REAL_VALUE_TYPE r;
2515 long l[3];
2516
2517 REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
2518 REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
2519 operands[1] = GEN_INT (l[0]);
2520 middlehalf[1] = GEN_INT (l[1]);
2521 latehalf[1] = GEN_INT (l[2]);
2522 }
2523 else if (CONSTANT_P (operands[1]))
2524 {
2525 /* actually, no non-CONST_DOUBLE constant should ever
2526 appear here. */
2527 abort ();
2528 if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0)
2529 latehalf[1] = constm1_rtx;
2530 else
2531 latehalf[1] = const0_rtx;
2532 }
2533 }
2534 else
2535 {
2536 middlehalf[1] = operands[1];
2537 latehalf[1] = operands[1];
2538 }
2539 }
79e68feb 2540 else
2505bc97
RS
2541 /* size is not 12: */
2542 {
2543 if (optype0 == REGOP)
1d8eaa6b 2544 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
2505bc97 2545 else if (optype0 == OFFSOP)
b72f00af 2546 latehalf[0] = adjust_address (operands[0], SImode, size - 4);
2505bc97
RS
2547 else
2548 latehalf[0] = operands[0];
2549
2550 if (optype1 == REGOP)
1d8eaa6b 2551 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
2505bc97 2552 else if (optype1 == OFFSOP)
b72f00af 2553 latehalf[1] = adjust_address (operands[1], SImode, size - 4);
2505bc97
RS
2554 else if (optype1 == CNSTOP)
2555 split_double (operands[1], &operands[1], &latehalf[1]);
2556 else
2557 latehalf[1] = operands[1];
2558 }
79e68feb
RS
2559
2560 /* If insn is effectively movd N(sp),-(sp) then we will do the
2561 high word first. We should use the adjusted operand 1 (which is N+4(sp))
2562 for the low word as well, to compensate for the first decrement of sp. */
2563 if (optype0 == PUSHOP
2564 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
2565 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
c88aeaf8 2566 operands[1] = middlehalf[1] = latehalf[1];
79e68feb 2567
7f98eeb6
RS
2568 /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),
2569 if the upper part of reg N does not appear in the MEM, arrange to
2570 emit the move late-half first. Otherwise, compute the MEM address
2571 into the upper part of N and use that as a pointer to the memory
2572 operand. */
2573 if (optype0 == REGOP
2574 && (optype1 == OFFSOP || optype1 == MEMOP))
2575 {
1d8eaa6b 2576 rtx testlow = gen_rtx_REG (SImode, REGNO (operands[0]));
3a58400f
RS
2577
2578 if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
d7e8d581 2579 && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
7f98eeb6
RS
2580 {
2581 /* If both halves of dest are used in the src memory address,
3a58400f
RS
2582 compute the address into latehalf of dest.
2583 Note that this can't happen if the dest is two data regs. */
7f98eeb6
RS
2584compadr:
2585 xops[0] = latehalf[0];
2586 xops[1] = XEXP (operands[1], 0);
d7e8d581 2587 output_asm_insn ("lea %a1,%0", xops);
b72f00af 2588 if (GET_MODE (operands[1]) == XFmode )
7f98eeb6 2589 {
1d8eaa6b 2590 operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);
b72f00af
RK
2591 middlehalf[1] = adjust_address (operands[1], DImode, size - 8);
2592 latehalf[1] = adjust_address (operands[1], DImode, size - 4);
7f98eeb6
RS
2593 }
2594 else
2595 {
1d8eaa6b 2596 operands[1] = gen_rtx_MEM (DImode, latehalf[0]);
b72f00af 2597 latehalf[1] = adjust_address (operands[1], DImode, size - 4);
7f98eeb6
RS
2598 }
2599 }
2600 else if (size == 12
d7e8d581
RS
2601 && reg_overlap_mentioned_p (middlehalf[0],
2602 XEXP (operands[1], 0)))
7f98eeb6 2603 {
3a58400f
RS
2604 /* Check for two regs used by both source and dest.
2605 Note that this can't happen if the dest is all data regs.
2606 It can happen if the dest is d6, d7, a0.
2607 But in that case, latehalf is an addr reg, so
2608 the code at compadr does ok. */
2609
2610 if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
d7e8d581
RS
2611 || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
2612 goto compadr;
7f98eeb6
RS
2613
2614 /* JRV says this can't happen: */
2615 if (addreg0 || addreg1)
d7e8d581 2616 abort ();
7f98eeb6 2617
7a1929e1 2618 /* Only the middle reg conflicts; simply put it last. */
7f98eeb6
RS
2619 output_asm_insn (singlemove_string (operands), operands);
2620 output_asm_insn (singlemove_string (latehalf), latehalf);
2621 output_asm_insn (singlemove_string (middlehalf), middlehalf);
2622 return "";
2623 }
2fb8a81d 2624 else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)))
7f98eeb6
RS
2625 /* If the low half of dest is mentioned in the source memory
2626 address, the arrange to emit the move late half first. */
2627 dest_overlapped_low = 1;
2628 }
2629
79e68feb
RS
2630 /* If one or both operands autodecrementing,
2631 do the two words, high-numbered first. */
2632
2633 /* Likewise, the first move would clobber the source of the second one,
2634 do them in the other order. This happens only for registers;
2635 such overlap can't happen in memory unless the user explicitly
2636 sets it up, and that is an undefined circumstance. */
2637
2638 if (optype0 == PUSHOP || optype1 == PUSHOP
2639 || (optype0 == REGOP && optype1 == REGOP
2505bc97 2640 && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
7f98eeb6
RS
2641 || REGNO (operands[0]) == REGNO (latehalf[1])))
2642 || dest_overlapped_low)
79e68feb
RS
2643 {
2644 /* Make any unoffsettable addresses point at high-numbered word. */
2645 if (addreg0)
2505bc97
RS
2646 {
2647 if (size == 12)
07eced4d 2648 output_asm_insn ("addq%.l %#8,%0", &addreg0);
2505bc97 2649 else
07eced4d 2650 output_asm_insn ("addq%.l %#4,%0", &addreg0);
2505bc97 2651 }
79e68feb 2652 if (addreg1)
2505bc97
RS
2653 {
2654 if (size == 12)
07eced4d 2655 output_asm_insn ("addq%.l %#8,%0", &addreg1);
2505bc97 2656 else
07eced4d 2657 output_asm_insn ("addq%.l %#4,%0", &addreg1);
2505bc97 2658 }
79e68feb
RS
2659
2660 /* Do that word. */
2661 output_asm_insn (singlemove_string (latehalf), latehalf);
2662
2663 /* Undo the adds we just did. */
2664 if (addreg0)
07eced4d 2665 output_asm_insn ("subq%.l %#4,%0", &addreg0);
79e68feb 2666 if (addreg1)
07eced4d 2667 output_asm_insn ("subq%.l %#4,%0", &addreg1);
79e68feb 2668
2505bc97
RS
2669 if (size == 12)
2670 {
2671 output_asm_insn (singlemove_string (middlehalf), middlehalf);
2672 if (addreg0)
07eced4d 2673 output_asm_insn ("subq%.l %#4,%0", &addreg0);
2505bc97 2674 if (addreg1)
07eced4d 2675 output_asm_insn ("subq%.l %#4,%0", &addreg1);
2505bc97
RS
2676 }
2677
79e68feb
RS
2678 /* Do low-numbered word. */
2679 return singlemove_string (operands);
2680 }
2681
2682 /* Normal case: do the two words, low-numbered first. */
2683
2684 output_asm_insn (singlemove_string (operands), operands);
2685
2505bc97
RS
2686 /* Do the middle one of the three words for long double */
2687 if (size == 12)
2688 {
2689 if (addreg0)
07eced4d 2690 output_asm_insn ("addq%.l %#4,%0", &addreg0);
2505bc97 2691 if (addreg1)
07eced4d 2692 output_asm_insn ("addq%.l %#4,%0", &addreg1);
2505bc97
RS
2693
2694 output_asm_insn (singlemove_string (middlehalf), middlehalf);
2695 }
2696
79e68feb
RS
2697 /* Make any unoffsettable addresses point at high-numbered word. */
2698 if (addreg0)
07eced4d 2699 output_asm_insn ("addq%.l %#4,%0", &addreg0);
79e68feb 2700 if (addreg1)
07eced4d 2701 output_asm_insn ("addq%.l %#4,%0", &addreg1);
79e68feb
RS
2702
2703 /* Do that word. */
2704 output_asm_insn (singlemove_string (latehalf), latehalf);
2705
2706 /* Undo the adds we just did. */
2707 if (addreg0)
2505bc97
RS
2708 {
2709 if (size == 12)
07eced4d 2710 output_asm_insn ("subq%.l %#8,%0", &addreg0);
2505bc97 2711 else
07eced4d 2712 output_asm_insn ("subq%.l %#4,%0", &addreg0);
2505bc97 2713 }
79e68feb 2714 if (addreg1)
2505bc97
RS
2715 {
2716 if (size == 12)
07eced4d 2717 output_asm_insn ("subq%.l %#8,%0", &addreg1);
2505bc97 2718 else
07eced4d 2719 output_asm_insn ("subq%.l %#4,%0", &addreg1);
2505bc97 2720 }
79e68feb
RS
2721
2722 return "";
2723}
2724
2725/* Return a REG that occurs in ADDR with coefficient 1.
2726 ADDR can be effectively incremented by incrementing REG. */
2727
2728static rtx
2729find_addr_reg (addr)
2730 rtx addr;
2731{
2732 while (GET_CODE (addr) == PLUS)
2733 {
2734 if (GET_CODE (XEXP (addr, 0)) == REG)
2735 addr = XEXP (addr, 0);
2736 else if (GET_CODE (XEXP (addr, 1)) == REG)
2737 addr = XEXP (addr, 1);
2738 else if (CONSTANT_P (XEXP (addr, 0)))
2739 addr = XEXP (addr, 1);
2740 else if (CONSTANT_P (XEXP (addr, 1)))
2741 addr = XEXP (addr, 0);
2742 else
2743 abort ();
2744 }
2745 if (GET_CODE (addr) == REG)
2746 return addr;
2747 abort ();
2748}
9ee3c687
JW
2749
2750/* Output assembler code to perform a 32 bit 3 operand add. */
2751
5505f548 2752const char *
9ee3c687
JW
2753output_addsi3 (operands)
2754 rtx *operands;
2755{
2756 if (! operands_match_p (operands[0], operands[1]))
2757 {
2758 if (!ADDRESS_REG_P (operands[1]))
2759 {
2760 rtx tmp = operands[1];
2761
2762 operands[1] = operands[2];
2763 operands[2] = tmp;
2764 }
2765
2766 /* These insns can result from reloads to access
2767 stack slots over 64k from the frame pointer. */
2768 if (GET_CODE (operands[2]) == CONST_INT
2769 && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000)
8c61b6c1 2770 return "move%.l %2,%0\n\tadd%.l %1,%0";
9ee3c687
JW
2771#ifdef SGS
2772 if (GET_CODE (operands[2]) == REG)
2773 return "lea 0(%1,%2.l),%0";
2774 else
2775 return "lea %c2(%1),%0";
2776#else /* not SGS */
2777#ifdef MOTOROLA
2778 if (GET_CODE (operands[2]) == REG)
2779 return "lea (%1,%2.l),%0";
2780 else
2781 return "lea (%c2,%1),%0";
2782#else /* not MOTOROLA (MIT syntax) */
2783 if (GET_CODE (operands[2]) == REG)
2784 return "lea %1@(0,%2:l),%0";
2785 else
2786 return "lea %1@(%c2),%0";
2787#endif /* not MOTOROLA */
2788#endif /* not SGS */
2789 }
2790 if (GET_CODE (operands[2]) == CONST_INT)
2791 {
2792#ifndef NO_ADDSUB_Q
2793 if (INTVAL (operands[2]) > 0
2794 && INTVAL (operands[2]) <= 8)
2795 return "addq%.l %2,%0";
2796 if (INTVAL (operands[2]) < 0
2797 && INTVAL (operands[2]) >= -8)
2798 {
c5c76735 2799 operands[2] = GEN_INT (- INTVAL (operands[2]));
9ee3c687
JW
2800 return "subq%.l %2,%0";
2801 }
2802 /* On the CPU32 it is faster to use two addql instructions to
2803 add a small integer (8 < N <= 16) to a register.
7a1929e1 2804 Likewise for subql. */
9ee3c687
JW
2805 if (TARGET_CPU32 && REG_P (operands[0]))
2806 {
2807 if (INTVAL (operands[2]) > 8
2808 && INTVAL (operands[2]) <= 16)
2809 {
1d8eaa6b 2810 operands[2] = GEN_INT (INTVAL (operands[2]) - 8);
8c61b6c1 2811 return "addq%.l %#8,%0\n\taddq%.l %2,%0";
9ee3c687
JW
2812 }
2813 if (INTVAL (operands[2]) < -8
2814 && INTVAL (operands[2]) >= -16)
2815 {
c5c76735 2816 operands[2] = GEN_INT (- INTVAL (operands[2]) - 8);
8c61b6c1 2817 return "subq%.l %#8,%0\n\tsubq%.l %2,%0";
9ee3c687
JW
2818 }
2819 }
2820#endif
2821 if (ADDRESS_REG_P (operands[0])
2822 && INTVAL (operands[2]) >= -0x8000
2823 && INTVAL (operands[2]) < 0x8000)
2824 {
2825 if (TARGET_68040)
2826 return "add%.w %2,%0";
2827 else
2828#ifdef MOTOROLA
2829 return "lea (%c2,%0),%0";
2830#else
2831 return "lea %0@(%c2),%0";
2832#endif
2833 }
2834 }
2835 return "add%.l %2,%0";
2836}
79e68feb
RS
2837\f
2838/* Store in cc_status the expressions that the condition codes will
2839 describe after execution of an instruction whose pattern is EXP.
2840 Do not alter them if the instruction would not alter the cc's. */
2841
2842/* On the 68000, all the insns to store in an address register fail to
2843 set the cc's. However, in some cases these instructions can make it
2844 possibly invalid to use the saved cc's. In those cases we clear out
2845 some or all of the saved cc's so they won't be used. */
2846
1d8eaa6b 2847void
79e68feb
RS
2848notice_update_cc (exp, insn)
2849 rtx exp;
2850 rtx insn;
2851{
2852 /* If the cc is being set from the fpa and the expression is not an
2853 explicit floating point test instruction (which has code to deal with
2854 this), reinit the CC. */
2855 if (((cc_status.value1 && FPA_REG_P (cc_status.value1))
2856 || (cc_status.value2 && FPA_REG_P (cc_status.value2)))
2857 && !(GET_CODE (exp) == PARALLEL
2858 && GET_CODE (XVECEXP (exp, 0, 0)) == SET
2859 && XEXP (XVECEXP (exp, 0, 0), 0) == cc0_rtx))
2860 {
2861 CC_STATUS_INIT;
2862 }
2863 else if (GET_CODE (exp) == SET)
2864 {
2865 if (GET_CODE (SET_SRC (exp)) == CALL)
2866 {
2867 CC_STATUS_INIT;
2868 }
2869 else if (ADDRESS_REG_P (SET_DEST (exp)))
2870 {
f5963e61 2871 if (cc_status.value1 && modified_in_p (cc_status.value1, insn))
79e68feb 2872 cc_status.value1 = 0;
f5963e61 2873 if (cc_status.value2 && modified_in_p (cc_status.value2, insn))
79e68feb
RS
2874 cc_status.value2 = 0;
2875 }
2876 else if (!FP_REG_P (SET_DEST (exp))
2877 && SET_DEST (exp) != cc0_rtx
2878 && (FP_REG_P (SET_SRC (exp))
2879 || GET_CODE (SET_SRC (exp)) == FIX
2880 || GET_CODE (SET_SRC (exp)) == FLOAT_TRUNCATE
2881 || GET_CODE (SET_SRC (exp)) == FLOAT_EXTEND))
2882 {
2883 CC_STATUS_INIT;
2884 }
2885 /* A pair of move insns doesn't produce a useful overall cc. */
2886 else if (!FP_REG_P (SET_DEST (exp))
2887 && !FP_REG_P (SET_SRC (exp))
2888 && GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4
2889 && (GET_CODE (SET_SRC (exp)) == REG
2890 || GET_CODE (SET_SRC (exp)) == MEM
2891 || GET_CODE (SET_SRC (exp)) == CONST_DOUBLE))
2892 {
2893 CC_STATUS_INIT;
2894 }
2895 else if (GET_CODE (SET_SRC (exp)) == CALL)
2896 {
2897 CC_STATUS_INIT;
2898 }
2899 else if (XEXP (exp, 0) != pc_rtx)
2900 {
2901 cc_status.flags = 0;
2902 cc_status.value1 = XEXP (exp, 0);
2903 cc_status.value2 = XEXP (exp, 1);
2904 }
2905 }
2906 else if (GET_CODE (exp) == PARALLEL
2907 && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
2908 {
2909 if (ADDRESS_REG_P (XEXP (XVECEXP (exp, 0, 0), 0)))
2910 CC_STATUS_INIT;
2911 else if (XEXP (XVECEXP (exp, 0, 0), 0) != pc_rtx)
2912 {
2913 cc_status.flags = 0;
2914 cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
2915 cc_status.value2 = XEXP (XVECEXP (exp, 0, 0), 1);
2916 }
2917 }
2918 else
2919 CC_STATUS_INIT;
2920 if (cc_status.value2 != 0
2921 && ADDRESS_REG_P (cc_status.value2)
2922 && GET_MODE (cc_status.value2) == QImode)
2923 CC_STATUS_INIT;
2924 if (cc_status.value2 != 0
2925 && !(cc_status.value1 && FPA_REG_P (cc_status.value1)))
2926 switch (GET_CODE (cc_status.value2))
2927 {
2928 case PLUS: case MINUS: case MULT:
2929 case DIV: case UDIV: case MOD: case UMOD: case NEG:
b757e352 2930#if 0 /* These instructions always clear the overflow bit */
996a5f59 2931 case ASHIFT: case ASHIFTRT: case LSHIFTRT:
79e68feb 2932 case ROTATE: case ROTATERT:
b757e352 2933#endif
79e68feb
RS
2934 if (GET_MODE (cc_status.value2) != VOIDmode)
2935 cc_status.flags |= CC_NO_OVERFLOW;
2936 break;
2937 case ZERO_EXTEND:
2938 /* (SET r1 (ZERO_EXTEND r2)) on this machine
2939 ends with a move insn moving r2 in r2's mode.
2940 Thus, the cc's are set for r2.
7a1929e1 2941 This can set N bit spuriously. */
79e68feb 2942 cc_status.flags |= CC_NOT_NEGATIVE;
1d8eaa6b
AS
2943
2944 default:
2945 break;
79e68feb
RS
2946 }
2947 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
2948 && cc_status.value2
2949 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
2950 cc_status.value2 = 0;
2951 if (((cc_status.value1 && FP_REG_P (cc_status.value1))
2952 || (cc_status.value2 && FP_REG_P (cc_status.value2)))
2953 && !((cc_status.value1 && FPA_REG_P (cc_status.value1))
2954 || (cc_status.value2 && FPA_REG_P (cc_status.value2))))
2955 cc_status.flags = CC_IN_68881;
2956}
2957\f
5505f548 2958const char *
79e68feb
RS
2959output_move_const_double (operands)
2960 rtx *operands;
2961{
2962#ifdef SUPPORT_SUN_FPA
64a184e9 2963 if (TARGET_FPA && FPA_REG_P (operands[0]))
79e68feb
RS
2964 {
2965 int code = standard_sun_fpa_constant_p (operands[1]);
2966
2967 if (code != 0)
2968 {
2969 static char buf[40];
2970
2971 sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff);
2972 return buf;
2973 }
2974 return "fpmove%.d %1,%0";
2975 }
2976 else
2977#endif
2978 {
2979 int code = standard_68881_constant_p (operands[1]);
2980
2981 if (code != 0)
2982 {
2983 static char buf[40];
2984
2985 sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
2986 return buf;
2987 }
2988 return "fmove%.d %1,%0";
2989 }
2990}
2991
5505f548 2992const char *
79e68feb
RS
2993output_move_const_single (operands)
2994 rtx *operands;
2995{
2996#ifdef SUPPORT_SUN_FPA
2997 if (TARGET_FPA)
2998 {
2999 int code = standard_sun_fpa_constant_p (operands[1]);
3000
3001 if (code != 0)
3002 {
3003 static char buf[40];
3004
3005 sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff);
3006 return buf;
3007 }
3008 return "fpmove%.s %1,%0";
3009 }
3010 else
3011#endif /* defined SUPPORT_SUN_FPA */
3012 {
3013 int code = standard_68881_constant_p (operands[1]);
3014
3015 if (code != 0)
3016 {
3017 static char buf[40];
3018
3019 sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
3020 return buf;
3021 }
3022 return "fmove%.s %f1,%0";
3023 }
3024}
3025
3026/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
3027 from the "fmovecr" instruction.
3028 The value, anded with 0xff, gives the code to use in fmovecr
3029 to get the desired constant. */
3030
7a1929e1 3031/* This code has been fixed for cross-compilation. */
c1cfb2ae
RS
3032
3033static int inited_68881_table = 0;
3034
5505f548 3035static const char *const strings_68881[7] = {
c1cfb2ae
RS
3036 "0.0",
3037 "1.0",
3038 "10.0",
3039 "100.0",
3040 "10000.0",
3041 "1e8",
3042 "1e16"
3043 };
3044
8b60264b 3045static const int codes_68881[7] = {
c1cfb2ae
RS
3046 0x0f,
3047 0x32,
3048 0x33,
3049 0x34,
3050 0x35,
3051 0x36,
3052 0x37
3053 };
3054
3055REAL_VALUE_TYPE values_68881[7];
3056
3057/* Set up values_68881 array by converting the decimal values
7a1929e1 3058 strings_68881 to binary. */
c1cfb2ae
RS
3059
3060void
3061init_68881_table ()
3062{
3063 int i;
3064 REAL_VALUE_TYPE r;
3065 enum machine_mode mode;
3066
16d82c3c 3067 mode = SFmode;
c1cfb2ae
RS
3068 for (i = 0; i < 7; i++)
3069 {
3070 if (i == 6)
16d82c3c 3071 mode = DFmode;
c1cfb2ae
RS
3072 r = REAL_VALUE_ATOF (strings_68881[i], mode);
3073 values_68881[i] = r;
3074 }
3075 inited_68881_table = 1;
3076}
79e68feb
RS
3077
3078int
3079standard_68881_constant_p (x)
3080 rtx x;
3081{
c1cfb2ae
RS
3082 REAL_VALUE_TYPE r;
3083 int i;
79e68feb 3084
a5d54cc5
RK
3085#ifdef NO_ASM_FMOVECR
3086 return 0;
3087#endif
3088
e18db50d 3089 /* fmovecr must be emulated on the 68040 and 68060, so it shouldn't be
7a1929e1 3090 used at all on those chips. */
e18db50d 3091 if (TARGET_68040 || TARGET_68060)
79e68feb
RS
3092 return 0;
3093
c1cfb2ae 3094#ifndef REAL_ARITHMETIC
79e68feb
RS
3095#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
3096 if (! flag_pretend_float)
3097 return 0;
c1cfb2ae 3098#endif
79e68feb
RS
3099#endif
3100
c1cfb2ae
RS
3101 if (! inited_68881_table)
3102 init_68881_table ();
3103
3104 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
3105
64c0b414
AS
3106 /* Use REAL_VALUES_IDENTICAL instead of REAL_VALUES_EQUAL so that -0.0
3107 is rejected. */
c1cfb2ae
RS
3108 for (i = 0; i < 6; i++)
3109 {
64c0b414 3110 if (REAL_VALUES_IDENTICAL (r, values_68881[i]))
c1cfb2ae
RS
3111 return (codes_68881[i]);
3112 }
3113
79e68feb
RS
3114 if (GET_MODE (x) == SFmode)
3115 return 0;
c1cfb2ae
RS
3116
3117 if (REAL_VALUES_EQUAL (r, values_68881[6]))
3118 return (codes_68881[6]);
3119
79e68feb
RS
3120 /* larger powers of ten in the constants ram are not used
3121 because they are not equal to a `double' C constant. */
3122 return 0;
3123}
3124
3125/* If X is a floating-point constant, return the logarithm of X base 2,
3126 or 0 if X is not a power of 2. */
3127
3128int
3129floating_exact_log2 (x)
3130 rtx x;
3131{
c1cfb2ae 3132 REAL_VALUE_TYPE r, r1;
79e68feb
RS
3133 int i;
3134
c1cfb2ae 3135#ifndef REAL_ARITHMETIC
79e68feb
RS
3136#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
3137 if (! flag_pretend_float)
3138 return 0;
c1cfb2ae 3139#endif
79e68feb
RS
3140#endif
3141
c1cfb2ae 3142 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
79e68feb 3143
c1cfb2ae 3144 if (REAL_VALUES_LESS (r, dconst0))
79e68feb
RS
3145 return 0;
3146
6b62e557 3147 r1 = dconst1;
c1cfb2ae
RS
3148 i = 0;
3149 while (REAL_VALUES_LESS (r1, r))
3150 {
3151 r1 = REAL_VALUE_LDEXP (dconst1, i);
3152 if (REAL_VALUES_EQUAL (r1, r))
3153 return i;
3154 i = i + 1;
3155 }
79e68feb
RS
3156 return 0;
3157}
3158\f
3159#ifdef SUPPORT_SUN_FPA
3160/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
3161 from the Sun FPA's constant RAM.
3162 The value returned, anded with 0x1ff, gives the code to use in fpmove
7a1929e1 3163 to get the desired constant. */
c1cfb2ae
RS
3164
3165static int inited_FPA_table = 0;
3166
5505f548 3167static const char *const strings_FPA[38] = {
c1cfb2ae
RS
3168/* small rationals */
3169 "0.0",
3170 "1.0",
3171 "0.5",
3172 "-1.0",
3173 "2.0",
3174 "3.0",
3175 "4.0",
3176 "8.0",
3177 "0.25",
3178 "0.125",
3179 "10.0",
3180 "-0.5",
3181/* Decimal equivalents of double precision values */
3182 "2.718281828459045091", /* D_E */
3183 "6.283185307179586477", /* 2 pi */
3184 "3.141592653589793116", /* D_PI */
3185 "1.570796326794896619", /* pi/2 */
3186 "1.414213562373095145", /* D_SQRT2 */
3187 "0.7071067811865475244", /* 1/sqrt(2) */
3188 "-1.570796326794896619", /* -pi/2 */
3189 "1.442695040888963387", /* D_LOG2ofE */
3190 "3.321928024887362182", /* D_LOG2of10 */
3191 "0.6931471805599452862", /* D_LOGEof2 */
3192 "2.302585092994045901", /* D_LOGEof10 */
3193 "0.3010299956639811980", /* D_LOG10of2 */
3194 "0.4342944819032518167", /* D_LOG10ofE */
3195/* Decimal equivalents of single precision values */
3196 "2.718281745910644531", /* S_E */
3197 "6.283185307179586477", /* 2 pi */
3198 "3.141592741012573242", /* S_PI */
3199 "1.570796326794896619", /* pi/2 */
3200 "1.414213538169860840", /* S_SQRT2 */
3201 "0.7071067811865475244", /* 1/sqrt(2) */
3202 "-1.570796326794896619", /* -pi/2 */
3203 "1.442695021629333496", /* S_LOG2ofE */
3204 "3.321928024291992188", /* S_LOG2of10 */
3205 "0.6931471824645996094", /* S_LOGEof2 */
3206 "2.302585124969482442", /* S_LOGEof10 */
3207 "0.3010300099849700928", /* S_LOG10of2 */
3208 "0.4342944920063018799", /* S_LOG10ofE */
3209};
3210
3211
8b60264b 3212static const int codes_FPA[38] = {
c1cfb2ae
RS
3213/* small rationals */
3214 0x200,
3215 0xe,
3216 0xf,
3217 0x10,
3218 0x11,
3219 0xb1,
3220 0x12,
3221 0x13,
3222 0x15,
3223 0x16,
3224 0x17,
3225 0x2e,
3226/* double precision */
3227 0x8,
3228 0x9,
3229 0xa,
3230 0xb,
3231 0xc,
3232 0xd,
3233 0x27,
3234 0x28,
3235 0x29,
3236 0x2a,
3237 0x2b,
3238 0x2c,
3239 0x2d,
3240/* single precision */
3241 0x8,
3242 0x9,
3243 0xa,
3244 0xb,
3245 0xc,
3246 0xd,
3247 0x27,
3248 0x28,
3249 0x29,
3250 0x2a,
3251 0x2b,
3252 0x2c,
3253 0x2d
3254 };
3255
3256REAL_VALUE_TYPE values_FPA[38];
3257
7a1929e1 3258/* This code has been fixed for cross-compilation. */
c1cfb2ae 3259
22036103
KG
3260static void init_FPA_table PARAMS ((void));
3261static void
c1cfb2ae
RS
3262init_FPA_table ()
3263{
3264 enum machine_mode mode;
3265 int i;
3266 REAL_VALUE_TYPE r;
3267
3268 mode = DFmode;
3269 for (i = 0; i < 38; i++)
3270 {
3271 if (i == 25)
3272 mode = SFmode;
3273 r = REAL_VALUE_ATOF (strings_FPA[i], mode);
3274 values_FPA[i] = r;
3275 }
3276 inited_FPA_table = 1;
3277}
3278
79e68feb
RS
3279
3280int
3281standard_sun_fpa_constant_p (x)
3282 rtx x;
3283{
c1cfb2ae
RS
3284 REAL_VALUE_TYPE r;
3285 int i;
79e68feb 3286
c1cfb2ae 3287#ifndef REAL_ARITHMETIC
79e68feb
RS
3288#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
3289 if (! flag_pretend_float)
3290 return 0;
3291#endif
c1cfb2ae
RS
3292#endif
3293
3294 if (! inited_FPA_table)
3295 init_FPA_table ();
3296
3297 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
3298
3299 for (i=0; i<12; i++)
3300 {
3301 if (REAL_VALUES_EQUAL (r, values_FPA[i]))
3302 return (codes_FPA[i]);
3303 }
79e68feb 3304
64a184e9 3305 if (GET_MODE (x) == SFmode)
79e68feb 3306 {
c1cfb2ae
RS
3307 for (i=25; i<38; i++)
3308 {
3309 if (REAL_VALUES_EQUAL (r, values_FPA[i]))
3310 return (codes_FPA[i]);
3311 }
79e68feb
RS
3312 }
3313 else
3314 {
c1cfb2ae
RS
3315 for (i=12; i<25; i++)
3316 {
3317 if (REAL_VALUES_EQUAL (r, values_FPA[i]))
3318 return (codes_FPA[i]);
3319 }
79e68feb
RS
3320 }
3321 return 0x0;
3322}
3323#endif /* define SUPPORT_SUN_FPA */
3324\f
3325/* A C compound statement to output to stdio stream STREAM the
3326 assembler syntax for an instruction operand X. X is an RTL
3327 expression.
3328
3329 CODE is a value that can be used to specify one of several ways
3330 of printing the operand. It is used when identical operands
3331 must be printed differently depending on the context. CODE
3332 comes from the `%' specification that was used to request
3333 printing of the operand. If the specification was just `%DIGIT'
3334 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
3335 is the ASCII code for LTR.
3336
3337 If X is a register, this macro should print the register's name.
3338 The names can be found in an array `reg_names' whose type is
3339 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
3340
3341 When the machine description has a specification `%PUNCT' (a `%'
3342 followed by a punctuation character), this macro is called with
3343 a null pointer for X and the punctuation character for CODE.
3344
3345 The m68k specific codes are:
3346
3347 '.' for dot needed in Motorola-style opcode names.
3348 '-' for an operand pushing on the stack:
3349 sp@-, -(sp) or -(%sp) depending on the style of syntax.
3350 '+' for an operand pushing on the stack:
3351 sp@+, (sp)+ or (%sp)+ depending on the style of syntax.
3352 '@' for a reference to the top word on the stack:
3353 sp@, (sp) or (%sp) depending on the style of syntax.
3354 '#' for an immediate operand prefix (# in MIT and Motorola syntax
a7e2b014 3355 but & in SGS syntax, $ in CRDS/UNOS syntax).
79e68feb
RS
3356 '!' for the cc register (used in an `and to cc' insn).
3357 '$' for the letter `s' in an op code, but only on the 68040.
3358 '&' for the letter `d' in an op code, but only on the 68040.
2ac5f14a 3359 '/' for register prefix needed by longlong.h.
79e68feb
RS
3360
3361 'b' for byte insn (no effect, on the Sun; this is for the ISI).
3362 'd' to force memory addressing to be absolute, not relative.
3363 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex)
2c8ec431
DL
3364 'o' for operands to go directly to output_operand_address (bypassing
3365 print_operand_address--used only for SYMBOL_REFs under TARGET_PCREL)
79e68feb
RS
3366 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather
3367 than directly). Second part of 'y' below.
3368 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex),
3369 or print pair of registers as rx:ry.
3370 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs
3371 CONST_DOUBLE's as SunFPA constant RAM registers if
3372 possible, so it should not be used except for the SunFPA.
3373
3374 */
3375
3376void
3377print_operand (file, op, letter)
3378 FILE *file; /* file to write to */
3379 rtx op; /* operand to print */
3380 int letter; /* %<letter> or 0 */
3381{
1d8eaa6b 3382#ifdef SUPPORT_SUN_FPA
79e68feb 3383 int i;
1d8eaa6b 3384#endif
79e68feb
RS
3385
3386 if (letter == '.')
3387 {
a7e2b014 3388#if defined (MOTOROLA) && !defined (CRDS)
79e68feb
RS
3389 asm_fprintf (file, ".");
3390#endif
3391 }
3392 else if (letter == '#')
3393 {
cffd0d74 3394 asm_fprintf (file, "%0I");
79e68feb
RS
3395 }
3396 else if (letter == '-')
3397 {
3398#ifdef MOTOROLA
3399 asm_fprintf (file, "-(%Rsp)");
3400#else
3401 asm_fprintf (file, "%Rsp@-");
3402#endif
3403 }
3404 else if (letter == '+')
3405 {
3406#ifdef MOTOROLA
3407 asm_fprintf (file, "(%Rsp)+");
3408#else
3409 asm_fprintf (file, "%Rsp@+");
3410#endif
3411 }
3412 else if (letter == '@')
3413 {
3414#ifdef MOTOROLA
3415 asm_fprintf (file, "(%Rsp)");
3416#else
3417 asm_fprintf (file, "%Rsp@");
3418#endif
3419 }
3420 else if (letter == '!')
3421 {
cffd0d74 3422 asm_fprintf (file, "%Rfpcr");
79e68feb
RS
3423 }
3424 else if (letter == '$')
3425 {
3426 if (TARGET_68040_ONLY)
3427 {
3428 fprintf (file, "s");
3429 }
3430 }
3431 else if (letter == '&')
3432 {
3433 if (TARGET_68040_ONLY)
3434 {
3435 fprintf (file, "d");
3436 }
3437 }
2ac5f14a
ILT
3438 else if (letter == '/')
3439 {
3440 asm_fprintf (file, "%R");
3441 }
2c8ec431
DL
3442 else if (letter == 'o')
3443 {
3444 /* This is only for direct addresses with TARGET_PCREL */
3445 if (GET_CODE (op) != MEM || GET_CODE (XEXP (op, 0)) != SYMBOL_REF
3446 || !TARGET_PCREL)
3447 abort ();
3448 output_addr_const (file, XEXP (op, 0));
3449 }
79e68feb
RS
3450 else if (GET_CODE (op) == REG)
3451 {
f4a6e73b 3452#ifdef SUPPORT_SUN_FPA
79e68feb
RS
3453 if (REGNO (op) < 16
3454 && (letter == 'y' || letter == 'x')
3455 && GET_MODE (op) == DFmode)
3456 {
3457 fprintf (file, "%s:%s", reg_names[REGNO (op)],
3458 reg_names[REGNO (op)+1]);
3459 }
3460 else
f4a6e73b 3461#endif
79e68feb 3462 {
7f49c331
RK
3463 if (letter == 'R')
3464 /* Print out the second register name of a register pair.
3465 I.e., R (6) => 7. */
3466 fputs (reg_names[REGNO (op) + 1], file);
3467 else
3468 fputs (reg_names[REGNO (op)], file);
79e68feb
RS
3469 }
3470 }
3471 else if (GET_CODE (op) == MEM)
3472 {
3473 output_address (XEXP (op, 0));
3474 if (letter == 'd' && ! TARGET_68020
3475 && CONSTANT_ADDRESS_P (XEXP (op, 0))
3476 && !(GET_CODE (XEXP (op, 0)) == CONST_INT
3477 && INTVAL (XEXP (op, 0)) < 0x8000
3478 && INTVAL (XEXP (op, 0)) >= -0x8000))
3479 {
3f889ae8
RK
3480#ifdef MOTOROLA
3481 fprintf (file, ".l");
3482#else
79e68feb 3483 fprintf (file, ":l");
3f889ae8 3484#endif
79e68feb
RS
3485 }
3486 }
3487#ifdef SUPPORT_SUN_FPA
3488 else if ((letter == 'y' || letter == 'w')
64a184e9 3489 && GET_CODE (op) == CONST_DOUBLE
79e68feb
RS
3490 && (i = standard_sun_fpa_constant_p (op)))
3491 {
3492 fprintf (file, "%%%d", i & 0x1ff);
3493 }
3494#endif
3495 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
3496 {
c1cfb2ae
RS
3497 REAL_VALUE_TYPE r;
3498 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
3499 ASM_OUTPUT_FLOAT_OPERAND (letter, file, r);
3500 }
3501 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode)
3502 {
3503 REAL_VALUE_TYPE r;
3504 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
3505 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r);
79e68feb 3506 }
e2c0a924 3507 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
79e68feb 3508 {
c1cfb2ae
RS
3509 REAL_VALUE_TYPE r;
3510 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
3511 ASM_OUTPUT_DOUBLE_OPERAND (file, r);
79e68feb
RS
3512 }
3513 else
3514 {
2c8ec431
DL
3515 /* Use `print_operand_address' instead of `output_addr_const'
3516 to ensure that we print relevant PIC stuff. */
3517 asm_fprintf (file, "%0I");
3518 if (TARGET_PCREL
3519 && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST))
3520 print_operand_address (file, op);
3521 else
3522 output_addr_const (file, op);
79e68feb
RS
3523 }
3524}
3525
3526\f
3527/* A C compound statement to output to stdio stream STREAM the
3528 assembler syntax for an instruction operand that is a memory
3529 reference whose address is ADDR. ADDR is an RTL expression.
3530
3531 Note that this contains a kludge that knows that the only reason
3532 we have an address (plus (label_ref...) (reg...)) when not generating
3533 PIC code is in the insn before a tablejump, and we know that m68k.md
3534 generates a label LInnn: on such an insn.
3535
3536 It is possible for PIC to generate a (plus (label_ref...) (reg...))
3537 and we handle that just like we would a (plus (symbol_ref...) (reg...)).
3538
3539 Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)"
3540 fails to assemble. Luckily "Lnnn(pc,d0.l*2)" produces the results
3541 we want. This difference can be accommodated by using an assembler
3542 define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other
3543 string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END
ad7c12b2 3544 macro. See m68k/sgs.h for an example; for versions without the bug.
f4a6e73b
RK
3545 Some assemblers refuse all the above solutions. The workaround is to
3546 emit "K(pc,d0.l*2)" with K being a small constant known to give the
3547 right behaviour.
79e68feb
RS
3548
3549 They also do not like things like "pea 1.w", so we simple leave off
3550 the .w on small constants.
3551
3552 This routine is responsible for distinguishing between -fpic and -fPIC
3553 style relocations in an address. When generating -fpic code the
3554 offset is output in word mode (eg movel a5@(_foo:w), a0). When generating
3555 -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */
3556
f4a6e73b
RK
3557#ifndef ASM_OUTPUT_CASE_FETCH
3558#ifdef MOTOROLA
3559#ifdef SGS
3560#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
3561 asm_fprintf (file, "%LLD%d(%Rpc,%s.", labelno, regname)
3562#else
3563#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
3564 asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.", labelno, labelno, regname)
3565#endif
3566#else
3567#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
3568 asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:", labelno, labelno, regname)
3569#endif
3570#endif /* ASM_OUTPUT_CASE_FETCH */
3571
79e68feb
RS
3572void
3573print_operand_address (file, addr)
3574 FILE *file;
3575 rtx addr;
3576{
3577 register rtx reg1, reg2, breg, ireg;
3578 rtx offset;
3579
3580 switch (GET_CODE (addr))
3581 {
3582 case REG:
3583#ifdef MOTOROLA
3584 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
3585#else
3586 fprintf (file, "%s@", reg_names[REGNO (addr)]);
3587#endif
3588 break;
3589 case PRE_DEC:
3590#ifdef MOTOROLA
3591 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
3592#else
3593 fprintf (file, "%s@-", reg_names[REGNO (XEXP (addr, 0))]);
3594#endif
3595 break;
3596 case POST_INC:
3597#ifdef MOTOROLA
3598 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
3599#else
3600 fprintf (file, "%s@+", reg_names[REGNO (XEXP (addr, 0))]);
3601#endif
3602 break;
3603 case PLUS:
3604 reg1 = reg2 = ireg = breg = offset = 0;
3605 if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
3606 {
3607 offset = XEXP (addr, 0);
3608 addr = XEXP (addr, 1);
3609 }
3610 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
3611 {
3612 offset = XEXP (addr, 1);
3613 addr = XEXP (addr, 0);
3614 }
3615 if (GET_CODE (addr) != PLUS)
3616 {
3617 ;
3618 }
3619 else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND)
3620 {
3621 reg1 = XEXP (addr, 0);
3622 addr = XEXP (addr, 1);
3623 }
3624 else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND)
3625 {
3626 reg1 = XEXP (addr, 1);
3627 addr = XEXP (addr, 0);
3628 }
3629 else if (GET_CODE (XEXP (addr, 0)) == MULT)
3630 {
3631 reg1 = XEXP (addr, 0);
3632 addr = XEXP (addr, 1);
3633 }
3634 else if (GET_CODE (XEXP (addr, 1)) == MULT)
3635 {
3636 reg1 = XEXP (addr, 1);
3637 addr = XEXP (addr, 0);
3638 }
3639 else if (GET_CODE (XEXP (addr, 0)) == REG)
3640 {
3641 reg1 = XEXP (addr, 0);
3642 addr = XEXP (addr, 1);
3643 }
3644 else if (GET_CODE (XEXP (addr, 1)) == REG)
3645 {
3646 reg1 = XEXP (addr, 1);
3647 addr = XEXP (addr, 0);
3648 }
3649 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT
3650 || GET_CODE (addr) == SIGN_EXTEND)
3651 {
3652 if (reg1 == 0)
3653 {
3654 reg1 = addr;
3655 }
3656 else
3657 {
3658 reg2 = addr;
3659 }
3660 addr = 0;
3661 }
3662#if 0 /* for OLD_INDEXING */
3663 else if (GET_CODE (addr) == PLUS)
3664 {
3665 if (GET_CODE (XEXP (addr, 0)) == REG)
3666 {
3667 reg2 = XEXP (addr, 0);
3668 addr = XEXP (addr, 1);
3669 }
3670 else if (GET_CODE (XEXP (addr, 1)) == REG)
3671 {
3672 reg2 = XEXP (addr, 1);
3673 addr = XEXP (addr, 0);
3674 }
3675 }
3676#endif
3677 if (offset != 0)
3678 {
3679 if (addr != 0)
3680 {
3681 abort ();
3682 }
3683 addr = offset;
3684 }
3685 if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND
3686 || GET_CODE (reg1) == MULT))
3687 || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
3688 {
3689 breg = reg2;
3690 ireg = reg1;
3691 }
3692 else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
3693 {
3694 breg = reg1;
3695 ireg = reg2;
3696 }
3697 if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF
63d415c0 3698 && ! (flag_pic && ireg == pic_offset_table_rtx))
79e68feb
RS
3699 {
3700 int scale = 1;
3701 if (GET_CODE (ireg) == MULT)
3702 {
3703 scale = INTVAL (XEXP (ireg, 1));
3704 ireg = XEXP (ireg, 0);
3705 }
3706 if (GET_CODE (ireg) == SIGN_EXTEND)
3707 {
f4a6e73b 3708 ASM_OUTPUT_CASE_FETCH (file,
79e68feb
RS
3709 CODE_LABEL_NUMBER (XEXP (addr, 0)),
3710 reg_names[REGNO (XEXP (ireg, 0))]);
f4a6e73b 3711 fprintf (file, "w");
79e68feb
RS
3712 }
3713 else
3714 {
f4a6e73b 3715 ASM_OUTPUT_CASE_FETCH (file,
79e68feb
RS
3716 CODE_LABEL_NUMBER (XEXP (addr, 0)),
3717 reg_names[REGNO (ireg)]);
f4a6e73b 3718 fprintf (file, "l");
79e68feb
RS
3719 }
3720 if (scale != 1)
3721 {
3722#ifdef MOTOROLA
3723 fprintf (file, "*%d", scale);
3724#else
3725 fprintf (file, ":%d", scale);
3726#endif
3727 }
3728 putc (')', file);
3729 break;
3730 }
3731 if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF
63d415c0 3732 && ! (flag_pic && breg == pic_offset_table_rtx))
79e68feb 3733 {
f4a6e73b 3734 ASM_OUTPUT_CASE_FETCH (file,
79e68feb
RS
3735 CODE_LABEL_NUMBER (XEXP (addr, 0)),
3736 reg_names[REGNO (breg)]);
f4a6e73b 3737 fprintf (file, "l)");
79e68feb
RS
3738 break;
3739 }
3740 if (ireg != 0 || breg != 0)
3741 {
3742 int scale = 1;
3743 if (breg == 0)
3744 {
3745 abort ();
3746 }
3747 if (! flag_pic && addr && GET_CODE (addr) == LABEL_REF)
3748 {
3749 abort ();
3750 }
3751#ifdef MOTOROLA
3752 if (addr != 0)
3753 {
3754 output_addr_const (file, addr);
66c432a7 3755 if (flag_pic && (breg == pic_offset_table_rtx))
e9a25f70
JL
3756 {
3757 fprintf (file, "@GOT");
3758 if (flag_pic == 1)
3759 fprintf (file, ".w");
3760 }
79e68feb
RS
3761 }
3762 fprintf (file, "(%s", reg_names[REGNO (breg)]);
3763 if (ireg != 0)
3764 {
3765 putc (',', file);
3766 }
3767#else
3768 fprintf (file, "%s@(", reg_names[REGNO (breg)]);
3769 if (addr != 0)
3770 {
3771 output_addr_const (file, addr);
3772 if ((flag_pic == 1) && (breg == pic_offset_table_rtx))
3773 fprintf (file, ":w");
3774 if ((flag_pic == 2) && (breg == pic_offset_table_rtx))
3775 fprintf (file, ":l");
3776 }
3777 if (addr != 0 && ireg != 0)
3778 {
3779 putc (',', file);
3780 }
3781#endif
3782 if (ireg != 0 && GET_CODE (ireg) == MULT)
3783 {
3784 scale = INTVAL (XEXP (ireg, 1));
3785 ireg = XEXP (ireg, 0);
3786 }
3787 if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND)
3788 {
3789#ifdef MOTOROLA
3790 fprintf (file, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]);
3791#else
3792 fprintf (file, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]);
3793#endif
3794 }
3795 else if (ireg != 0)
3796 {
3797#ifdef MOTOROLA
3798 fprintf (file, "%s.l", reg_names[REGNO (ireg)]);
3799#else
3800 fprintf (file, "%s:l", reg_names[REGNO (ireg)]);
3801#endif
3802 }
3803 if (scale != 1)
3804 {
3805#ifdef MOTOROLA
3806 fprintf (file, "*%d", scale);
3807#else
3808 fprintf (file, ":%d", scale);
3809#endif
3810 }
3811 putc (')', file);
3812 break;
3813 }
3814 else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF
63d415c0 3815 && ! (flag_pic && reg1 == pic_offset_table_rtx))
79e68feb 3816 {
f4a6e73b 3817 ASM_OUTPUT_CASE_FETCH (file,
79e68feb
RS
3818 CODE_LABEL_NUMBER (XEXP (addr, 0)),
3819 reg_names[REGNO (reg1)]);
f4a6e73b 3820 fprintf (file, "l)");
79e68feb
RS
3821 break;
3822 }
2c8ec431 3823 /* FALL-THROUGH (is this really what we want?) */
79e68feb
RS
3824 default:
3825 if (GET_CODE (addr) == CONST_INT
3826 && INTVAL (addr) < 0x8000
3827 && INTVAL (addr) >= -0x8000)
3828 {
3829#ifdef MOTOROLA
3830#ifdef SGS
7a1929e1 3831 /* Many SGS assemblers croak on size specifiers for constants. */
6d5f49b2 3832 fprintf (file, "%d", (int) INTVAL (addr));
79e68feb 3833#else
6d5f49b2 3834 fprintf (file, "%d.w", (int) INTVAL (addr));
79e68feb
RS
3835#endif
3836#else
6d5f49b2 3837 fprintf (file, "%d:w", (int) INTVAL (addr));
79e68feb
RS
3838#endif
3839 }
2c8ec431
DL
3840 else if (GET_CODE (addr) == CONST_INT)
3841 {
6d5f49b2 3842 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2c8ec431
DL
3843 }
3844 else if (TARGET_PCREL)
3845 {
3846 fputc ('(', file);
3847 output_addr_const (file, addr);
3848 if (flag_pic == 1)
3849 asm_fprintf (file, ":w,%Rpc)");
3850 else
3851 asm_fprintf (file, ":l,%Rpc)");
3852 }
79e68feb
RS
3853 else
3854 {
c2ac2ff6
AS
3855 /* Special case for SYMBOL_REF if the symbol name ends in
3856 `.<letter>', this can be mistaken as a size suffix. Put
3857 the name in parentheses. */
3858 if (GET_CODE (addr) == SYMBOL_REF
3859 && strlen (XSTR (addr, 0)) > 2
3860 && XSTR (addr, 0)[strlen (XSTR (addr, 0)) - 2] == '.')
3861 {
3862 putc ('(', file);
3863 output_addr_const (file, addr);
3864 putc (')', file);
3865 }
3866 else
3867 output_addr_const (file, addr);
79e68feb
RS
3868 }
3869 break;
3870 }
3871}
af13f02d
JW
3872\f
3873/* Check for cases where a clr insns can be omitted from code using
3874 strict_low_part sets. For example, the second clrl here is not needed:
3875 clrl d0; movw a0@+,d0; use d0; clrl d0; movw a0@+; use d0; ...
3876
3877 MODE is the mode of this STRICT_LOW_PART set. FIRST_INSN is the clear
3878 insn we are checking for redundancy. TARGET is the register set by the
3879 clear insn. */
3880
3881int
3882strict_low_part_peephole_ok (mode, first_insn, target)
3883 enum machine_mode mode;
3884 rtx first_insn;
3885 rtx target;
3886{
3887 rtx p;
3888
3889 p = prev_nonnote_insn (first_insn);
3890
3891 while (p)
3892 {
3893 /* If it isn't an insn, then give up. */
3894 if (GET_CODE (p) != INSN)
3895 return 0;
3896
3897 if (reg_set_p (target, p))
3898 {
3899 rtx set = single_set (p);
3900 rtx dest;
3901
3902 /* If it isn't an easy to recognize insn, then give up. */
3903 if (! set)
3904 return 0;
3905
3906 dest = SET_DEST (set);
3907
3908 /* If this sets the entire target register to zero, then our
3909 first_insn is redundant. */
3910 if (rtx_equal_p (dest, target)
3911 && SET_SRC (set) == const0_rtx)
3912 return 1;
3913 else if (GET_CODE (dest) == STRICT_LOW_PART
3914 && GET_CODE (XEXP (dest, 0)) == REG
3915 && REGNO (XEXP (dest, 0)) == REGNO (target)
3916 && (GET_MODE_SIZE (GET_MODE (XEXP (dest, 0)))
3917 <= GET_MODE_SIZE (mode)))
3918 /* This is a strict low part set which modifies less than
3919 we are using, so it is safe. */
3920 ;
3921 else
3922 return 0;
3923 }
3924
3925 p = prev_nonnote_insn (p);
3926
3927 }
3928
3929 return 0;
3930}
67cd4f83
TG
3931
3932/* Accept integer operands in the range 0..0xffffffff. We have to check the
3933 range carefully since this predicate is used in DImode contexts. Also, we
3934 need some extra crud to make it work when hosted on 64-bit machines. */
3935
3936int
3937const_uint32_operand (op, mode)
3938 rtx op;
97660e20 3939 enum machine_mode mode;
67cd4f83 3940{
97660e20
RH
3941 /* It doesn't make sense to ask this question with a mode that is
3942 not larger than 32 bits. */
3943 if (GET_MODE_BITSIZE (mode) <= 32)
3944 abort ();
3945
67cd4f83
TG
3946#if HOST_BITS_PER_WIDE_INT > 32
3947 /* All allowed constants will fit a CONST_INT. */
3948 return (GET_CODE (op) == CONST_INT
3949 && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL));
3950#else
07ed7ecf 3951 return (GET_CODE (op) == CONST_INT
67cd4f83
TG
3952 || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0));
3953#endif
3954}
3955
3956/* Accept integer operands in the range -0x80000000..0x7fffffff. We have
3957 to check the range carefully since this predicate is used in DImode
3958 contexts. */
3959
3960int
3961const_sint32_operand (op, mode)
3962 rtx op;
97660e20 3963 enum machine_mode mode;
67cd4f83 3964{
97660e20
RH
3965 /* It doesn't make sense to ask this question with a mode that is
3966 not larger than 32 bits. */
3967 if (GET_MODE_BITSIZE (mode) <= 32)
3968 abort ();
3969
67cd4f83
TG
3970 /* All allowed constants will fit a CONST_INT. */
3971 return (GET_CODE (op) == CONST_INT
3972 && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));
3973}
29ae8a3c 3974
2c8ec431
DL
3975/* Operand predicates for implementing asymmetric pc-relative addressing
3976 on m68k. The m68k supports pc-relative addressing (mode 7, register 2)
3977 when used as a source operand, but not as a destintation operand.
3978
3979 We model this by restricting the meaning of the basic predicates
3980 (general_operand, memory_operand, etc) to forbid the use of this
3981 addressing mode, and then define the following predicates that permit
3982 this addressing mode. These predicates can then be used for the
3983 source operands of the appropriate instructions.
3984
3985 n.b. While it is theoretically possible to change all machine patterns
3986 to use this addressing more where permitted by the architecture,
3987 it has only been implemented for "common" cases: SImode, HImode, and
3988 QImode operands, and only for the principle operations that would
3989 require this addressing mode: data movement and simple integer operations.
3990
3991 In parallel with these new predicates, two new constraint letters
3992 were defined: 'S' and 'T'. 'S' is the -mpcrel analog of 'm'.
3993 'T' replaces 's' in the non-pcrel case. It is a no-op in the pcrel case.
3994 In the pcrel case 's' is only valid in combination with 'a' registers.
3995 See addsi3, subsi3, cmpsi, and movsi patterns for a better understanding
3996 of how these constraints are used.
3997
3998 The use of these predicates is strictly optional, though patterns that
3999 don't will cause an extra reload register to be allocated where one
4000 was not necessary:
4001
4002 lea (abc:w,%pc),%a0 ; need to reload address
4003 moveq &1,%d1 ; since write to pc-relative space
4004 movel %d1,%a0@ ; is not allowed
4005 ...
4006 lea (abc:w,%pc),%a1 ; no need to reload address here
4007 movel %a1@,%d0 ; since "movel (abc:w,%pc),%d0" is ok
4008
4009 For more info, consult tiemann@cygnus.com.
4010
4011
4012 All of the ugliness with predicates and constraints is due to the
4013 simple fact that the m68k does not allow a pc-relative addressing
4014 mode as a destination. gcc does not distinguish between source and
4015 destination addresses. Hence, if we claim that pc-relative address
4016 modes are valid, e.g. GO_IF_LEGITIMATE_ADDRESS accepts them, then we
4017 end up with invalid code. To get around this problem, we left
4018 pc-relative modes as invalid addresses, and then added special
4019 predicates and constraints to accept them.
4020
4021 A cleaner way to handle this is to modify gcc to distinguish
4022 between source and destination addresses. We can then say that
4023 pc-relative is a valid source address but not a valid destination
4024 address, and hopefully avoid a lot of the predicate and constraint
4025 hackery. Unfortunately, this would be a pretty big change. It would
4026 be a useful change for a number of ports, but there aren't any current
4027 plans to undertake this.
4028
4029 ***************************************************************************/
4030
4031
4032/* Special case of a general operand that's used as a source operand.
4033 Use this to permit reads from PC-relative memory when -mpcrel
4034 is specified. */
4035
4036int
4037general_src_operand (op, mode)
4038 rtx op;
4039 enum machine_mode mode;
4040{
4041 if (TARGET_PCREL
4042 && GET_CODE (op) == MEM
4043 && (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
4044 || GET_CODE (XEXP (op, 0)) == LABEL_REF
4045 || GET_CODE (XEXP (op, 0)) == CONST))
4046 return 1;
4047 return general_operand (op, mode);
4048}
4049
4050/* Special case of a nonimmediate operand that's used as a source.
4051 Use this to permit reads from PC-relative memory when -mpcrel
4052 is specified. */
4053
4054int
4055nonimmediate_src_operand (op, mode)
4056 rtx op;
4057 enum machine_mode mode;
4058{
4059 if (TARGET_PCREL && GET_CODE (op) == MEM
4060 && (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
4061 || GET_CODE (XEXP (op, 0)) == LABEL_REF
4062 || GET_CODE (XEXP (op, 0)) == CONST))
4063 return 1;
4064 return nonimmediate_operand (op, mode);
4065}
4066
4067/* Special case of a memory operand that's used as a source.
4068 Use this to permit reads from PC-relative memory when -mpcrel
4069 is specified. */
4070
4071int
4072memory_src_operand (op, mode)
4073 rtx op;
4074 enum machine_mode mode;
4075{
4076 if (TARGET_PCREL && GET_CODE (op) == MEM
4077 && (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
4078 || GET_CODE (XEXP (op, 0)) == LABEL_REF
4079 || GET_CODE (XEXP (op, 0)) == CONST))
4080 return 1;
4081 return memory_operand (op, mode);
4082}
4083
4084/* Predicate that accepts only a pc-relative address. This is needed
4085 because pc-relative addresses don't satisfy the predicate
4086 "general_src_operand". */
4087
4088int
4089pcrel_address (op, mode)
4090 rtx op;
5505f548 4091 enum machine_mode mode ATTRIBUTE_UNUSED;
2c8ec431
DL
4092{
4093 return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF
4094 || GET_CODE (op) == CONST);
4095}
4096
5505f548 4097const char *
29ae8a3c
RK
4098output_andsi3 (operands)
4099 rtx *operands;
4100{
4101 int logval;
4102 if (GET_CODE (operands[2]) == CONST_INT
4103 && (INTVAL (operands[2]) | 0xffff) == 0xffffffff
4104 && (DATA_REG_P (operands[0])
4105 || offsettable_memref_p (operands[0]))
4106 && !TARGET_5200)
4107 {
4108 if (GET_CODE (operands[0]) != REG)
b72f00af 4109 operands[0] = adjust_address (operands[0], HImode, 2);
1d8eaa6b 4110 operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
29ae8a3c
RK
4111 /* Do not delete a following tstl %0 insn; that would be incorrect. */
4112 CC_STATUS_INIT;
4113 if (operands[2] == const0_rtx)
4114 return "clr%.w %0";
4115 return "and%.w %2,%0";
4116 }
4117 if (GET_CODE (operands[2]) == CONST_INT
4118 && (logval = exact_log2 (~ INTVAL (operands[2]))) >= 0
4119 && (DATA_REG_P (operands[0])
4120 || offsettable_memref_p (operands[0])))
4121 {
4122 if (DATA_REG_P (operands[0]))
4123 {
1d8eaa6b 4124 operands[1] = GEN_INT (logval);
29ae8a3c
RK
4125 }
4126 else
4127 {
b72f00af 4128 operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
1d8eaa6b 4129 operands[1] = GEN_INT (logval % 8);
29ae8a3c
RK
4130 }
4131 /* This does not set condition codes in a standard way. */
4132 CC_STATUS_INIT;
4133 return "bclr %1,%0";
4134 }
4135 return "and%.l %2,%0";
4136}
4137
5505f548 4138const char *
29ae8a3c
RK
4139output_iorsi3 (operands)
4140 rtx *operands;
4141{
4142 register int logval;
4143 if (GET_CODE (operands[2]) == CONST_INT
4144 && INTVAL (operands[2]) >> 16 == 0
4145 && (DATA_REG_P (operands[0])
4146 || offsettable_memref_p (operands[0]))
4147 && !TARGET_5200)
4148 {
4149 if (GET_CODE (operands[0]) != REG)
b72f00af 4150 operands[0] = adjust_address (operands[0], HImode, 2);
29ae8a3c
RK
4151 /* Do not delete a following tstl %0 insn; that would be incorrect. */
4152 CC_STATUS_INIT;
4153 if (INTVAL (operands[2]) == 0xffff)
4154 return "mov%.w %2,%0";
4155 return "or%.w %2,%0";
4156 }
4157 if (GET_CODE (operands[2]) == CONST_INT
4158 && (logval = exact_log2 (INTVAL (operands[2]))) >= 0
4159 && (DATA_REG_P (operands[0])
4160 || offsettable_memref_p (operands[0])))
4161 {
4162 if (DATA_REG_P (operands[0]))
b72f00af 4163 operands[1] = GEN_INT (logval);
29ae8a3c
RK
4164 else
4165 {
b72f00af 4166 operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
1d8eaa6b 4167 operands[1] = GEN_INT (logval % 8);
29ae8a3c
RK
4168 }
4169 CC_STATUS_INIT;
4170 return "bset %1,%0";
4171 }
4172 return "or%.l %2,%0";
4173}
4174
5505f548 4175const char *
29ae8a3c
RK
4176output_xorsi3 (operands)
4177 rtx *operands;
4178{
4179 register int logval;
4180 if (GET_CODE (operands[2]) == CONST_INT
4181 && INTVAL (operands[2]) >> 16 == 0
4182 && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))
4183 && !TARGET_5200)
4184 {
4185 if (! DATA_REG_P (operands[0]))
b72f00af 4186 operands[0] = adjust_address (operands[0], HImode, 2);
29ae8a3c
RK
4187 /* Do not delete a following tstl %0 insn; that would be incorrect. */
4188 CC_STATUS_INIT;
4189 if (INTVAL (operands[2]) == 0xffff)
4190 return "not%.w %0";
4191 return "eor%.w %2,%0";
4192 }
4193 if (GET_CODE (operands[2]) == CONST_INT
4194 && (logval = exact_log2 (INTVAL (operands[2]))) >= 0
4195 && (DATA_REG_P (operands[0])
4196 || offsettable_memref_p (operands[0])))
4197 {
4198 if (DATA_REG_P (operands[0]))
b72f00af 4199 operands[1] = GEN_INT (logval);
29ae8a3c
RK
4200 else
4201 {
b72f00af 4202 operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
1d8eaa6b 4203 operands[1] = GEN_INT (logval % 8);
29ae8a3c
RK
4204 }
4205 CC_STATUS_INIT;
4206 return "bchg %1,%0";
4207 }
4208 return "eor%.l %2,%0";
4209}
7c262518
RH
4210
4211/* Output assembly to switch to section NAME with attribute FLAGS. */
4212
4213static void
715bdd29 4214m68k_coff_asm_named_section (name, flags)
7c262518
RH
4215 const char *name;
4216 unsigned int flags;
7c262518
RH
4217{
4218 char flagchar;
4219
4220 if (flags & SECTION_WRITE)
4221 flagchar = 'd';
4222 else
4223 flagchar = 'x';
4224
4225 fprintf (asm_out_file, "\t.section\t%s,\"%c\"\n", name, flagchar);
4226}
2cc07db4 4227
d67c7dd8 4228#ifdef CTOR_LIST_BEGIN
2cc07db4
RH
4229static void
4230m68k_svr3_asm_out_constructor (symbol, priority)
4231 rtx symbol;
4232 int priority ATTRIBUTE_UNUSED;
4233{
4234 rtx xop[2];
4235
4236 xop[1] = symbol;
4237 xop[0] = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
4238
4239 init_section ();
4240 output_asm_insn (output_move_simode (xop), xop);
4241}
4242#endif