|
|
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)
210: optype0 = MEMOP;
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: {
256: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
257: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
258: }
259: }
260: else
261: latehalf[1] = operands[1];
262:
263: /* If the first move would clobber the source of the second one,
264: do them in the other order. This happens only for registers;
265: such overlap can't happen in memory unless the user explicitly
266: sets it up, and that is an undefined circumstance. */
267:
268: if (optype0 == REGOP && optype1 == REGOP
269: && REGNO (operands[0]) == REGNO (latehalf[1]))
270: {
271: /* Make any unoffsetable addresses point at high-numbered word. */
272: if (addreg0)
273: output_asm_insn ("addu %0,%0,4", &addreg0);
274: if (addreg1)
275: output_asm_insn ("addu %0,%0,4", &addreg1);
276:
277: /* Do that word. */
278: output_asm_insn (singlemove_string (latehalf), latehalf);
279:
280: /* Undo the adds we just did. */
281: if (addreg0)
282: output_asm_insn ("subu %0,%0,4", &addreg0);
283: if (addreg1)
284: output_asm_insn ("subu %0,%0,4", &addreg0);
285:
286: /* Do low-numbered word. */
287: return singlemove_string (operands);
288: }
289:
290: /* Normal case: do the two words, low-numbered first. */
291:
292: output_asm_insn (singlemove_string (operands), operands);
293:
294: /* Make any unoffsetable addresses point at high-numbered word. */
295: if (addreg0)
296: output_asm_insn ("addu %0,%0,4", &addreg0);
297: if (addreg1)
298: output_asm_insn ("addu %0,%0,4", &addreg1);
299:
300: /* Do that word. */
301: output_asm_insn (singlemove_string (latehalf), latehalf);
302:
303: /* Undo the adds we just did. */
304: if (addreg0)
305: output_asm_insn ("subu %0,%0,4", &addreg0);
306: if (addreg1)
307: output_asm_insn ("subu %0,%0,4", &addreg1);
308:
309: return "";
310: }
311:
312: /* Return a REG that occurs in ADDR with coefficient 1.
313: ADDR can be effectively incremented by incrementing REG. */
314:
315: static rtx
316: find_addr_reg (addr)
317: rtx addr;
318: {
319: while (GET_CODE (addr) == PLUS)
320: {
321: if (GET_CODE (XEXP (addr, 0)) == REG)
322: addr = XEXP (addr, 0);
323: if (GET_CODE (XEXP (addr, 1)) == REG)
324: addr = XEXP (addr, 1);
325: if (CONSTANT_P (XEXP (addr, 0)))
326: addr = XEXP (addr, 1);
327: if (CONSTANT_P (XEXP (addr, 1)))
328: addr = XEXP (addr, 0);
329: }
330: if (GET_CODE (addr) == REG)
331: return addr;
332: return 0;
333: }
334:
335: /* Output an ascii string. */
336: output_ascii (file, p, size)
337: FILE *file;
338: char *p;
339: int size;
340: {
341: int i;
342:
343: fprintf (file, "\tstring \"");
344:
345: for (i = 0; i < size; i++)
346: {
347: register int c = p[i];
348: if (c == '\"' || c == '\\')
349: putc ('\\', file);
350: if (c >= ' ' && c < 0177)
351: putc (c, file);
352: else
353: {
354: fprintf (file, "\\%03o", c);
355: /* After an octal-escape, if a digit follows,
356: terminate one string constant and start another.
357: The Vax assembler fails to stop reading the escape
358: after three digits, so this is the only way we
359: can get it to parse the data properly. */
360: if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
361: fprintf (file, "\"\n\tstring \"");
362: }
363: }
364: fprintf (file, "\"\n");
365: }
366:
367: void
368: output_load_address (operands)
369: rtx *operands;
370: {
371: rtx base, offset;
372:
373: if (CONSTANT_P (operands[3]))
374: {
375: output_asm_insn ("lda %0,%3", operands);
376: return;
377: }
378:
379: if (REG_P (operands[3]))
380: {
381: if (REGNO (operands[0]) != REGNO (operands[3]))
382: output_asm_insn ("or %0,r0,%3", operands);
383: return;
384: }
385:
386: base = XEXP (operands[3], 0);
387: offset = XEXP (operands[3], 1);
388:
389: if (GET_CODE (base) == CONST_INT)
390: {
391: rtx tmp = base;
392: base = offset;
393: offset = tmp;
394: }
395:
396: if (GET_CODE (offset) != CONST_INT)
397: abort ();
398:
399: operands[6] = base;
400: operands[7] = offset;
401:
402: if (REG_P (base))
403: if (FITS_16_BITS (offset))
404: output_asm_insn ("addu %0,%6,%7", operands);
405: else if (INT_FITS_16_BITS (- INTVAL (offset)))
406: output_asm_insn ("subu %0,%6,%7", operands);
407: else
408: output_asm_insn ("or.h %0,r0,hi16(%7)\n\tor %0,%0,lo16(%7)\n\tadd %0,%6,%0", operands);
409: else
410: {
411: if (GET_CODE (base) == MULT)
412: if (GET_MODE (base) == QImode)
413: output_asm_insn ("lda.b %0,%6");
414: else if (GET_MODE (base) == HImode)
415: output_asm_insn ("lda.h %0,%6");
416: else if (GET_MODE (base) == SImode)
417: output_asm_insn ("lda %0,%6");
418: else
419: output_asm_insn ("lda.d %0,%6");
420: else
421: output_asm_insn ("lda %0,%6");
422:
423: if (FITS_16_BITS (offset))
424: output_asm_insn ("addu %0,%7,%0", operands);
425: else if (INT_FITS_16_BITS (- INTVAL (offset)))
426: output_asm_insn ("subu %0,%7,%0", operands);
427: else
428: output_asm_insn ("or.h r25,r0,hi16(%7)\n\tor r25,r0,lo16(%7)\n\taddu %0,%0r25", operands);
429: }
430: }
431:
432: char *
433: output_block_move (operands)
434: rtx *operands;
435: {
436: static int movstrsi_label = 0;
437: int align = 4;
438:
439: rtx xoperands[9];
440: int available[3];
441: int i, j;
442:
443: /* Since we clobber untold things, nix the condition codes. */
444: CC_STATUS_INIT;
445:
446: /* Get past the MEMs. */
447: operands[0] = XEXP (operands[0], 0);
448: operands[1] = XEXP (operands[1], 0);
449:
450: xoperands[0] = 0;
451: xoperands[1] = 0;
452: xoperands[2] = 0;
453:
454: available[0] = 1;
455: available[1] = 1;
456: available[2] = 1;
457: #if 1
458: /* Prepare to juggle registers if necessary. */
459: if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 10) < 3)
460: {
461: xoperands[0] = operands[0];
462: available[REGNO (operands[0]) - 10] = 0;
463: }
464: if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 10) < 3)
465: {
466: xoperands[1] = operands[1];
467: available[REGNO (operands[1]) - 10] = 0;
468: }
469: if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 10) < 3)
470: {
471: xoperands[2] = operands[2];
472: available[REGNO (operands[2]) - 10] = 0;
473: }
474: for (i = 0; i < 3; i++)
475: {
476: if (xoperands[i])
477: continue;
478: if (available[0])
479: {
480: xoperands[i] = gen_rtx (REG, SImode, 10);
481: available[0] = 0;
482: continue;
483: }
484: if (available[1])
485: {
486: xoperands[i] = gen_rtx (REG, SImode, 11);
487: available[1] = 0;
488: continue;
489: }
490: xoperands[i] = gen_rtx (REG, SImode, 12);
491: available[2] = 0;
492: }
493: #endif
494:
495: /* First, figure out best alignment we may assume. */
496: if (REG_P (operands[2]))
497: {
498: xoperands[5] = operands[2];
499: output_asm_insn ("sub %5,%2,1", xoperands);
500: align = 1;
501: }
502: else
503: {
504: int i = INTVAL (operands[2]);
505:
506: if (i & 1)
507: align = 1;
508: else if (i & 3)
509: {
510: align = 2;
511: i >>= 1;
512: }
513: else
514: i >>= 2;
515:
516: /* predecrement count. */
517: i -= 1;
518: if (i < 0) abort ();
519:
520: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i);
521:
522: if (INT_FITS_16_BITS (i))
523: output_asm_insn ("addu %2,r0,%5", xoperands);
524: else if (INT_FITS_16_BITS (-i))
525: {
526: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, -i);
527: output_asm_insn ("subu %2,r0,%5", xoperands);
528: }
529: else
530: output_asm_insn ("or.u %2,r0,hi16(%5)\n\tor %2,%2,lo16(%5)", xoperands);
531: }
532: /* Now, set up for pipelined operation: dest must contain
533: a pre-incremented address, because its index is pre-decremented. */
534:
535: xoperands[3] = plus_constant (operands[0], align);
536: output_load_address (xoperands);
537:
538: xoperands[4] = operands[1];
539: output_load_address (xoperands+1);
540:
541: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
542:
543: if (align == 4)
544: 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);
545: else if (align == 2)
546: 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);
547: else
548: 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);
549: return "";
550: }
551:
552: char *
553: output_store_const_int (mode, operands)
554: enum machine_mode mode;
555: rtx *operands;
556: {
557: int i = INTVAL (operands[1]);
558: if (INT_FITS_16_BITS (i))
559: return "addu %0,r0,%1";
560: if (INT_FITS_16_BITS (-i))
561: {
562: operands[1] = gen_rtx (CONST_INT, VOIDmode, -i);
563: return "subu %0,r0,%1";
564: }
565: if ((i & 0xffff) == 0)
566: return "or.u %0,r0,hi16(%1)";
567: /* Could check to see if number is a contiguous field
568: of 1's. Then we could use the SET instruction. */
569: if (mode == HImode)
570: {
571: warning ("truncating constant `%d' to fit in half-word", INTVAL (operands[1]));
572: return "or %0,r0,lo16(%1)";
573: }
574: if (mode == QImode)
575: {
576: warning ("truncating constant `%d' to fit in byte");
577: operands[1] = gen_rtx (CONST_INT, VOIDmode, i & 0xff);
578: return "or %0,r0,%1";
579: }
580:
581: return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)";
582: }
583:
584: /* This routine assumes that floating point numbers are represented
585: in a manner which is consistent between host and target machines. */
586: char *
587: output_store_const_float (mode, operands)
588: enum machine_mode mode;
589: rtx *operands;
590: {
591: int i = INTVAL (operands[1]);
592: if (INT_FITS_16_BITS (i))
593: return "addu %0,r0,%1";
594: if (INT_FITS_16_BITS (-i))
595: {
596: operands[1] = gen_rtx (CONST_INT, VOIDmode, -i);
597: return "subu %0,r0,%1";
598: }
599: if ((i & 0xffff) == 0)
600: return "or.u %0,r0,hi16(%1)";
601: /* Could check to see if number is a contiguous field
602: of 1's. Then we could use the SET instruction. */
603: return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)";
604: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.