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