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