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