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