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