|
|
1.1 root 1: /* Subroutines for insn-output.c for Motorola 68000 family.
2: Copyright (C) 1987, 1993 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
6: GNU CC is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 2, or (at your option)
9: any later version.
10:
11: GNU CC is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU CC; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20:
21: /* Some output-actions in m68k.md need these. */
22: #include <stdio.h>
23: #include "config.h"
24: #include "rtl.h"
25: #include "regs.h"
26: #include "hard-reg-set.h"
27: #include "real.h"
28: #include "insn-config.h"
29: #include "conditions.h"
30: #include "insn-flags.h"
31: #include "output.h"
32: #include "insn-attr.h"
33:
34: /* Needed for use_return_insn. */
35: #include "flags.h"
36:
37: #ifdef SUPPORT_SUN_FPA
38:
39: /* Index into this array by (register number >> 3) to find the
40: smallest class which contains that register. */
41: enum reg_class regno_reg_class[]
42: = { DATA_REGS, ADDR_REGS, FP_REGS,
43: LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };
44:
45: #endif /* defined SUPPORT_SUN_FPA */
46:
47: /* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END,
48: if SGS_SWITCH_TABLE. */
49: int switch_table_difference_label_flag;
50:
51: static rtx find_addr_reg ();
52: rtx legitimize_pic_address ();
53:
54:
55: /* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the
56: function at any time during the compilation process. In the future
57: we should try and eliminate the USE if we can easily determine that
58: all PIC references were deleted from the current function. That would
59: save an address register */
60:
1.1.1.2 ! root 61: void
1.1 root 62: finalize_pic ()
63: {
64: if (flag_pic && current_function_uses_pic_offset_table)
65: emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
66: }
67:
68:
69: /* This function generates the assembly code for function entry.
70: STREAM is a stdio stream to output the code to.
71: SIZE is an int: how many units of temporary storage to allocate.
72: Refer to the array `regs_ever_live' to determine which registers
73: to save; `regs_ever_live[I]' is nonzero if register number I
74: is ever used in the function. This function is responsible for
75: knowing which registers should not be saved even if used. */
76:
77:
78: /* Note that the order of the bit mask for fmovem is the opposite
79: of the order for movem! */
80:
81:
82: void
83: output_function_prologue (stream, size)
84: FILE *stream;
85: int size;
86: {
87: register int regno;
88: register int mask = 0;
89: int num_saved_regs = 0;
90: extern char call_used_regs[];
91: int fsize = (size + 3) & -4;
92:
93:
94: if (frame_pointer_needed)
95: {
96: /* Adding negative number is faster on the 68040. */
97: if (fsize < 0x8000 && !TARGET_68040)
98: {
99: #ifdef MOTOROLA
100: asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
101: reg_names[FRAME_POINTER_REGNUM], -fsize);
102: #else
103: asm_fprintf (stream, "\tlink %s,%0I%d\n",
104: reg_names[FRAME_POINTER_REGNUM], -fsize);
105: #endif
106: }
107: else if (TARGET_68020)
108: {
109: #ifdef MOTOROLA
110: asm_fprintf (stream, "\tlink.l %s,%0I%d\n",
111: reg_names[FRAME_POINTER_REGNUM], -fsize);
112: #else
113: asm_fprintf (stream, "\tlink %s,%0I%d\n",
114: reg_names[FRAME_POINTER_REGNUM], -fsize);
115: #endif
116: }
117: else
118: {
119: #ifdef MOTOROLA
120: asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n",
121: reg_names[FRAME_POINTER_REGNUM], -fsize);
122: #else
123: asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n",
124: reg_names[FRAME_POINTER_REGNUM], -fsize);
125: #endif
126: }
127: }
128: else if (fsize)
129: {
130: /* Adding negative number is faster on the 68040. */
131: if (fsize + 4 < 0x8000)
132: {
133: #ifdef MOTOROLA
134: asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
135: #else
136: asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
137: #endif
138: }
139: else
140: {
141: #ifdef MOTOROLA
142: asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));
143: #else
144: asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4));
145: #endif
146: }
147: }
148: #ifdef SUPPORT_SUN_FPA
149: for (regno = 24; regno < 56; regno++)
150: if (regs_ever_live[regno] && ! call_used_regs[regno])
151: {
152: #ifdef MOTOROLA
153: asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
154: reg_names[regno]);
155: #else
156: asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n",
157: reg_names[regno]);
158: #endif
159: }
160: #endif
161: for (regno = 16; regno < 24; regno++)
162: if (regs_ever_live[regno] && ! call_used_regs[regno])
163: mask |= 1 << (regno - 16);
164: if ((mask & 0xff) != 0)
165: {
166: #ifdef MOTOROLA
167: asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
168: #else
169: asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
170: #endif
171: }
172: mask = 0;
173: for (regno = 0; regno < 16; regno++)
174: if (regs_ever_live[regno] && ! call_used_regs[regno])
175: {
176: mask |= 1 << (15 - regno);
177: num_saved_regs++;
178: }
179: if (frame_pointer_needed)
180: {
181: mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
182: num_saved_regs--;
183: }
184:
185: #if NEED_PROBE
186: fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
187: #endif
188:
189: if (num_saved_regs <= 2)
190: {
191: /* Store each separately in the same order moveml uses.
192: Using two movel instructions instead of a single moveml
193: is about 15% faster for the 68020 and 68030 at no expense
194: in code size */
195:
196: int i;
197:
198: /* Undo the work from above. */
199: for (i = 0; i< 16; i++)
200: if (mask & (1 << i))
201: asm_fprintf (stream,
202: #ifdef MOTOROLA
203: "\t%Omove.l %s,-(%Rsp)\n",
204: #else
205: "\tmovel %s,%Rsp@-\n",
206: #endif
207: reg_names[15 - i]);
208: }
209: else if (mask)
210: {
211: #ifdef MOTOROLA
212: asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
213: #else
214: asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
215: #endif
216: }
217: if (flag_pic && current_function_uses_pic_offset_table)
218: {
219: #ifdef MOTOROLA
220: asm_fprintf (stream, "\t%Olea (%Rpc, %U_GLOBAL_OFFSET_TABLE_@GOTPC), %s\n",
221: reg_names[PIC_OFFSET_TABLE_REGNUM]);
222: #else
223: asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n",
224: reg_names[PIC_OFFSET_TABLE_REGNUM]);
225: asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n",
226: reg_names[PIC_OFFSET_TABLE_REGNUM],
227: reg_names[PIC_OFFSET_TABLE_REGNUM]);
228: #endif
229: }
230: }
231:
232: /* Return true if this function's epilogue can be output as RTL. */
233:
234: int
235: use_return_insn ()
236: {
237: int regno;
238:
239: if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
240: return 0;
241:
242: /* Copied from output_function_epilogue (). We should probably create a
243: separate layout routine to perform the common work. */
244:
245: for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
246: if (regs_ever_live[regno] && ! call_used_regs[regno])
247: return 0;
248:
249: return 1;
250: }
251:
252: /* This function generates the assembly code for function exit,
253: on machines that need it. Args are same as for FUNCTION_PROLOGUE.
254:
255: The function epilogue should not depend on the current stack pointer!
256: It should use the frame pointer only, if there is a frame pointer.
257: This is mandatory because of alloca; we also take advantage of it to
258: omit stack adjustments before returning. */
259:
260: void
261: output_function_epilogue (stream, size)
262: FILE *stream;
263: int size;
264: {
265: register int regno;
266: register int mask, fmask;
267: register int nregs;
268: int offset, foffset, fpoffset;
269: extern char call_used_regs[];
270: int fsize = (size + 3) & -4;
271: int big = 0;
272: rtx insn = get_last_insn ();
273:
274: /* If the last insn was a BARRIER, we don't have to write any code. */
275: if (GET_CODE (insn) == NOTE)
276: insn = prev_nonnote_insn (insn);
277: if (insn && GET_CODE (insn) == BARRIER)
278: {
279: /* Output just a no-op so that debuggers don't get confused
280: about which function the pc is in at this address. */
281: asm_fprintf (stream, "\tnop\n");
282: return;
283: }
284:
285: #ifdef FUNCTION_EXTRA_EPILOGUE
286: FUNCTION_EXTRA_EPILOGUE (stream, size);
287: #endif
288: nregs = 0; fmask = 0; fpoffset = 0;
289: #ifdef SUPPORT_SUN_FPA
290: for (regno = 24 ; regno < 56 ; regno++)
291: if (regs_ever_live[regno] && ! call_used_regs[regno])
292: nregs++;
293: fpoffset = nregs * 8;
294: #endif
295: nregs = 0;
296: for (regno = 16; regno < 24; regno++)
297: if (regs_ever_live[regno] && ! call_used_regs[regno])
298: {
299: nregs++;
300: fmask |= 1 << (23 - regno);
301: }
302: foffset = fpoffset + nregs * 12;
303: nregs = 0; mask = 0;
304: if (frame_pointer_needed)
305: regs_ever_live[FRAME_POINTER_REGNUM] = 0;
306: for (regno = 0; regno < 16; regno++)
307: if (regs_ever_live[regno] && ! call_used_regs[regno])
308: {
309: nregs++;
310: mask |= 1 << regno;
311: }
312: offset = foffset + nregs * 4;
313: if (offset + fsize >= 0x8000
314: && frame_pointer_needed
315: && (mask || fmask || fpoffset))
316: {
317: #ifdef MOTOROLA
318: asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra0\n", -fsize);
319: #else
320: asm_fprintf (stream, "\tmovel %0I%d,%Ra0\n", -fsize);
321: #endif
322: fsize = 0, big = 1;
323: }
324: if (nregs <= 2)
325: {
326: /* Restore each separately in the same order moveml does.
327: Using two movel instructions instead of a single moveml
328: is about 15% faster for the 68020 and 68030 at no expense
329: in code size. */
330:
331: int i;
332:
333: /* Undo the work from above. */
334: for (i = 0; i< 16; i++)
335: if (mask & (1 << i))
336: {
337: if (big)
338: {
339: #ifdef MOTOROLA
340: asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra0.l),%s\n",
341: offset + fsize,
342: reg_names[FRAME_POINTER_REGNUM],
343: reg_names[i]);
344: #else
345: asm_fprintf (stream, "\tmovel %s@(-%d,%Ra0:l),%s\n",
346: reg_names[FRAME_POINTER_REGNUM],
347: offset + fsize, reg_names[i]);
348: #endif
349: }
350: else if (! frame_pointer_needed)
351: {
352: #ifdef MOTOROLA
353: asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n",
354: reg_names[i]);
355: #else
356: asm_fprintf (stream, "\tmovel %Rsp@+,%s\n",
357: reg_names[i]);
358: #endif
359: }
360: else
361: {
362: #ifdef MOTOROLA
363: asm_fprintf (stream, "\t%Omove.l -%d(%s),%s\n",
364: offset + fsize,
365: reg_names[FRAME_POINTER_REGNUM],
366: reg_names[i]);
367: #else
368: asm_fprintf (stream, "\tmovel %s@(-%d),%s\n",
369: reg_names[FRAME_POINTER_REGNUM],
370: offset + fsize, reg_names[i]);
371: #endif
372: }
373: offset = offset - 4;
374: }
375: }
376: else if (mask)
377: {
378: if (big)
379: {
380: #ifdef MOTOROLA
381: asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra0.l),%0I0x%x\n",
382: offset + fsize,
383: reg_names[FRAME_POINTER_REGNUM],
384: mask);
385: #else
386: asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra0:l),%0I0x%x\n",
387: reg_names[FRAME_POINTER_REGNUM],
388: offset + fsize, mask);
389: #endif
390: }
391: else if (! frame_pointer_needed)
392: {
393: #ifdef MOTOROLA
394: asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);
395: #else
396: asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask);
397: #endif
398: }
399: else
400: {
401: #ifdef MOTOROLA
402: asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n",
403: offset + fsize,
404: reg_names[FRAME_POINTER_REGNUM],
405: mask);
406: #else
407: asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n",
408: reg_names[FRAME_POINTER_REGNUM],
409: offset + fsize, mask);
410: #endif
411: }
412: }
413: if (fmask)
414: {
415: if (big)
416: {
417: #ifdef MOTOROLA
418: asm_fprintf (stream, "\tfmovm -%d(%s,%Ra0.l),%0I0x%x\n",
419: foffset + fsize,
420: reg_names[FRAME_POINTER_REGNUM],
421: fmask);
422: #else
423: asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra0:l),%0I0x%x\n",
424: reg_names[FRAME_POINTER_REGNUM],
425: foffset + fsize, fmask);
426: #endif
427: }
428: else if (! frame_pointer_needed)
429: {
430: #ifdef MOTOROLA
431: asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask);
432: #else
433: asm_fprintf (stream, "\tfmovem %Rsp@+,%0I0x%x\n", fmask);
434: #endif
435: }
436: else
437: {
438: #ifdef MOTOROLA
439: asm_fprintf (stream, "\tfmovm -%d(%s),%0I0x%x\n",
440: foffset + fsize,
441: reg_names[FRAME_POINTER_REGNUM],
442: fmask);
443: #else
444: asm_fprintf (stream, "\tfmovem %s@(-%d),%0I0x%x\n",
445: reg_names[FRAME_POINTER_REGNUM],
446: foffset + fsize, fmask);
447: #endif
448: }
449: }
450: if (fpoffset != 0)
451: for (regno = 55; regno >= 24; regno--)
452: if (regs_ever_live[regno] && ! call_used_regs[regno])
453: {
454: if (big)
455: {
456: #ifdef MOTOROLA
457: asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra0.l), %s\n",
458: fpoffset + fsize,
459: reg_names[FRAME_POINTER_REGNUM],
460: reg_names[regno]);
461: #else
462: asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra0:l), %s\n",
463: reg_names[FRAME_POINTER_REGNUM],
464: fpoffset + fsize, reg_names[regno]);
465: #endif
466: }
467: else if (! frame_pointer_needed)
468: {
469: #ifdef MOTOROLA
470: asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n",
471: reg_names[regno]);
472: #else
473: asm_fprintf (stream, "\tfpmoved %Rsp@+, %s\n",
474: reg_names[regno]);
475: #endif
476: }
477: else
478: {
479: #ifdef MOTOROLA
480: asm_fprintf (stream, "\tfpmovd -%d(%s), %s\n",
481: fpoffset + fsize,
482: reg_names[FRAME_POINTER_REGNUM],
483: reg_names[regno]);
484: #else
485: asm_fprintf (stream, "\tfpmoved %s@(-%d), %s\n",
486: reg_names[FRAME_POINTER_REGNUM],
487: fpoffset + fsize, reg_names[regno]);
488: #endif
489: }
490: fpoffset -= 8;
491: }
492: if (frame_pointer_needed)
493: fprintf (stream, "\tunlk %s\n",
494: reg_names[FRAME_POINTER_REGNUM]);
495: else if (fsize)
496: {
497: if (fsize + 4 < 0x8000)
498: {
499: #ifdef MOTOROLA
500: asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4);
501: #else
502: asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4);
503: #endif
504: }
505: else
506: {
507: #ifdef MOTOROLA
508: asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4);
509: #else
510: asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", fsize + 4);
511: #endif
512: }
513: }
514: if (current_function_pops_args)
515: asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args);
516: else
517: fprintf (stream, "\trts\n");
518: }
519:
520: /* Similar to general_operand, but exclude stack_pointer_rtx. */
521:
522: int
523: not_sp_operand (op, mode)
524: register rtx op;
525: enum machine_mode mode;
526: {
527: return op != stack_pointer_rtx && general_operand (op, mode);
528: }
529:
530: /* Return TRUE if X is a valid comparison operator for the dbcc
531: instruction.
532:
533: Note it rejects floating point comparison operators.
534: (In the future we could use Fdbcc).
535:
536: It also rejects some comparisons when CC_NO_OVERFLOW is set. */
537:
538: int
539: valid_dbcc_comparison_p (x, mode)
540: rtx x;
541: enum machine_mode mode;
542: {
543: /* We could add support for these in the future */
544: if (cc_prev_status.flags & CC_IN_68881)
545: return 0;
546:
547: switch (GET_CODE (x))
548: {
549:
550: case EQ: case NE: case GTU: case LTU:
551: case GEU: case LEU:
552: return 1;
553:
554: /* Reject some when CC_NO_OVERFLOW is set. This may be over
555: conservative */
556: case GT: case LT: case GE: case LE:
557: return ! (cc_prev_status.flags & CC_NO_OVERFLOW);
558: default:
559: return 0;
560: }
561: }
562:
563: /* Output a dbCC; jCC sequence. Note we do not handle the
564: floating point version of this sequence (Fdbcc). We also
565: do not handle alternative conditions when CC_NO_OVERFLOW is
566: set. It is assumed that valid_dbcc_comparison_p will kick
567: those out before we get here. */
568:
569: output_dbcc_and_branch (operands)
570: rtx *operands;
571: {
572:
573: switch (GET_CODE (operands[3]))
574: {
575: case EQ:
576: #ifdef MOTOROLA
577: output_asm_insn ("dbeq %0,%l1\n\tjbeq %l2", operands);
578: #else
579: output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands);
580: #endif
581: break;
582:
583: case NE:
584: #ifdef MOTOROLA
585: output_asm_insn ("dbne %0,%l1\n\tjbne %l2", operands);
586: #else
587: output_asm_insn ("dbne %0,%l1\n\tjne %l2", operands);
588: #endif
589: break;
590:
591: case GT:
592: #ifdef MOTOROLA
593: output_asm_insn ("dbgt %0,%l1\n\tjbgt %l2", operands);
594: #else
595: output_asm_insn ("dbgt %0,%l1\n\tjgt %l2", operands);
596: #endif
597: break;
598:
599: case GTU:
600: #ifdef MOTOROLA
601: output_asm_insn ("dbhi %0,%l1\n\tjbhi %l2", operands);
602: #else
603: output_asm_insn ("dbhi %0,%l1\n\tjhi %l2", operands);
604: #endif
605: break;
606:
607: case LT:
608: #ifdef MOTOROLA
609: output_asm_insn ("dblt %0,%l1\n\tjblt %l2", operands);
610: #else
611: output_asm_insn ("dblt %0,%l1\n\tjlt %l2", operands);
612: #endif
613: break;
614:
615: case LTU:
616: #ifdef MOTOROLA
617: output_asm_insn ("dbcs %0,%l1\n\tjbcs %l2", operands);
618: #else
619: output_asm_insn ("dbcs %0,%l1\n\tjcs %l2", operands);
620: #endif
621: break;
622:
623: case GE:
624: #ifdef MOTOROLA
625: output_asm_insn ("dbge %0,%l1\n\tjbge %l2", operands);
626: #else
627: output_asm_insn ("dbge %0,%l1\n\tjge %l2", operands);
628: #endif
629: break;
630:
631: case GEU:
632: #ifdef MOTOROLA
633: output_asm_insn ("dbcc %0,%l1\n\tjbcc %l2", operands);
634: #else
635: output_asm_insn ("dbcc %0,%l1\n\tjcc %l2", operands);
636: #endif
637: break;
638:
639: case LE:
640: #ifdef MOTOROLA
641: output_asm_insn ("dble %0,%l1\n\tjble %l2", operands);
642: #else
643: output_asm_insn ("dble %0,%l1\n\tjle %l2", operands);
644: #endif
645: break;
646:
647: case LEU:
648: #ifdef MOTOROLA
649: output_asm_insn ("dbls %0,%l1\n\tjbls %l2", operands);
650: #else
651: output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands);
652: #endif
653: break;
654:
655: default:
656: abort ();
657: }
658:
659: /* If the decrement is to be done in SImode, then we have
660: to compensate for the fact that dbcc decrements in HImode. */
661: switch (GET_MODE (operands[0]))
662: {
663: case SImode:
664: #ifdef MOTOROLA
665: output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjbpl %l1", operands);
666: #else
667: output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjpl %l1", operands);
668: #endif
669: break;
670:
671: case HImode:
672: break;
673:
674: default:
675: abort ();
676: }
677: }
678:
679: char *
680: output_btst (operands, countop, dataop, insn, signpos)
681: rtx *operands;
682: rtx countop, dataop;
683: rtx insn;
684: int signpos;
685: {
686: operands[0] = countop;
687: operands[1] = dataop;
688:
689: if (GET_CODE (countop) == CONST_INT)
690: {
691: register int count = INTVAL (countop);
692: /* If COUNT is bigger than size of storage unit in use,
693: advance to the containing unit of same size. */
694: if (count > signpos)
695: {
696: int offset = (count & ~signpos) / 8;
697: count = count & signpos;
698: operands[1] = dataop = adj_offsettable_operand (dataop, offset);
699: }
700: if (count == signpos)
701: cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
702: else
703: cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
704:
705: /* These three statements used to use next_insns_test_no...
706: but it appears that this should do the same job. */
707: if (count == 31
708: && next_insn_tests_no_inequality (insn))
709: return "tst%.l %1";
710: if (count == 15
711: && next_insn_tests_no_inequality (insn))
712: return "tst%.w %1";
713: if (count == 7
714: && next_insn_tests_no_inequality (insn))
715: return "tst%.b %1";
716:
717: cc_status.flags = CC_NOT_NEGATIVE;
718: }
719: return "btst %0,%1";
720: }
721:
722: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
723: reference and a constant. */
724:
725: int
726: symbolic_operand (op, mode)
727: register rtx op;
728: enum machine_mode mode;
729: {
730: switch (GET_CODE (op))
731: {
732: case SYMBOL_REF:
733: case LABEL_REF:
734: return 1;
735:
736: case CONST:
737: op = XEXP (op, 0);
738: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
739: || GET_CODE (XEXP (op, 0)) == LABEL_REF)
740: && GET_CODE (XEXP (op, 1)) == CONST_INT);
741:
742: #if 0 /* Deleted, with corresponding change in m68k.h,
743: so as to fit the specs. No CONST_DOUBLE is ever symbolic. */
744: case CONST_DOUBLE:
745: return GET_MODE (op) == mode;
746: #endif
747:
748: default:
749: return 0;
750: }
751: }
752:
753:
754: /* Legitimize PIC addresses. If the address is already
755: position-independent, we return ORIG. Newly generated
756: position-independent addresses go to REG. If we need more
757: than one register, we lose.
758:
759: An address is legitimized by making an indirect reference
760: through the Global Offset Table with the name of the symbol
761: used as an offset.
762:
763: The assembler and linker are responsible for placing the
764: address of the symbol in the GOT. The function prologue
765: is responsible for initializing a5 to the starting address
766: of the GOT.
767:
768: The assembler is also responsible for translating a symbol name
769: into a constant displacement from the start of the GOT.
770:
771: A quick example may make things a little clearer:
772:
773: When not generating PIC code to store the value 12345 into _foo
774: we would generate the following code:
775:
776: movel #12345, _foo
777:
778: When generating PIC two transformations are made. First, the compiler
779: loads the address of foo into a register. So the first transformation makes:
780:
781: lea _foo, a0
782: movel #12345, a0@
783:
784: The code in movsi will intercept the lea instruction and call this
785: routine which will transform the instructions into:
786:
787: movel a5@(_foo:w), a0
788: movel #12345, a0@
789:
790:
791: That (in a nutshell) is how *all* symbol and label references are
792: handled. */
793:
794: rtx
795: legitimize_pic_address (orig, mode, reg)
796: rtx orig, reg;
797: enum machine_mode mode;
798: {
799: rtx pic_ref = orig;
800:
801: /* First handle a simple SYMBOL_REF or LABEL_REF */
802: if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
803: {
804: if (reg == 0)
805: abort ();
806:
807: pic_ref = gen_rtx (MEM, Pmode,
808: gen_rtx (PLUS, Pmode,
809: pic_offset_table_rtx, orig));
810: current_function_uses_pic_offset_table = 1;
811: RTX_UNCHANGING_P (pic_ref) = 1;
812: emit_move_insn (reg, pic_ref);
813: return reg;
814: }
815: else if (GET_CODE (orig) == CONST)
816: {
817: rtx base, offset;
818:
819: /* Make sure this is CONST has not already been legitimized */
820: if (GET_CODE (XEXP (orig, 0)) == PLUS
821: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
822: return orig;
823:
824: if (reg == 0)
825: abort ();
826:
827: /* legitimize both operands of the PLUS */
828: if (GET_CODE (XEXP (orig, 0)) == PLUS)
829: {
830: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
831: orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
832: base == reg ? 0 : reg);
833: }
834: else abort ();
835:
836: if (GET_CODE (orig) == CONST_INT)
837: return plus_constant_for_output (base, INTVAL (orig));
838: pic_ref = gen_rtx (PLUS, Pmode, base, orig);
839: /* Likewise, should we set special REG_NOTEs here? */
840: }
841: return pic_ref;
842: }
843:
844:
845: /* Return the best assembler insn template
846: for moving operands[1] into operands[0] as a fullword. */
847:
848: static char *
849: singlemove_string (operands)
850: rtx *operands;
851: {
852: #ifdef SUPPORT_SUN_FPA
853: if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))
854: return "fpmoves %1,%0";
855: #endif
856: if (DATA_REG_P (operands[0])
857: && GET_CODE (operands[1]) == CONST_INT
858: && INTVAL (operands[1]) < 128
859: && INTVAL (operands[1]) >= -128)
860: {
861: #if defined (MOTOROLA) && !defined (CRDS)
862: return "moveq%.l %1,%0";
863: #else
864: return "moveq %1,%0";
865: #endif
866: }
867: if (operands[1] != const0_rtx)
868: return "move%.l %1,%0";
869: if (! ADDRESS_REG_P (operands[0]))
870: return "clr%.l %0";
871: return "sub%.l %0,%0";
872: }
873:
874:
875: /* Output assembler code to perform a doubleword move insn
876: with operands OPERANDS. */
877:
878: char *
879: output_move_double (operands)
880: rtx *operands;
881: {
882: enum
883: {
884: REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP
885: } optype0, optype1;
886: rtx latehalf[2];
887: rtx middlehalf[2];
1.1.1.2 ! root 888: rtx xops[2];
1.1 root 889: rtx addreg0 = 0, addreg1 = 0;
1.1.1.2 ! root 890: int dest_overlapped_low = 0;
1.1 root 891: int size = GET_MODE_SIZE (GET_MODE (operands[0]));
892:
893: middlehalf[0] = 0;
894: middlehalf[1] = 0;
895:
896: /* First classify both operands. */
897:
898: if (REG_P (operands[0]))
899: optype0 = REGOP;
900: else if (offsettable_memref_p (operands[0]))
901: optype0 = OFFSOP;
902: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
903: optype0 = POPOP;
904: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
905: optype0 = PUSHOP;
906: else if (GET_CODE (operands[0]) == MEM)
907: optype0 = MEMOP;
908: else
909: optype0 = RNDOP;
910:
911: if (REG_P (operands[1]))
912: optype1 = REGOP;
913: else if (CONSTANT_P (operands[1]))
914: optype1 = CNSTOP;
915: else if (offsettable_memref_p (operands[1]))
916: optype1 = OFFSOP;
917: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
918: optype1 = POPOP;
919: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
920: optype1 = PUSHOP;
921: else if (GET_CODE (operands[1]) == MEM)
922: optype1 = MEMOP;
923: else
924: optype1 = RNDOP;
925:
926: /* Check for the cases that the operand constraints are not
927: supposed to allow to happen. Abort if we get one,
928: because generating code for these cases is painful. */
929:
930: if (optype0 == RNDOP || optype1 == RNDOP)
931: abort ();
932:
933: /* If one operand is decrementing and one is incrementing
934: decrement the former register explicitly
935: and change that operand into ordinary indexing. */
936:
937: if (optype0 == PUSHOP && optype1 == POPOP)
938: {
939: operands[0] = XEXP (XEXP (operands[0], 0), 0);
940: if (size == 12)
941: output_asm_insn ("sub%.l %#12,%0", operands);
942: else
943: output_asm_insn ("subq%.l %#8,%0", operands);
944: if (GET_MODE (operands[1]) == XFmode)
945: operands[0] = gen_rtx (MEM, XFmode, operands[0]);
946: else if (GET_MODE (operands[0]) == DFmode)
947: operands[0] = gen_rtx (MEM, DFmode, operands[0]);
948: else
949: operands[0] = gen_rtx (MEM, DImode, operands[0]);
950: optype0 = OFFSOP;
951: }
952: if (optype0 == POPOP && optype1 == PUSHOP)
953: {
954: operands[1] = XEXP (XEXP (operands[1], 0), 0);
955: if (size == 12)
956: output_asm_insn ("sub%.l %#12,%1", operands);
957: else
958: output_asm_insn ("subq%.l %#8,%1", operands);
959: if (GET_MODE (operands[1]) == XFmode)
960: operands[1] = gen_rtx (MEM, XFmode, operands[1]);
961: else if (GET_MODE (operands[1]) == DFmode)
962: operands[1] = gen_rtx (MEM, DFmode, operands[1]);
963: else
964: operands[1] = gen_rtx (MEM, DImode, operands[1]);
965: optype1 = OFFSOP;
966: }
967:
968: /* If an operand is an unoffsettable memory ref, find a register
969: we can increment temporarily to make it refer to the second word. */
970:
971: if (optype0 == MEMOP)
972: addreg0 = find_addr_reg (XEXP (operands[0], 0));
973:
974: if (optype1 == MEMOP)
975: addreg1 = find_addr_reg (XEXP (operands[1], 0));
976:
977: /* Ok, we can do one word at a time.
978: Normally we do the low-numbered word first,
979: but if either operand is autodecrementing then we
980: do the high-numbered word first.
981:
982: In either case, set up in LATEHALF the operands to use
983: for the high-numbered word and in some cases alter the
984: operands in OPERANDS to be suitable for the low-numbered word. */
985:
986: if (size == 12)
987: {
988: if (optype0 == REGOP)
989: {
990: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
991: middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
992: }
993: else if (optype0 == OFFSOP)
994: {
995: middlehalf[0] = adj_offsettable_operand (operands[0], 4);
996: latehalf[0] = adj_offsettable_operand (operands[0], size - 4);
997: }
998: else
999: {
1000: middlehalf[0] = operands[0];
1001: latehalf[0] = operands[0];
1002: }
1003:
1004: if (optype1 == REGOP)
1005: {
1006: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
1007: middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
1008: }
1009: else if (optype1 == OFFSOP)
1010: {
1011: middlehalf[1] = adj_offsettable_operand (operands[1], 4);
1012: latehalf[1] = adj_offsettable_operand (operands[1], size - 4);
1013: }
1014: else if (optype1 == CNSTOP)
1015: {
1016: if (GET_CODE (operands[1]) == CONST_DOUBLE)
1017: {
1018: REAL_VALUE_TYPE r;
1019: long l[3];
1020:
1021: REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
1022: REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
1023: operands[1] = GEN_INT (l[0]);
1024: middlehalf[1] = GEN_INT (l[1]);
1025: latehalf[1] = GEN_INT (l[2]);
1026: }
1027: else if (CONSTANT_P (operands[1]))
1028: {
1029: /* actually, no non-CONST_DOUBLE constant should ever
1030: appear here. */
1031: abort ();
1032: if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0)
1033: latehalf[1] = constm1_rtx;
1034: else
1035: latehalf[1] = const0_rtx;
1036: }
1037: }
1038: else
1039: {
1040: middlehalf[1] = operands[1];
1041: latehalf[1] = operands[1];
1042: }
1043: }
1044: else
1045: /* size is not 12: */
1046: {
1047: if (optype0 == REGOP)
1048: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
1049: else if (optype0 == OFFSOP)
1050: latehalf[0] = adj_offsettable_operand (operands[0], size - 4);
1051: else
1052: latehalf[0] = operands[0];
1053:
1054: if (optype1 == REGOP)
1055: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
1056: else if (optype1 == OFFSOP)
1057: latehalf[1] = adj_offsettable_operand (operands[1], size - 4);
1058: else if (optype1 == CNSTOP)
1059: split_double (operands[1], &operands[1], &latehalf[1]);
1060: else
1061: latehalf[1] = operands[1];
1062: }
1063:
1064: /* If insn is effectively movd N(sp),-(sp) then we will do the
1065: high word first. We should use the adjusted operand 1 (which is N+4(sp))
1066: for the low word as well, to compensate for the first decrement of sp. */
1067: if (optype0 == PUSHOP
1068: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
1069: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
1.1.1.2 ! root 1070: operands[1] = middlehalf[1] = latehalf[1];
! 1071:
! 1072: /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),
! 1073: if the upper part of reg N does not appear in the MEM, arrange to
! 1074: emit the move late-half first. Otherwise, compute the MEM address
! 1075: into the upper part of N and use that as a pointer to the memory
! 1076: operand. */
! 1077: if (optype0 == REGOP
! 1078: && (optype1 == OFFSOP || optype1 == MEMOP))
! 1079: {
! 1080: rtx testlow = gen_rtx (REG, SImode, REGNO (operands[0]));
! 1081:
! 1082: if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
! 1083: && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
! 1084: {
! 1085: /* If both halves of dest are used in the src memory address,
! 1086: compute the address into latehalf of dest.
! 1087: Note that this can't happen if the dest is two data regs. */
! 1088: compadr:
! 1089: xops[0] = latehalf[0];
! 1090: xops[1] = XEXP (operands[1], 0);
! 1091: output_asm_insn ("lea %a1,%0", xops);
! 1092: if( GET_MODE (operands[1]) == XFmode )
! 1093: {
! 1094: operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
! 1095: middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
! 1096: latehalf[1] = adj_offsettable_operand (operands[1], size-4);
! 1097: }
! 1098: else
! 1099: {
! 1100: operands[1] = gen_rtx (MEM, DImode, latehalf[0]);
! 1101: latehalf[1] = adj_offsettable_operand (operands[1], size-4);
! 1102: }
! 1103: }
! 1104: else if (size == 12
! 1105: && reg_overlap_mentioned_p (middlehalf[0],
! 1106: XEXP (operands[1], 0)))
! 1107: {
! 1108: /* Check for two regs used by both source and dest.
! 1109: Note that this can't happen if the dest is all data regs.
! 1110: It can happen if the dest is d6, d7, a0.
! 1111: But in that case, latehalf is an addr reg, so
! 1112: the code at compadr does ok. */
! 1113:
! 1114: if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
! 1115: || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
! 1116: goto compadr;
! 1117:
! 1118: /* JRV says this can't happen: */
! 1119: if (addreg0 || addreg1)
! 1120: abort ();
! 1121:
! 1122: /* Only the middle reg conflicts; simply put it last. */
! 1123: output_asm_insn (singlemove_string (operands), operands);
! 1124: output_asm_insn (singlemove_string (latehalf), latehalf);
! 1125: output_asm_insn (singlemove_string (middlehalf), middlehalf);
! 1126: return "";
! 1127: }
! 1128: else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)))
! 1129: /* If the low half of dest is mentioned in the source memory
! 1130: address, the arrange to emit the move late half first. */
! 1131: dest_overlapped_low = 1;
! 1132: }
1.1 root 1133:
1134: /* If one or both operands autodecrementing,
1135: do the two words, high-numbered first. */
1136:
1137: /* Likewise, the first move would clobber the source of the second one,
1138: do them in the other order. This happens only for registers;
1139: such overlap can't happen in memory unless the user explicitly
1140: sets it up, and that is an undefined circumstance. */
1141:
1142: if (optype0 == PUSHOP || optype1 == PUSHOP
1143: || (optype0 == REGOP && optype1 == REGOP
1144: && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
1.1.1.2 ! root 1145: || REGNO (operands[0]) == REGNO (latehalf[1])))
! 1146: || dest_overlapped_low)
1.1 root 1147: {
1148: /* Make any unoffsettable addresses point at high-numbered word. */
1149: if (addreg0)
1150: {
1151: if (size == 12)
1152: output_asm_insn ("addql %#8,%0", &addreg0);
1153: else
1154: output_asm_insn ("addql %#4,%0", &addreg0);
1155: }
1156: if (addreg1)
1157: {
1158: if (size == 12)
1159: output_asm_insn ("addql %#8,%0", &addreg1);
1160: else
1161: output_asm_insn ("addql %#4,%0", &addreg1);
1162: }
1163:
1164: /* Do that word. */
1165: output_asm_insn (singlemove_string (latehalf), latehalf);
1166:
1167: /* Undo the adds we just did. */
1168: if (addreg0)
1169: output_asm_insn ("subql %#4,%0", &addreg0);
1170: if (addreg1)
1171: output_asm_insn ("subql %#4,%0", &addreg1);
1172:
1173: if (size == 12)
1174: {
1175: output_asm_insn (singlemove_string (middlehalf), middlehalf);
1176: if (addreg0)
1177: output_asm_insn ("subql %#4,%0", &addreg0);
1178: if (addreg1)
1179: output_asm_insn ("subql %#4,%0", &addreg1);
1180: }
1181:
1182: /* Do low-numbered word. */
1183: return singlemove_string (operands);
1184: }
1185:
1186: /* Normal case: do the two words, low-numbered first. */
1187:
1188: output_asm_insn (singlemove_string (operands), operands);
1189:
1190: /* Do the middle one of the three words for long double */
1191: if (size == 12)
1192: {
1193: if (addreg0)
1194: output_asm_insn ("addql %#4,%0", &addreg0);
1195: if (addreg1)
1196: output_asm_insn ("addql %#4,%0", &addreg1);
1197:
1198: output_asm_insn (singlemove_string (middlehalf), middlehalf);
1199: }
1200:
1201: /* Make any unoffsettable addresses point at high-numbered word. */
1202: if (addreg0)
1203: output_asm_insn ("addql %#4,%0", &addreg0);
1204: if (addreg1)
1205: output_asm_insn ("addql %#4,%0", &addreg1);
1206:
1207: /* Do that word. */
1208: output_asm_insn (singlemove_string (latehalf), latehalf);
1209:
1210: /* Undo the adds we just did. */
1211: if (addreg0)
1212: {
1213: if (size == 12)
1214: output_asm_insn ("subql %#8,%0", &addreg0);
1215: else
1216: output_asm_insn ("subql %#4,%0", &addreg0);
1217: }
1218: if (addreg1)
1219: {
1220: if (size == 12)
1221: output_asm_insn ("subql %#8,%0", &addreg1);
1222: else
1223: output_asm_insn ("subql %#4,%0", &addreg1);
1224: }
1225:
1226: return "";
1227: }
1228:
1229: /* Return a REG that occurs in ADDR with coefficient 1.
1230: ADDR can be effectively incremented by incrementing REG. */
1231:
1232: static rtx
1233: find_addr_reg (addr)
1234: rtx addr;
1235: {
1236: while (GET_CODE (addr) == PLUS)
1237: {
1238: if (GET_CODE (XEXP (addr, 0)) == REG)
1239: addr = XEXP (addr, 0);
1240: else if (GET_CODE (XEXP (addr, 1)) == REG)
1241: addr = XEXP (addr, 1);
1242: else if (CONSTANT_P (XEXP (addr, 0)))
1243: addr = XEXP (addr, 1);
1244: else if (CONSTANT_P (XEXP (addr, 1)))
1245: addr = XEXP (addr, 0);
1246: else
1247: abort ();
1248: }
1249: if (GET_CODE (addr) == REG)
1250: return addr;
1251: abort ();
1252: }
1253:
1254: /* Store in cc_status the expressions that the condition codes will
1255: describe after execution of an instruction whose pattern is EXP.
1256: Do not alter them if the instruction would not alter the cc's. */
1257:
1258: /* On the 68000, all the insns to store in an address register fail to
1259: set the cc's. However, in some cases these instructions can make it
1260: possibly invalid to use the saved cc's. In those cases we clear out
1261: some or all of the saved cc's so they won't be used. */
1262:
1263: notice_update_cc (exp, insn)
1264: rtx exp;
1265: rtx insn;
1266: {
1267: /* If the cc is being set from the fpa and the expression is not an
1268: explicit floating point test instruction (which has code to deal with
1269: this), reinit the CC. */
1270: if (((cc_status.value1 && FPA_REG_P (cc_status.value1))
1271: || (cc_status.value2 && FPA_REG_P (cc_status.value2)))
1272: && !(GET_CODE (exp) == PARALLEL
1273: && GET_CODE (XVECEXP (exp, 0, 0)) == SET
1274: && XEXP (XVECEXP (exp, 0, 0), 0) == cc0_rtx))
1275: {
1276: CC_STATUS_INIT;
1277: }
1278: else if (GET_CODE (exp) == SET)
1279: {
1280: if (GET_CODE (SET_SRC (exp)) == CALL)
1281: {
1282: CC_STATUS_INIT;
1283: }
1284: else if (ADDRESS_REG_P (SET_DEST (exp)))
1285: {
1286: if (cc_status.value1
1287: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1288: cc_status.value1 = 0;
1289: if (cc_status.value2
1290: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1291: cc_status.value2 = 0;
1292: }
1293: else if (!FP_REG_P (SET_DEST (exp))
1294: && SET_DEST (exp) != cc0_rtx
1295: && (FP_REG_P (SET_SRC (exp))
1296: || GET_CODE (SET_SRC (exp)) == FIX
1297: || GET_CODE (SET_SRC (exp)) == FLOAT_TRUNCATE
1298: || GET_CODE (SET_SRC (exp)) == FLOAT_EXTEND))
1299: {
1300: CC_STATUS_INIT;
1301: }
1302: /* A pair of move insns doesn't produce a useful overall cc. */
1303: else if (!FP_REG_P (SET_DEST (exp))
1304: && !FP_REG_P (SET_SRC (exp))
1305: && GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4
1306: && (GET_CODE (SET_SRC (exp)) == REG
1307: || GET_CODE (SET_SRC (exp)) == MEM
1308: || GET_CODE (SET_SRC (exp)) == CONST_DOUBLE))
1309: {
1310: CC_STATUS_INIT;
1311: }
1312: else if (GET_CODE (SET_SRC (exp)) == CALL)
1313: {
1314: CC_STATUS_INIT;
1315: }
1316: else if (XEXP (exp, 0) != pc_rtx)
1317: {
1318: cc_status.flags = 0;
1319: cc_status.value1 = XEXP (exp, 0);
1320: cc_status.value2 = XEXP (exp, 1);
1321: }
1322: }
1323: else if (GET_CODE (exp) == PARALLEL
1324: && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1325: {
1326: if (ADDRESS_REG_P (XEXP (XVECEXP (exp, 0, 0), 0)))
1327: CC_STATUS_INIT;
1328: else if (XEXP (XVECEXP (exp, 0, 0), 0) != pc_rtx)
1329: {
1330: cc_status.flags = 0;
1331: cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
1332: cc_status.value2 = XEXP (XVECEXP (exp, 0, 0), 1);
1333: }
1334: }
1335: else
1336: CC_STATUS_INIT;
1337: if (cc_status.value2 != 0
1338: && ADDRESS_REG_P (cc_status.value2)
1339: && GET_MODE (cc_status.value2) == QImode)
1340: CC_STATUS_INIT;
1341: if (cc_status.value2 != 0
1342: && !(cc_status.value1 && FPA_REG_P (cc_status.value1)))
1343: switch (GET_CODE (cc_status.value2))
1344: {
1345: case PLUS: case MINUS: case MULT:
1346: case DIV: case UDIV: case MOD: case UMOD: case NEG:
1347: case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT:
1348: case ROTATE: case ROTATERT:
1349: if (GET_MODE (cc_status.value2) != VOIDmode)
1350: cc_status.flags |= CC_NO_OVERFLOW;
1351: break;
1352: case ZERO_EXTEND:
1353: /* (SET r1 (ZERO_EXTEND r2)) on this machine
1354: ends with a move insn moving r2 in r2's mode.
1355: Thus, the cc's are set for r2.
1356: This can set N bit spuriously. */
1357: cc_status.flags |= CC_NOT_NEGATIVE;
1358: }
1359: if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1360: && cc_status.value2
1361: && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1362: cc_status.value2 = 0;
1363: if (((cc_status.value1 && FP_REG_P (cc_status.value1))
1364: || (cc_status.value2 && FP_REG_P (cc_status.value2)))
1365: && !((cc_status.value1 && FPA_REG_P (cc_status.value1))
1366: || (cc_status.value2 && FPA_REG_P (cc_status.value2))))
1367: cc_status.flags = CC_IN_68881;
1368: }
1369:
1370: char *
1371: output_move_const_double (operands)
1372: rtx *operands;
1373: {
1374: #ifdef SUPPORT_SUN_FPA
1375: if (TARGET_FPA && FPA_REG_P (operands[0]))
1376: {
1377: int code = standard_sun_fpa_constant_p (operands[1]);
1378:
1379: if (code != 0)
1380: {
1381: static char buf[40];
1382:
1383: sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff);
1384: return buf;
1385: }
1386: return "fpmove%.d %1,%0";
1387: }
1388: else
1389: #endif
1390: {
1391: int code = standard_68881_constant_p (operands[1]);
1392:
1393: if (code != 0)
1394: {
1395: static char buf[40];
1396:
1397: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
1398: return buf;
1399: }
1400: return "fmove%.d %1,%0";
1401: }
1402: }
1403:
1404: char *
1405: output_move_const_single (operands)
1406: rtx *operands;
1407: {
1408: #ifdef SUPPORT_SUN_FPA
1409: if (TARGET_FPA)
1410: {
1411: int code = standard_sun_fpa_constant_p (operands[1]);
1412:
1413: if (code != 0)
1414: {
1415: static char buf[40];
1416:
1417: sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff);
1418: return buf;
1419: }
1420: return "fpmove%.s %1,%0";
1421: }
1422: else
1423: #endif /* defined SUPPORT_SUN_FPA */
1424: {
1425: int code = standard_68881_constant_p (operands[1]);
1426:
1427: if (code != 0)
1428: {
1429: static char buf[40];
1430:
1431: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
1432: return buf;
1433: }
1434: return "fmove%.s %f1,%0";
1435: }
1436: }
1437:
1438: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
1439: from the "fmovecr" instruction.
1440: The value, anded with 0xff, gives the code to use in fmovecr
1441: to get the desired constant. */
1442:
1443: /* This code has been fixed for cross-compilation. */
1444:
1445: static int inited_68881_table = 0;
1446:
1447: char *strings_68881[7] = {
1448: "0.0",
1449: "1.0",
1450: "10.0",
1451: "100.0",
1452: "10000.0",
1453: "1e8",
1454: "1e16"
1455: };
1456:
1457: int codes_68881[7] = {
1458: 0x0f,
1459: 0x32,
1460: 0x33,
1461: 0x34,
1462: 0x35,
1463: 0x36,
1464: 0x37
1465: };
1466:
1467: REAL_VALUE_TYPE values_68881[7];
1468:
1469: /* Set up values_68881 array by converting the decimal values
1470: strings_68881 to binary. */
1471:
1472: void
1473: init_68881_table ()
1474: {
1475: int i;
1476: REAL_VALUE_TYPE r;
1477: enum machine_mode mode;
1478:
1479: mode = DFmode;
1480: for (i = 0; i < 7; i++)
1481: {
1482: if (i == 6)
1483: mode = SFmode;
1484: r = REAL_VALUE_ATOF (strings_68881[i], mode);
1485: values_68881[i] = r;
1486: }
1487: inited_68881_table = 1;
1488: }
1489:
1490: int
1491: standard_68881_constant_p (x)
1492: rtx x;
1493: {
1494: REAL_VALUE_TYPE r;
1495: int i;
1496: enum machine_mode mode;
1497:
1498: /* fmovecr must be emulated on the 68040, so it shouldn't be used at all. */
1499: if (TARGET_68040)
1500: return 0;
1501:
1502: #ifndef REAL_ARITHMETIC
1503: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
1504: if (! flag_pretend_float)
1505: return 0;
1506: #endif
1507: #endif
1508:
1509: if (! inited_68881_table)
1510: init_68881_table ();
1511:
1512: REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1513:
1514: for (i = 0; i < 6; i++)
1515: {
1516: if (REAL_VALUES_EQUAL (r, values_68881[i]))
1517: return (codes_68881[i]);
1518: }
1519:
1520: if (GET_MODE (x) == SFmode)
1521: return 0;
1522:
1523: if (REAL_VALUES_EQUAL (r, values_68881[6]))
1524: return (codes_68881[6]);
1525:
1526: /* larger powers of ten in the constants ram are not used
1527: because they are not equal to a `double' C constant. */
1528: return 0;
1529: }
1530:
1531: /* If X is a floating-point constant, return the logarithm of X base 2,
1532: or 0 if X is not a power of 2. */
1533:
1534: int
1535: floating_exact_log2 (x)
1536: rtx x;
1537: {
1538: REAL_VALUE_TYPE r, r1;
1539: int i;
1540:
1541: #ifndef REAL_ARITHMETIC
1542: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
1543: if (! flag_pretend_float)
1544: return 0;
1545: #endif
1546: #endif
1547:
1548: REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1549:
1550: if (REAL_VALUES_LESS (r, dconst0))
1551: return 0;
1552:
1553: r1 = dconst1;
1554: i = 0;
1555: while (REAL_VALUES_LESS (r1, r))
1556: {
1557: r1 = REAL_VALUE_LDEXP (dconst1, i);
1558: if (REAL_VALUES_EQUAL (r1, r))
1559: return i;
1560: i = i + 1;
1561: }
1562: return 0;
1563: }
1564:
1565: #ifdef SUPPORT_SUN_FPA
1566: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
1567: from the Sun FPA's constant RAM.
1568: The value returned, anded with 0x1ff, gives the code to use in fpmove
1569: to get the desired constant. */
1570:
1571: static int inited_FPA_table = 0;
1572:
1573: char *strings_FPA[38] = {
1574: /* small rationals */
1575: "0.0",
1576: "1.0",
1577: "0.5",
1578: "-1.0",
1579: "2.0",
1580: "3.0",
1581: "4.0",
1582: "8.0",
1583: "0.25",
1584: "0.125",
1585: "10.0",
1586: "-0.5",
1587: /* Decimal equivalents of double precision values */
1588: "2.718281828459045091", /* D_E */
1589: "6.283185307179586477", /* 2 pi */
1590: "3.141592653589793116", /* D_PI */
1591: "1.570796326794896619", /* pi/2 */
1592: "1.414213562373095145", /* D_SQRT2 */
1593: "0.7071067811865475244", /* 1/sqrt(2) */
1594: "-1.570796326794896619", /* -pi/2 */
1595: "1.442695040888963387", /* D_LOG2ofE */
1596: "3.321928024887362182", /* D_LOG2of10 */
1597: "0.6931471805599452862", /* D_LOGEof2 */
1598: "2.302585092994045901", /* D_LOGEof10 */
1599: "0.3010299956639811980", /* D_LOG10of2 */
1600: "0.4342944819032518167", /* D_LOG10ofE */
1601: /* Decimal equivalents of single precision values */
1602: "2.718281745910644531", /* S_E */
1603: "6.283185307179586477", /* 2 pi */
1604: "3.141592741012573242", /* S_PI */
1605: "1.570796326794896619", /* pi/2 */
1606: "1.414213538169860840", /* S_SQRT2 */
1607: "0.7071067811865475244", /* 1/sqrt(2) */
1608: "-1.570796326794896619", /* -pi/2 */
1609: "1.442695021629333496", /* S_LOG2ofE */
1610: "3.321928024291992188", /* S_LOG2of10 */
1611: "0.6931471824645996094", /* S_LOGEof2 */
1612: "2.302585124969482442", /* S_LOGEof10 */
1613: "0.3010300099849700928", /* S_LOG10of2 */
1614: "0.4342944920063018799", /* S_LOG10ofE */
1615: };
1616:
1617:
1618: int codes_FPA[38] = {
1619: /* small rationals */
1620: 0x200,
1621: 0xe,
1622: 0xf,
1623: 0x10,
1624: 0x11,
1625: 0xb1,
1626: 0x12,
1627: 0x13,
1628: 0x15,
1629: 0x16,
1630: 0x17,
1631: 0x2e,
1632: /* double precision */
1633: 0x8,
1634: 0x9,
1635: 0xa,
1636: 0xb,
1637: 0xc,
1638: 0xd,
1639: 0x27,
1640: 0x28,
1641: 0x29,
1642: 0x2a,
1643: 0x2b,
1644: 0x2c,
1645: 0x2d,
1646: /* single precision */
1647: 0x8,
1648: 0x9,
1649: 0xa,
1650: 0xb,
1651: 0xc,
1652: 0xd,
1653: 0x27,
1654: 0x28,
1655: 0x29,
1656: 0x2a,
1657: 0x2b,
1658: 0x2c,
1659: 0x2d
1660: };
1661:
1662: REAL_VALUE_TYPE values_FPA[38];
1663:
1664: /* This code has been fixed for cross-compilation. */
1665:
1666: void
1667: init_FPA_table ()
1668: {
1669: enum machine_mode mode;
1670: int i;
1671: REAL_VALUE_TYPE r;
1672:
1673: mode = DFmode;
1674: for (i = 0; i < 38; i++)
1675: {
1676: if (i == 25)
1677: mode = SFmode;
1678: r = REAL_VALUE_ATOF (strings_FPA[i], mode);
1679: values_FPA[i] = r;
1680: }
1681: inited_FPA_table = 1;
1682: }
1683:
1684:
1685: int
1686: standard_sun_fpa_constant_p (x)
1687: rtx x;
1688: {
1689: REAL_VALUE_TYPE r;
1690: int i;
1691:
1692: #ifndef REAL_ARITHMETIC
1693: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
1694: if (! flag_pretend_float)
1695: return 0;
1696: #endif
1697: #endif
1698:
1699: if (! inited_FPA_table)
1700: init_FPA_table ();
1701:
1702: REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1703:
1704: for (i=0; i<12; i++)
1705: {
1706: if (REAL_VALUES_EQUAL (r, values_FPA[i]))
1707: return (codes_FPA[i]);
1708: }
1709:
1710: if (GET_MODE (x) == SFmode)
1711: {
1712: for (i=25; i<38; i++)
1713: {
1714: if (REAL_VALUES_EQUAL (r, values_FPA[i]))
1715: return (codes_FPA[i]);
1716: }
1717: }
1718: else
1719: {
1720: for (i=12; i<25; i++)
1721: {
1722: if (REAL_VALUES_EQUAL (r, values_FPA[i]))
1723: return (codes_FPA[i]);
1724: }
1725: }
1726: return 0x0;
1727: }
1728: #endif /* define SUPPORT_SUN_FPA */
1729:
1730: /* A C compound statement to output to stdio stream STREAM the
1731: assembler syntax for an instruction operand X. X is an RTL
1732: expression.
1733:
1734: CODE is a value that can be used to specify one of several ways
1735: of printing the operand. It is used when identical operands
1736: must be printed differently depending on the context. CODE
1737: comes from the `%' specification that was used to request
1738: printing of the operand. If the specification was just `%DIGIT'
1739: then CODE is 0; if the specification was `%LTR DIGIT' then CODE
1740: is the ASCII code for LTR.
1741:
1742: If X is a register, this macro should print the register's name.
1743: The names can be found in an array `reg_names' whose type is
1744: `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
1745:
1746: When the machine description has a specification `%PUNCT' (a `%'
1747: followed by a punctuation character), this macro is called with
1748: a null pointer for X and the punctuation character for CODE.
1749:
1750: The m68k specific codes are:
1751:
1752: '.' for dot needed in Motorola-style opcode names.
1753: '-' for an operand pushing on the stack:
1754: sp@-, -(sp) or -(%sp) depending on the style of syntax.
1755: '+' for an operand pushing on the stack:
1756: sp@+, (sp)+ or (%sp)+ depending on the style of syntax.
1757: '@' for a reference to the top word on the stack:
1758: sp@, (sp) or (%sp) depending on the style of syntax.
1759: '#' for an immediate operand prefix (# in MIT and Motorola syntax
1760: but & in SGS syntax).
1761: '!' for the cc register (used in an `and to cc' insn).
1762: '$' for the letter `s' in an op code, but only on the 68040.
1763: '&' for the letter `d' in an op code, but only on the 68040.
1764: '/' for register prefix needed by longlong.h.
1765:
1766: 'b' for byte insn (no effect, on the Sun; this is for the ISI).
1767: 'd' to force memory addressing to be absolute, not relative.
1768: 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex)
1769: 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather
1770: than directly). Second part of 'y' below.
1771: 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex),
1772: or print pair of registers as rx:ry.
1773: 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs
1774: CONST_DOUBLE's as SunFPA constant RAM registers if
1775: possible, so it should not be used except for the SunFPA.
1776:
1777: */
1778:
1779: void
1780: print_operand (file, op, letter)
1781: FILE *file; /* file to write to */
1782: rtx op; /* operand to print */
1783: int letter; /* %<letter> or 0 */
1784: {
1785: int i;
1786:
1787: if (letter == '.')
1788: {
1789: #ifdef MOTOROLA
1790: asm_fprintf (file, ".");
1791: #endif
1792: }
1793: else if (letter == '#')
1794: {
1795: asm_fprintf (file, "%0I");
1796: }
1797: else if (letter == '-')
1798: {
1799: #ifdef MOTOROLA
1800: asm_fprintf (file, "-(%Rsp)");
1801: #else
1802: asm_fprintf (file, "%Rsp@-");
1803: #endif
1804: }
1805: else if (letter == '+')
1806: {
1807: #ifdef MOTOROLA
1808: asm_fprintf (file, "(%Rsp)+");
1809: #else
1810: asm_fprintf (file, "%Rsp@+");
1811: #endif
1812: }
1813: else if (letter == '@')
1814: {
1815: #ifdef MOTOROLA
1816: asm_fprintf (file, "(%Rsp)");
1817: #else
1818: asm_fprintf (file, "%Rsp@");
1819: #endif
1820: }
1821: else if (letter == '!')
1822: {
1823: asm_fprintf (file, "%Rfpcr");
1824: }
1825: else if (letter == '$')
1826: {
1827: if (TARGET_68040_ONLY)
1828: {
1829: fprintf (file, "s");
1830: }
1831: }
1832: else if (letter == '&')
1833: {
1834: if (TARGET_68040_ONLY)
1835: {
1836: fprintf (file, "d");
1837: }
1838: }
1839: else if (letter == '/')
1840: {
1841: asm_fprintf (file, "%R");
1842: }
1843: else if (GET_CODE (op) == REG)
1844: {
1845: if (REGNO (op) < 16
1846: && (letter == 'y' || letter == 'x')
1847: && GET_MODE (op) == DFmode)
1848: {
1849: fprintf (file, "%s:%s", reg_names[REGNO (op)],
1850: reg_names[REGNO (op)+1]);
1851: }
1852: else
1853: {
1854: fprintf (file, "%s", reg_names[REGNO (op)]);
1855: }
1856: }
1857: else if (GET_CODE (op) == MEM)
1858: {
1859: output_address (XEXP (op, 0));
1860: if (letter == 'd' && ! TARGET_68020
1861: && CONSTANT_ADDRESS_P (XEXP (op, 0))
1862: && !(GET_CODE (XEXP (op, 0)) == CONST_INT
1863: && INTVAL (XEXP (op, 0)) < 0x8000
1864: && INTVAL (XEXP (op, 0)) >= -0x8000))
1865: {
1866: fprintf (file, ":l");
1867: }
1868: }
1869: #ifdef SUPPORT_SUN_FPA
1870: else if ((letter == 'y' || letter == 'w')
1871: && GET_CODE (op) == CONST_DOUBLE
1872: && (i = standard_sun_fpa_constant_p (op)))
1873: {
1874: fprintf (file, "%%%d", i & 0x1ff);
1875: }
1876: #endif
1877: else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
1878: {
1879: REAL_VALUE_TYPE r;
1880: REAL_VALUE_FROM_CONST_DOUBLE (r, op);
1881: ASM_OUTPUT_FLOAT_OPERAND (letter, file, r);
1882: }
1883: else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode)
1884: {
1885: REAL_VALUE_TYPE r;
1886: REAL_VALUE_FROM_CONST_DOUBLE (r, op);
1887: ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r);
1888: }
1889: else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
1890: {
1891: REAL_VALUE_TYPE r;
1892: REAL_VALUE_FROM_CONST_DOUBLE (r, op);
1893: ASM_OUTPUT_DOUBLE_OPERAND (file, r);
1894: }
1895: else
1896: {
1897: asm_fprintf (file, "%0I"); output_addr_const (file, op);
1898: }
1899: }
1900:
1901:
1902: /* A C compound statement to output to stdio stream STREAM the
1903: assembler syntax for an instruction operand that is a memory
1904: reference whose address is ADDR. ADDR is an RTL expression.
1905:
1906: Note that this contains a kludge that knows that the only reason
1907: we have an address (plus (label_ref...) (reg...)) when not generating
1908: PIC code is in the insn before a tablejump, and we know that m68k.md
1909: generates a label LInnn: on such an insn.
1910:
1911: It is possible for PIC to generate a (plus (label_ref...) (reg...))
1912: and we handle that just like we would a (plus (symbol_ref...) (reg...)).
1913:
1914: Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)"
1915: fails to assemble. Luckily "Lnnn(pc,d0.l*2)" produces the results
1916: we want. This difference can be accommodated by using an assembler
1917: define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other
1918: string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END
1919: macro. See m68k/sgs.h for an example; for versions without the bug.
1920:
1921: They also do not like things like "pea 1.w", so we simple leave off
1922: the .w on small constants.
1923:
1924: This routine is responsible for distinguishing between -fpic and -fPIC
1925: style relocations in an address. When generating -fpic code the
1926: offset is output in word mode (eg movel a5@(_foo:w), a0). When generating
1927: -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */
1928:
1929: void
1930: print_operand_address (file, addr)
1931: FILE *file;
1932: rtx addr;
1933: {
1934: register rtx reg1, reg2, breg, ireg;
1935: rtx offset;
1936:
1937: switch (GET_CODE (addr))
1938: {
1939: case REG:
1940: #ifdef MOTOROLA
1941: fprintf (file, "(%s)", reg_names[REGNO (addr)]);
1942: #else
1943: fprintf (file, "%s@", reg_names[REGNO (addr)]);
1944: #endif
1945: break;
1946: case PRE_DEC:
1947: #ifdef MOTOROLA
1948: fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
1949: #else
1950: fprintf (file, "%s@-", reg_names[REGNO (XEXP (addr, 0))]);
1951: #endif
1952: break;
1953: case POST_INC:
1954: #ifdef MOTOROLA
1955: fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
1956: #else
1957: fprintf (file, "%s@+", reg_names[REGNO (XEXP (addr, 0))]);
1958: #endif
1959: break;
1960: case PLUS:
1961: reg1 = reg2 = ireg = breg = offset = 0;
1962: if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
1963: {
1964: offset = XEXP (addr, 0);
1965: addr = XEXP (addr, 1);
1966: }
1967: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
1968: {
1969: offset = XEXP (addr, 1);
1970: addr = XEXP (addr, 0);
1971: }
1972: if (GET_CODE (addr) != PLUS)
1973: {
1974: ;
1975: }
1976: else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND)
1977: {
1978: reg1 = XEXP (addr, 0);
1979: addr = XEXP (addr, 1);
1980: }
1981: else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND)
1982: {
1983: reg1 = XEXP (addr, 1);
1984: addr = XEXP (addr, 0);
1985: }
1986: else if (GET_CODE (XEXP (addr, 0)) == MULT)
1987: {
1988: reg1 = XEXP (addr, 0);
1989: addr = XEXP (addr, 1);
1990: }
1991: else if (GET_CODE (XEXP (addr, 1)) == MULT)
1992: {
1993: reg1 = XEXP (addr, 1);
1994: addr = XEXP (addr, 0);
1995: }
1996: else if (GET_CODE (XEXP (addr, 0)) == REG)
1997: {
1998: reg1 = XEXP (addr, 0);
1999: addr = XEXP (addr, 1);
2000: }
2001: else if (GET_CODE (XEXP (addr, 1)) == REG)
2002: {
2003: reg1 = XEXP (addr, 1);
2004: addr = XEXP (addr, 0);
2005: }
2006: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT
2007: || GET_CODE (addr) == SIGN_EXTEND)
2008: {
2009: if (reg1 == 0)
2010: {
2011: reg1 = addr;
2012: }
2013: else
2014: {
2015: reg2 = addr;
2016: }
2017: addr = 0;
2018: }
2019: #if 0 /* for OLD_INDEXING */
2020: else if (GET_CODE (addr) == PLUS)
2021: {
2022: if (GET_CODE (XEXP (addr, 0)) == REG)
2023: {
2024: reg2 = XEXP (addr, 0);
2025: addr = XEXP (addr, 1);
2026: }
2027: else if (GET_CODE (XEXP (addr, 1)) == REG)
2028: {
2029: reg2 = XEXP (addr, 1);
2030: addr = XEXP (addr, 0);
2031: }
2032: }
2033: #endif
2034: if (offset != 0)
2035: {
2036: if (addr != 0)
2037: {
2038: abort ();
2039: }
2040: addr = offset;
2041: }
2042: if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND
2043: || GET_CODE (reg1) == MULT))
2044: || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
2045: {
2046: breg = reg2;
2047: ireg = reg1;
2048: }
2049: else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
2050: {
2051: breg = reg1;
2052: ireg = reg2;
2053: }
2054: if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF
2055: && ! (flag_pic && ireg == pic_offset_table_rtx))
2056: {
2057: int scale = 1;
2058: if (GET_CODE (ireg) == MULT)
2059: {
2060: scale = INTVAL (XEXP (ireg, 1));
2061: ireg = XEXP (ireg, 0);
2062: }
2063: if (GET_CODE (ireg) == SIGN_EXTEND)
2064: {
2065: #ifdef MOTOROLA
2066: #ifdef SGS
2067: asm_fprintf (file, "%LLD%d(%Rpc,%s.w",
2068: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2069: reg_names[REGNO (XEXP (ireg, 0))]);
2070: #else
2071: asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.w",
2072: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2073: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2074: reg_names[REGNO (XEXP (ireg, 0))]);
2075: #endif
2076: #else
2077: asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:w",
2078: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2079: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2080: reg_names[REGNO (XEXP (ireg, 0))]);
2081: #endif
2082: }
2083: else
2084: {
2085: #ifdef MOTOROLA
2086: #ifdef SGS
2087: asm_fprintf (file, "%LLD%d(%Rpc,%s.l",
2088: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2089: reg_names[REGNO (ireg)]);
2090: #else
2091: asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l",
2092: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2093: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2094: reg_names[REGNO (ireg)]);
2095: #endif
2096: #else
2097: asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l",
2098: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2099: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2100: reg_names[REGNO (ireg)]);
2101: #endif
2102: }
2103: if (scale != 1)
2104: {
2105: #ifdef MOTOROLA
2106: fprintf (file, "*%d", scale);
2107: #else
2108: fprintf (file, ":%d", scale);
2109: #endif
2110: }
2111: putc (')', file);
2112: break;
2113: }
2114: if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF
2115: && ! (flag_pic && breg == pic_offset_table_rtx))
2116: {
2117: #ifdef MOTOROLA
2118: #ifdef SGS
2119: asm_fprintf (file, "%LLD%d(%Rpc,%s.l",
2120: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2121: reg_names[REGNO (breg)]);
2122: #else
2123: asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l",
2124: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2125: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2126: reg_names[REGNO (breg)]);
2127: #endif
2128: #else
2129: asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l",
2130: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2131: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2132: reg_names[REGNO (breg)]);
2133: #endif
2134: putc (')', file);
2135: break;
2136: }
2137: if (ireg != 0 || breg != 0)
2138: {
2139: int scale = 1;
2140: if (breg == 0)
2141: {
2142: abort ();
2143: }
2144: if (! flag_pic && addr && GET_CODE (addr) == LABEL_REF)
2145: {
2146: abort ();
2147: }
2148: #ifdef MOTOROLA
2149: if (addr != 0)
2150: {
2151: output_addr_const (file, addr);
2152: if (flag_pic && (breg == pic_offset_table_rtx))
2153: fprintf (file, "@GOT");
2154: }
2155: fprintf (file, "(%s", reg_names[REGNO (breg)]);
2156: if (ireg != 0)
2157: {
2158: putc (',', file);
2159: }
2160: #else
2161: fprintf (file, "%s@(", reg_names[REGNO (breg)]);
2162: if (addr != 0)
2163: {
2164: output_addr_const (file, addr);
2165: if ((flag_pic == 1) && (breg == pic_offset_table_rtx))
2166: fprintf (file, ":w");
2167: if ((flag_pic == 2) && (breg == pic_offset_table_rtx))
2168: fprintf (file, ":l");
2169: }
2170: if (addr != 0 && ireg != 0)
2171: {
2172: putc (',', file);
2173: }
2174: #endif
2175: if (ireg != 0 && GET_CODE (ireg) == MULT)
2176: {
2177: scale = INTVAL (XEXP (ireg, 1));
2178: ireg = XEXP (ireg, 0);
2179: }
2180: if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND)
2181: {
2182: #ifdef MOTOROLA
2183: fprintf (file, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]);
2184: #else
2185: fprintf (file, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]);
2186: #endif
2187: }
2188: else if (ireg != 0)
2189: {
2190: #ifdef MOTOROLA
2191: fprintf (file, "%s.l", reg_names[REGNO (ireg)]);
2192: #else
2193: fprintf (file, "%s:l", reg_names[REGNO (ireg)]);
2194: #endif
2195: }
2196: if (scale != 1)
2197: {
2198: #ifdef MOTOROLA
2199: fprintf (file, "*%d", scale);
2200: #else
2201: fprintf (file, ":%d", scale);
2202: #endif
2203: }
2204: putc (')', file);
2205: break;
2206: }
2207: else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF
2208: && ! (flag_pic && reg1 == pic_offset_table_rtx))
2209: {
2210: #ifdef MOTOROLA
2211: #ifdef SGS
2212: asm_fprintf (file, "%LLD%d(%Rpc,%s.l)",
2213: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2214: reg_names[REGNO (reg1)]);
2215: #else
2216: asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l)",
2217: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2218: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2219: reg_names[REGNO (reg1)]);
2220: #endif
2221: #else
2222: asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l)",
2223: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2224: CODE_LABEL_NUMBER (XEXP (addr, 0)),
2225: reg_names[REGNO (reg1)]);
2226: #endif
2227: break;
2228: }
2229: /* FALL-THROUGH (is this really what we want? */
2230: default:
2231: if (GET_CODE (addr) == CONST_INT
2232: && INTVAL (addr) < 0x8000
2233: && INTVAL (addr) >= -0x8000)
2234: {
2235: #ifdef MOTOROLA
2236: #ifdef SGS
2237: /* Many SGS assemblers croak on size specifiers for constants. */
2238: fprintf (file, "%d", INTVAL (addr));
2239: #else
2240: fprintf (file, "%d.w", INTVAL (addr));
2241: #endif
2242: #else
2243: fprintf (file, "%d:w", INTVAL (addr));
2244: #endif
2245: }
2246: else
2247: {
2248: output_addr_const (file, addr);
2249: }
2250: break;
2251: }
2252: }
2253:
2254: /* Check for cases where a clr insns can be omitted from code using
2255: strict_low_part sets. For example, the second clrl here is not needed:
2256: clrl d0; movw a0@+,d0; use d0; clrl d0; movw a0@+; use d0; ...
2257:
2258: MODE is the mode of this STRICT_LOW_PART set. FIRST_INSN is the clear
2259: insn we are checking for redundancy. TARGET is the register set by the
2260: clear insn. */
2261:
2262: int
2263: strict_low_part_peephole_ok (mode, first_insn, target)
2264: enum machine_mode mode;
2265: rtx first_insn;
2266: rtx target;
2267: {
2268: rtx p;
2269:
2270: p = prev_nonnote_insn (first_insn);
2271:
2272: while (p)
2273: {
2274: /* If it isn't an insn, then give up. */
2275: if (GET_CODE (p) != INSN)
2276: return 0;
2277:
2278: if (reg_set_p (target, p))
2279: {
2280: rtx set = single_set (p);
2281: rtx dest;
2282:
2283: /* If it isn't an easy to recognize insn, then give up. */
2284: if (! set)
2285: return 0;
2286:
2287: dest = SET_DEST (set);
2288:
2289: /* If this sets the entire target register to zero, then our
2290: first_insn is redundant. */
2291: if (rtx_equal_p (dest, target)
2292: && SET_SRC (set) == const0_rtx)
2293: return 1;
2294: else if (GET_CODE (dest) == STRICT_LOW_PART
2295: && GET_CODE (XEXP (dest, 0)) == REG
2296: && REGNO (XEXP (dest, 0)) == REGNO (target)
2297: && (GET_MODE_SIZE (GET_MODE (XEXP (dest, 0)))
2298: <= GET_MODE_SIZE (mode)))
2299: /* This is a strict low part set which modifies less than
2300: we are using, so it is safe. */
2301: ;
2302: else
2303: return 0;
2304: }
2305:
2306: p = prev_nonnote_insn (p);
2307:
2308: }
2309:
2310: return 0;
2311: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.