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