|
|
1.1 root 1: /* Subroutines for insn-output.c for Motorola 88000.
2: Copyright (C) 1987 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
4:
5: This file is part of GNU CC.
6:
1.1.1.4 ! root 7: GNU CC is free software; you can redistribute it and/or modify
! 8: it under the terms of the GNU General Public License as published by
! 9: the Free Software Foundation; either version 1, or (at your option)
! 10: any later version.
! 11:
1.1 root 12: GNU CC is distributed in the hope that it will be useful,
1.1.1.4 ! root 13: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 15: GNU General Public License for more details.
! 16:
! 17: You should have received a copy of the GNU General Public License
! 18: along with GNU CC; see the file COPYING. If not, write to
! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
1.1 root 20:
21: #ifndef FILE
22: #include <stdio.h>
23: #endif
24:
25: /* This is where the condition code register lives. */
26: rtx cc0_reg_rtx;
27:
28: static rtx find_addr_reg ();
29:
30: #if 0
31: char *
32: output_compare (operands, opcode, exchange_opcode)
33: rtx *operands;
34: char *opcode;
35: char *exchange_opcode;
36: {
37: static char buf[40];
38: rtx op1, op2;
39:
1.1.1.4 ! root 40: if (GET_CODE (cc_prev_status.value2) == COMPARE)
1.1 root 41: {
42: op1 = XEXP (cc_prev_status.value2, 0);
43: op2 = XEXP (cc_prev_status.value2, 1);
44: }
45: else
46: {
47: op1 = cc_prev_status.value2;
48: op2 = const0_rtx;
49: }
50: if (GET_CODE (op1) == CONST_INT)
51: {
52: operands[2] = op1;
53: operands[1] = op2;
54: opcode = exchange_opcode;
55: }
56: else
57: {
58: operands[1] = op1;
59: operands[2] = op2;
60: }
61: sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode);
62: return buf;
63: }
64:
65: char *
66: output_fcompare (operands, opcode, exchange_opcode)
67: rtx *operands;
68: char *opcode;
69: char *exchange_opcode;
70: {
71: static char buf[40];
72:
73: rtx op1, op2;
74:
1.1.1.4 ! root 75: if (GET_CODE (cc_prev_status.value2) == COMPARE)
1.1 root 76: {
77: op1 = XEXP (cc_prev_status.value2, 0);
78: op2 = XEXP (cc_prev_status.value2, 1);
79: }
80: else
81: {
82: op1 = cc_prev_status.value2;
83: op2 = const0_rtx;
84: }
85: if (GET_CODE (op1) == CONST_DOUBLE)
86: {
87: operands[2] = op1;
88: operands[1] = op2;
89: opcode = exchange_opcode;
90: }
91: else
92: {
93: operands[1] = op1;
94: operands[2] = op2;
95: }
96: sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode);
97: return buf;
98: }
99:
100: char *
101: output_store (operands, opcode, exchange_opcode)
102: rtx *operands;
103: char *opcode;
104: char *exchange_opcode;
105: {
106: static char buf[40];
107: rtx op1, op2;
108:
1.1.1.4 ! root 109: if (GET_CODE (cc_prev_status.value2) == COMPARE)
1.1 root 110: {
111: op1 = XEXP (cc_prev_status.value2, 0);
112: op2 = XEXP (cc_prev_status.value2, 1);
113: }
114: else
115: {
116: op1 = cc_prev_status.value2;
117: op2 = const0_rtx;
118: }
119:
120: if (GET_CODE (op1) == CONST_INT)
121: {
122: operands[2] = op1;
123: operands[1] = op2;
124: opcode = exchange_opcode;
125: }
126: else
127: {
128: operands[1] = op1;
129: operands[2] = op2;
130: }
131:
132: sprintf (buf, "cmp r25,%%1,%%2\n\textu %%0,r25,1<%s>", opcode);
133: return buf;
134: }
135: #endif
136:
137: /* Nonzero if OP is a valid second operand for an arithmetic insn. */
138:
139: int
140: arith_operand (op, mode)
141: rtx op;
142: enum machine_mode mode;
143: {
144: return (register_operand (op, mode)
145: || (GET_CODE (op) == CONST_INT
146: && (unsigned) INTVAL (op) < 0x10000));
147: }
148:
149: int
150: arith32_operand (op, mode)
151: rtx op;
152: enum machine_mode mode;
153: {
154: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
155: }
156:
157: int
158: int5_operand (op, mode)
159: rtx op;
160: enum machine_mode mode;
161: {
162: return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x20);
163: }
164:
165: /* Return the best assembler insn template
166: for moving operands[1] into operands[0] as a fullword. */
167:
168: static char *
169: singlemove_string (operands)
170: rtx *operands;
171: {
172: if (GET_CODE (operands[0]) == MEM)
173: return "st %r1,%0";
174: if (GET_CODE (operands[1]) == MEM)
175: return "ld %0,%1";
176: return "or %0,r0,%1";
177: }
178:
179: /* Output assembler code to perform a doubleword move insn
180: with operands OPERANDS. */
181:
182: char *
183: output_move_double (operands)
184: rtx *operands;
185: {
186: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
187: rtx latehalf[2];
188: rtx addreg0 = 0, addreg1 = 0;
189:
190: /* First classify both operands. */
191:
192: if (REG_P (operands[0]))
193: optype0 = REGOP;
194: else if (offsetable_memref_p (operands[0]))
195: optype0 = OFFSOP;
196: else if (GET_CODE (operands[0]) == MEM)
197: optype0 = MEMOP;
198: else
199: optype0 = RNDOP;
200:
201: if (REG_P (operands[1]))
202: optype1 = REGOP;
203: else if (CONSTANT_P (operands[1])
204: || GET_CODE (operands[1]) == CONST_DOUBLE)
205: optype1 = CNSTOP;
206: else if (offsetable_memref_p (operands[1]))
207: optype1 = OFFSOP;
208: else if (GET_CODE (operands[1]) == MEM)
1.1.1.2 root 209: optype1 = MEMOP;
1.1 root 210: else
211: optype1 = RNDOP;
212:
213: /* Check for the cases that the operand constraints are not
214: supposed to allow to happen. Abort if we get one,
215: because generating code for these cases is painful. */
216:
217: if (optype0 == RNDOP || optype1 == RNDOP)
218: abort ();
219:
220: /* If an operand is an unoffsettable memory ref, find a register
221: we can increment temporarily to make it refer to the second word. */
222:
223: if (optype0 == MEMOP)
224: addreg0 = find_addr_reg (operands[0]);
225:
226: if (optype1 == MEMOP)
227: addreg1 = find_addr_reg (operands[1]);
228:
229: /* Ok, we can do one word at a time.
230: Normally we do the low-numbered word first,
231: but if either operand is autodecrementing then we
232: do the high-numbered word first.
233:
234: In either case, set up in LATEHALF the operands to use
235: for the high-numbered word and in some cases alter the
236: operands in OPERANDS to be suitable for the low-numbered word. */
237:
238: if (optype0 == REGOP)
239: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
240: else if (optype0 == OFFSOP)
241: latehalf[0] = adj_offsetable_operand (operands[0], 4);
242: else
243: latehalf[0] = operands[0];
244:
245: if (optype1 == REGOP)
246: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
247: else if (optype1 == OFFSOP)
248: latehalf[1] = adj_offsetable_operand (operands[1], 4);
249: else if (optype1 == CNSTOP)
250: {
251: if (CONSTANT_P (operands[1]))
252: latehalf[1] = const0_rtx;
253: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
254: {
1.1.1.3 root 255: latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
256: CONST_DOUBLE_HIGH (operands[1]));
257: operands[1] = gen_rtx (CONST_INT, VOIDmode,
258: CONST_DOUBLE_LOW (operands[1]));
1.1 root 259: }
260: }
261: else
262: latehalf[1] = operands[1];
263:
264: /* If the first move would clobber the source of the second one,
265: do them in the other order. This happens only for registers;
266: such overlap can't happen in memory unless the user explicitly
267: sets it up, and that is an undefined circumstance. */
268:
269: if (optype0 == REGOP && optype1 == REGOP
270: && REGNO (operands[0]) == REGNO (latehalf[1]))
271: {
272: /* Make any unoffsetable addresses point at high-numbered word. */
273: if (addreg0)
274: output_asm_insn ("addu %0,%0,4", &addreg0);
275: if (addreg1)
276: output_asm_insn ("addu %0,%0,4", &addreg1);
277:
278: /* Do that word. */
279: output_asm_insn (singlemove_string (latehalf), latehalf);
280:
281: /* Undo the adds we just did. */
282: if (addreg0)
283: output_asm_insn ("subu %0,%0,4", &addreg0);
284: if (addreg1)
285: output_asm_insn ("subu %0,%0,4", &addreg0);
286:
287: /* Do low-numbered word. */
288: return singlemove_string (operands);
289: }
290:
291: /* Normal case: do the two words, low-numbered first. */
292:
293: output_asm_insn (singlemove_string (operands), operands);
294:
295: /* Make any unoffsetable addresses point at high-numbered word. */
296: if (addreg0)
297: output_asm_insn ("addu %0,%0,4", &addreg0);
298: if (addreg1)
299: output_asm_insn ("addu %0,%0,4", &addreg1);
300:
301: /* Do that word. */
302: output_asm_insn (singlemove_string (latehalf), latehalf);
303:
304: /* Undo the adds we just did. */
305: if (addreg0)
306: output_asm_insn ("subu %0,%0,4", &addreg0);
307: if (addreg1)
308: output_asm_insn ("subu %0,%0,4", &addreg1);
309:
310: return "";
311: }
312:
313: /* Return a REG that occurs in ADDR with coefficient 1.
314: ADDR can be effectively incremented by incrementing REG. */
315:
316: static rtx
317: find_addr_reg (addr)
318: rtx addr;
319: {
320: while (GET_CODE (addr) == PLUS)
321: {
322: if (GET_CODE (XEXP (addr, 0)) == REG)
323: addr = XEXP (addr, 0);
324: if (GET_CODE (XEXP (addr, 1)) == REG)
325: addr = XEXP (addr, 1);
326: if (CONSTANT_P (XEXP (addr, 0)))
327: addr = XEXP (addr, 1);
328: if (CONSTANT_P (XEXP (addr, 1)))
329: addr = XEXP (addr, 0);
330: }
331: if (GET_CODE (addr) == REG)
332: return addr;
333: return 0;
334: }
335:
336: /* Output an ascii string. */
337: output_ascii (file, p, size)
338: FILE *file;
339: char *p;
340: int size;
341: {
342: int i;
343:
344: fprintf (file, "\tstring \"");
345:
346: for (i = 0; i < size; i++)
347: {
348: register int c = p[i];
349: if (c == '\"' || c == '\\')
350: putc ('\\', file);
351: if (c >= ' ' && c < 0177)
352: putc (c, file);
353: else
354: {
355: fprintf (file, "\\%03o", c);
356: /* After an octal-escape, if a digit follows,
357: terminate one string constant and start another.
358: The Vax assembler fails to stop reading the escape
359: after three digits, so this is the only way we
360: can get it to parse the data properly. */
361: if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
362: fprintf (file, "\"\n\tstring \"");
363: }
364: }
365: fprintf (file, "\"\n");
366: }
367:
368: void
369: output_load_address (operands)
370: rtx *operands;
371: {
372: rtx base, offset;
373:
374: if (CONSTANT_P (operands[3]))
375: {
376: output_asm_insn ("lda %0,%3", operands);
377: return;
378: }
379:
380: if (REG_P (operands[3]))
381: {
382: if (REGNO (operands[0]) != REGNO (operands[3]))
383: output_asm_insn ("or %0,r0,%3", operands);
384: return;
385: }
386:
387: base = XEXP (operands[3], 0);
388: offset = XEXP (operands[3], 1);
389:
390: if (GET_CODE (base) == CONST_INT)
391: {
392: rtx tmp = base;
393: base = offset;
394: offset = tmp;
395: }
396:
397: if (GET_CODE (offset) != CONST_INT)
398: abort ();
399:
400: operands[6] = base;
401: operands[7] = offset;
402:
403: if (REG_P (base))
404: if (FITS_16_BITS (offset))
405: output_asm_insn ("addu %0,%6,%7", operands);
406: else if (INT_FITS_16_BITS (- INTVAL (offset)))
407: output_asm_insn ("subu %0,%6,%7", operands);
408: else
409: output_asm_insn ("or.h %0,r0,hi16(%7)\n\tor %0,%0,lo16(%7)\n\tadd %0,%6,%0", operands);
410: else
411: {
412: if (GET_CODE (base) == MULT)
413: if (GET_MODE (base) == QImode)
414: output_asm_insn ("lda.b %0,%6");
415: else if (GET_MODE (base) == HImode)
416: output_asm_insn ("lda.h %0,%6");
417: else if (GET_MODE (base) == SImode)
418: output_asm_insn ("lda %0,%6");
419: else
420: output_asm_insn ("lda.d %0,%6");
421: else
422: output_asm_insn ("lda %0,%6");
423:
424: if (FITS_16_BITS (offset))
425: output_asm_insn ("addu %0,%7,%0", operands);
426: else if (INT_FITS_16_BITS (- INTVAL (offset)))
427: output_asm_insn ("subu %0,%7,%0", operands);
428: else
429: output_asm_insn ("or.h r25,r0,hi16(%7)\n\tor r25,r0,lo16(%7)\n\taddu %0,%0r25", operands);
430: }
431: }
432:
433: char *
434: output_block_move (operands)
435: rtx *operands;
436: {
437: static int movstrsi_label = 0;
438: int align = 4;
439:
440: rtx xoperands[9];
441: int available[3];
442: int i, j;
443:
444: /* Since we clobber untold things, nix the condition codes. */
445: CC_STATUS_INIT;
446:
447: /* Get past the MEMs. */
448: operands[0] = XEXP (operands[0], 0);
449: operands[1] = XEXP (operands[1], 0);
450:
451: xoperands[0] = 0;
452: xoperands[1] = 0;
453: xoperands[2] = 0;
454:
455: available[0] = 1;
456: available[1] = 1;
457: available[2] = 1;
458: #if 1
459: /* Prepare to juggle registers if necessary. */
460: if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 10) < 3)
461: {
462: xoperands[0] = operands[0];
463: available[REGNO (operands[0]) - 10] = 0;
464: }
465: if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 10) < 3)
466: {
467: xoperands[1] = operands[1];
468: available[REGNO (operands[1]) - 10] = 0;
469: }
470: if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 10) < 3)
471: {
472: xoperands[2] = operands[2];
473: available[REGNO (operands[2]) - 10] = 0;
474: }
475: for (i = 0; i < 3; i++)
476: {
477: if (xoperands[i])
478: continue;
479: if (available[0])
480: {
481: xoperands[i] = gen_rtx (REG, SImode, 10);
482: available[0] = 0;
483: continue;
484: }
485: if (available[1])
486: {
487: xoperands[i] = gen_rtx (REG, SImode, 11);
488: available[1] = 0;
489: continue;
490: }
491: xoperands[i] = gen_rtx (REG, SImode, 12);
492: available[2] = 0;
493: }
494: #endif
495:
496: /* First, figure out best alignment we may assume. */
497: if (REG_P (operands[2]))
498: {
499: xoperands[5] = operands[2];
500: output_asm_insn ("sub %5,%2,1", xoperands);
501: align = 1;
502: }
503: else
504: {
505: int i = INTVAL (operands[2]);
506:
507: if (i & 1)
508: align = 1;
509: else if (i & 3)
510: {
511: align = 2;
512: i >>= 1;
513: }
514: else
515: i >>= 2;
516:
517: /* predecrement count. */
518: i -= 1;
519: if (i < 0) abort ();
520:
521: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i);
522:
523: if (INT_FITS_16_BITS (i))
524: output_asm_insn ("addu %2,r0,%5", xoperands);
525: else if (INT_FITS_16_BITS (-i))
526: {
527: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, -i);
528: output_asm_insn ("subu %2,r0,%5", xoperands);
529: }
530: else
531: output_asm_insn ("or.u %2,r0,hi16(%5)\n\tor %2,%2,lo16(%5)", xoperands);
532: }
533: /* Now, set up for pipelined operation: dest must contain
534: a pre-incremented address, because its index is pre-decremented. */
535:
536: xoperands[3] = plus_constant (operands[0], align);
537: output_load_address (xoperands);
538:
539: xoperands[4] = operands[1];
540: output_load_address (xoperands+1);
541:
542: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
543:
544: if (align == 4)
545: output_asm_insn ("\n@Lm%3:\n\tld r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst r25,%0[%2]", xoperands);
546: else if (align == 2)
547: output_asm_insn ("\n@Lm%3:\n\tld.h r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.h r25,%0[%2]", xoperands);
548: else
549: output_asm_insn ("\n@Lm%3:\n\tld.b r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.b r25,%0[%2]", xoperands);
550: return "";
551: }
552:
553: char *
554: output_store_const_int (mode, operands)
555: enum machine_mode mode;
556: rtx *operands;
557: {
558: int i = INTVAL (operands[1]);
559: if (INT_FITS_16_BITS (i))
560: return "addu %0,r0,%1";
561: if (INT_FITS_16_BITS (-i))
562: {
563: operands[1] = gen_rtx (CONST_INT, VOIDmode, -i);
564: return "subu %0,r0,%1";
565: }
566: if ((i & 0xffff) == 0)
567: return "or.u %0,r0,hi16(%1)";
568: /* Could check to see if number is a contiguous field
569: of 1's. Then we could use the SET instruction. */
570: if (mode == HImode)
571: {
572: warning ("truncating constant `%d' to fit in half-word", INTVAL (operands[1]));
573: return "or %0,r0,lo16(%1)";
574: }
575: if (mode == QImode)
576: {
577: warning ("truncating constant `%d' to fit in byte");
578: operands[1] = gen_rtx (CONST_INT, VOIDmode, i & 0xff);
579: return "or %0,r0,%1";
580: }
581:
582: return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)";
583: }
584:
585: /* This routine assumes that floating point numbers are represented
586: in a manner which is consistent between host and target machines. */
587: char *
588: output_store_const_float (mode, operands)
589: enum machine_mode mode;
590: rtx *operands;
591: {
592: int i = INTVAL (operands[1]);
593: if (INT_FITS_16_BITS (i))
594: return "addu %0,r0,%1";
595: if (INT_FITS_16_BITS (-i))
596: {
597: operands[1] = gen_rtx (CONST_INT, VOIDmode, -i);
598: return "subu %0,r0,%1";
599: }
600: if ((i & 0xffff) == 0)
601: return "or.u %0,r0,hi16(%1)";
602: /* Could check to see if number is a contiguous field
603: of 1's. Then we could use the SET instruction. */
604: return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)";
605: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.