|
|
1.1 root 1: /* Subroutines for insn-output.c for Intel 860
2: Copyright (C) 1989 Free Software Foundation, Inc.
3: Derived from out-sparc.c.
4:
5: This file is part of GNU CC.
6:
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:
12: GNU CC is distributed in the hope that it will be useful,
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. */
20:
21:
22: /* Global variables for machine-dependend things. */
23:
24: /* This should go away if we pass floats to regs via
25: the stack instead of the frame, and if we learn how
26: to renumber all the registers when we don't do a save (hard!). */
27: extern int frame_pointer_needed;
28:
29: static rtx find_addr_reg ();
30:
31: /* Return non-zero only if OP is a register of mode MODE,
32: or const0_rtx. */
33: int
34: reg_or_0_operand (op, mode)
35: rtx op;
36: enum machine_mode mode;
37: {
38: return (op == const0_rtx || register_operand (op, mode)
39: || op == CONST0_RTX (mode));
40: }
41:
42: /* Return non-zero if this pattern, can be evaluated safely, even if it
43: was not asked for. */
44: int
45: safe_insn_src_p (op, mode)
46: rtx op;
47: enum machine_mode mode;
48: {
49: /* Just experimenting. */
50:
51: /* No floating point src is safe if it contains an arithmetic
52: operation, since that operation may trap. */
53: switch (GET_CODE (op))
54: {
55: case CONST_INT:
56: case LABEL_REF:
57: case SYMBOL_REF:
58: case CONST:
59: return 1;
60:
61: case REG:
62: return 1;
63:
64: case MEM:
65: return CONSTANT_ADDRESS_P (XEXP (op, 0));
66:
67: /* We never need to negate or complement constants. */
68: case NEG:
69: return (mode != SFmode && mode != DFmode);
70: case NOT:
71: case ZERO_EXTEND:
72: return 1;
73:
74: case EQ:
75: case NE:
76: case LT:
77: case GT:
78: case LE:
79: case GE:
80: case LTU:
81: case GTU:
82: case LEU:
83: case GEU:
84: case MINUS:
85: case PLUS:
86: return (mode != SFmode && mode != DFmode);
87: case AND:
88: case IOR:
89: case XOR:
90: case LSHIFT:
91: case ASHIFT:
92: case ASHIFTRT:
93: case LSHIFTRT:
94: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
95: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
96: return 0;
97: return 1;
98:
99: default:
100: return 0;
101: }
102: }
103:
104: /* Return 1 if REG is clobbered in IN.
105: Return 2 if REG is used in IN.
106: Return 3 if REG is both used and clobbered in IN.
107: Return 0 if neither. */
108:
109: static int
110: reg_clobbered_p (reg, in)
111: rtx reg;
112: rtx in;
113: {
114: register enum rtx_code code;
115:
116: if (in == 0)
117: return 0;
118:
119: code = GET_CODE (in);
120:
121: if (code == SET || code == CLOBBER)
122: {
123: rtx dest = SET_DEST (in);
124: int set = 0;
125: int used = 0;
126:
127: while (GET_CODE (dest) == STRICT_LOW_PART
128: || GET_CODE (dest) == SUBREG
129: || GET_CODE (dest) == SIGN_EXTRACT
130: || GET_CODE (dest) == ZERO_EXTRACT)
131: dest = XEXP (dest, 0);
132:
133: if (dest == reg)
134: set = 1;
135: else if (GET_CODE (dest) == REG
136: && refers_to_regno_p (REGNO (reg),
137: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
138: SET_DEST (in), 0))
139: {
140: set = 1;
141: /* Anything that sets just part of the register
142: is considered using as well as setting it.
143: But note that a straight SUBREG of a single-word value
144: clobbers the entire value. */
145: if (dest != SET_DEST (in)
146: && ! (GET_CODE (SET_DEST (in)) == SUBREG
147: || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))
148: used = 1;
149: }
150:
151: if (code == SET)
152: {
153: if (set)
154: used = refers_to_regno_p (REGNO (reg),
155: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
156: SET_SRC (in), 0);
157: else
158: used = refers_to_regno_p (REGNO (reg),
159: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
160: in, 0);
161: }
162:
163: return set + used * 2;
164: }
165:
166: if (refers_to_regno_p (REGNO (reg),
167: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
168: in, 0))
169: return 2;
170: return 0;
171: }
172:
173: /* Return non-zero if OP can be written to without screwing up
174: GCC's model of what's going on. It is assumed that this operand
175: appears in the dest position of a SET insn in a conditional
176: branch's delay slot. AFTER is the label to start looking from. */
177: int
178: operand_clobbered_before_used_after (op, after)
179: rtx op;
180: rtx after;
181: {
182: extern char call_used_regs[];
183:
184: /* Just experimenting. */
185: if (GET_CODE (op) == CC0)
186: return 1;
187: if (GET_CODE (op) == REG)
188: {
189: rtx insn;
190:
191: if (op == stack_pointer_rtx)
192: return 0;
193:
194: /* Scan forward from the label, to see if the value of OP
195: is clobbered before the first use. */
196:
197: for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
198: {
199: if (GET_CODE (insn) == NOTE)
200: continue;
201: if (GET_CODE (insn) == INSN
202: || GET_CODE (insn) == JUMP_INSN
203: || GET_CODE (insn) == CALL_INSN)
204: {
205: switch (reg_clobbered_p (op, PATTERN (insn)))
206: {
207: default:
208: return 0;
209: case 1:
210: return 1;
211: case 0:
212: break;
213: }
214: }
215: /* If we reach another label without clobbering OP,
216: then we cannot safely write it here. */
217: else if (GET_CODE (insn) == CODE_LABEL)
218: return 0;
219: if (GET_CODE (insn) == JUMP_INSN)
220: {
221: if (condjump_p (insn))
222: return 0;
223: /* This is a jump insn which has already
224: been mangled. We can't tell what it does. */
225: if (GET_CODE (PATTERN (insn)) == PARALLEL)
226: return 0;
227: if (! JUMP_LABEL (insn))
228: return 0;
229: /* Keep following jumps. */
230: insn = JUMP_LABEL (insn);
231: }
232: }
233: return 1;
234: }
235:
236: /* In both of these cases, the first insn executed
237: for this op will be a orh whatever%h,r0,r31,
238: which is tolerable. */
239: if (GET_CODE (op) == MEM)
240: return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
241:
242: return 0;
243: }
244:
245: /* Return non-zero if this pattern, as a source to a "SET",
246: is known to yield an instruction of unit size. */
247: int
248: single_insn_src_p (op, mode)
249: rtx op;
250: enum machine_mode mode;
251: {
252: switch (GET_CODE (op))
253: {
254: case CONST_INT:
255: /* This is not always a single insn src, technically,
256: but output_delayed_branch knows how to deal with it. */
257: return 1;
258:
259: case SYMBOL_REF:
260: case CONST:
261: /* This is not a single insn src, technically,
262: but output_delayed_branch knows how to deal with it. */
263: return 1;
264:
265: case REG:
266: return 1;
267:
268: case MEM:
269: return 1;
270:
271: /* We never need to negate or complement constants. */
272: case NEG:
273: return (mode != DFmode);
274: case NOT:
275: case ZERO_EXTEND:
276: return 1;
277:
278: case EQ:
279: case NE:
280: case LT:
281: case GT:
282: case LE:
283: case GE:
284: case LTU:
285: case GTU:
286: case LEU:
287: case GEU:
288: case MINUS:
289: case PLUS:
290: /* Not doing floating point, since they probably
291: take longer than the branch slot they might fill. */
292: return (mode != SFmode && mode != DFmode);
293: case AND:
294: case IOR:
295: case XOR:
296: case LSHIFT:
297: case ASHIFT:
298: case ASHIFTRT:
299: case LSHIFTRT:
300: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
301: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
302: return 0;
303: return 1;
304:
305: case SUBREG:
306: if (SUBREG_WORD (op) != 0)
307: return 0;
308: return single_insn_src_p (SUBREG_REG (op), mode);
309:
310: /* Not doing floating point, since they probably
311: take longer than the branch slot they might fill. */
312: case FLOAT_EXTEND:
313: case FLOAT_TRUNCATE:
314: case FLOAT:
315: case FIX:
316: case UNSIGNED_FLOAT:
317: case UNSIGNED_FIX:
318: return 0;
319:
320: default:
321: return 0;
322: }
323: }
324:
325: /* Nonzero only if this *really* is a single insn operand. */
326: int
327: strict_single_insn_op_p (op, mode)
328: rtx op;
329: enum machine_mode mode;
330: {
331: if (mode == VOIDmode)
332: mode = GET_MODE (op);
333:
334: switch (GET_CODE (op))
335: {
336: case CC0:
337: return 1;
338:
339: case CONST_INT:
340: if (SMALL_INT (op))
341: return 1;
342: /* We can put this set insn into delay slot, because this is one
343: insn; 'sethi'. */
344: if ((INTVAL (op) & 0x3ff) == 0)
345: return 1;
346: return 0;
347:
348: case SYMBOL_REF:
349: return 0;
350:
351: case REG:
352: #if 0
353: /* This loses when moving an freg to a general reg. */
354: return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
355: #endif
356: return (mode != DFmode && mode != DImode);
357:
358: case MEM:
359: if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
360: return (mode != DFmode && mode != DImode);
361: return 0;
362:
363: /* We never need to negate or complement constants. */
364: case NEG:
365: return (mode != DFmode);
366: case NOT:
367: case ZERO_EXTEND:
368: return 1;
369:
370: case EQ:
371: case NE:
372: case LT:
373: case GT:
374: case LE:
375: case GE:
376: case LTU:
377: case GTU:
378: case LEU:
379: case GEU:
380: case MINUS:
381: case PLUS:
382: case AND:
383: case IOR:
384: case XOR:
385: case LSHIFT:
386: case ASHIFT:
387: case ASHIFTRT:
388: case LSHIFTRT:
389: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
390: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
391: return 0;
392: return 1;
393:
394: case SUBREG:
395: if (SUBREG_WORD (op) != 0)
396: return 0;
397: return strict_single_insn_op_p (SUBREG_REG (op), mode);
398:
399: case SIGN_EXTEND:
400: if (GET_CODE (XEXP (op, 0)) == MEM
401: && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
402: return 1;
403: return 0;
404:
405: /* Not doing floating point, since they probably
406: take longer than the branch slot they might fill. */
407: case FLOAT_EXTEND:
408: case FLOAT_TRUNCATE:
409: case FLOAT:
410: case FIX:
411: case UNSIGNED_FLOAT:
412: case UNSIGNED_FIX:
413: return 0;
414:
415: default:
416: return 0;
417: }
418: }
419:
420: /* Return truth value of whether OP is a relational operator. */
421: int
422: relop (op, mode)
423: rtx op;
424: enum machine_mode mode;
425: {
426: switch (GET_CODE (op))
427: {
428: case EQ:
429: case NE:
430: case GT:
431: case GE:
432: case LT:
433: case LE:
434: case GTU:
435: case GEU:
436: case LTU:
437: case LEU:
438: return 1;
439: }
440: return 0;
441: }
442:
443: /* Return truth value of whether OP can be used as an operands in a three
444: address add/subtract insn (such as add %o1,7,%l2) of mode MODE. */
445:
446: int
447: arith_operand (op, mode)
448: rtx op;
449: enum machine_mode mode;
450: {
451: return (register_operand (op, mode)
452: || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
453: }
454:
455: /* Return 1 if OP is a valid first operand for a logical insn of mode MODE. */
456:
457: int
458: logic_operand (op, mode)
459: rtx op;
460: enum machine_mode mode;
461: {
462: return (register_operand (op, mode)
463: || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
464: }
465:
466: /* Return 1 if OP is a valid first operand for either a logical insn
467: or an add insn of mode MODE. */
468:
469: int
470: compare_operand (op, mode)
471: rtx op;
472: enum machine_mode mode;
473: {
474: return (register_operand (op, mode)
475: || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
476: }
477:
478: /* Return truth value of whether OP can be used as an operand
479: of a bte insn. */
480:
481: int
482: bte_operand (op, mode)
483: rtx op;
484: enum machine_mode mode;
485: {
486: return (register_operand (op, mode)
487: || (GET_CODE (op) == CONST_INT
488: && (unsigned) INTVAL (op) < 0x20));
489: }
490:
491: /* Return 1 if OP is an indexed memory reference of mode MODE. */
492:
493: int
494: indexed_operand (op, mode)
495: rtx op;
496: enum machine_mode mode;
497: {
498: return (GET_CODE (op) == MEM && GET_MODE (op) == mode
499: && GET_CODE (XEXP (op, 0)) == PLUS
500: && GET_MODE (XEXP (op, 0)) == SImode
501: && register_operand (XEXP (XEXP (op, 0), 0), SImode)
502: && register_operand (XEXP (XEXP (op, 0), 1), SImode));
503: }
504:
505: /* Return 1 if OP is a suitable source operand for a load insn
506: with mode MODE. */
507:
508: int
509: load_operand (op, mode)
510: rtx op;
511: enum machine_mode mode;
512: {
513: return (memory_operand (op, mode) || indexed_operand (op, mode));
514: }
515:
516: /* Return truth value of whether OP is a integer which fits the
517: range constraining immediate operands in add/subtract insns. */
518:
519: int
520: small_int (op, mode)
521: rtx op;
522: enum machine_mode mode;
523: {
524: return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
525: }
526:
527: /* Return truth value of whether OP is a integer which fits the
528: range constraining immediate operands in logic insns. */
529:
530: int
531: logic_int (op, mode)
532: rtx op;
533: enum machine_mode mode;
534: {
535: return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
536: }
537:
538: /* Return the best assembler insn template
539: for moving operands[1] into operands[0] as a fullword. */
540:
541: static char *
542: singlemove_string (operands)
543: rtx *operands;
544: {
545: if (GET_CODE (operands[0]) == MEM)
546: {
547: if (GET_CODE (operands[1]) != MEM)
548: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
549: {
550: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
551: && (cc_prev_status.flags & CC_HI_R31_ADJ)
552: && cc_prev_status.mdep == XEXP (operands[0], 0)))
553: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
554: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
555: cc_status.mdep = XEXP (operands[0], 0);
556: return "st.l %r1,l%%%m0(r31)";
557: }
558: else
559: return "st.l %r1,%0";
560: else
561: abort ();
562: #if 0
563: {
564: rtx xoperands[2];
565:
566: cc_status.flags &= ~CC_F0_IS_0;
567: xoperands[0] = gen_rtx (REG, SFmode, 32);
568: xoperands[1] = operands[1];
569: output_asm_insn (singlemove_string (xoperands), xoperands);
570: xoperands[1] = xoperands[0];
571: xoperands[0] = operands[0];
572: output_asm_insn (singlemove_string (xoperands), xoperands);
573: return "";
574: }
575: #endif
576: }
577: if (GET_CODE (operands[1]) == MEM)
578: {
579: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
580: {
581: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
582: && (cc_prev_status.flags & CC_HI_R31_ADJ)
583: && cc_prev_status.mdep == XEXP (operands[1], 0)))
584: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
585: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
586: cc_status.mdep = XEXP (operands[1], 0);
587: return "ld.l l%%%m1(r31),%0";
588: }
589: return "ld.l %1,%0";
590: }
591: return "mov %1,%0";
592: }
593:
594: /* Output assembler code to perform a doubleword move insn
595: with operands OPERANDS. */
596:
597: char *
598: output_move_double (operands)
599: rtx *operands;
600: {
601: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
602: rtx latehalf[2];
603: rtx addreg0 = 0, addreg1 = 0;
604:
605: /* First classify both operands. */
606:
607: if (REG_P (operands[0]))
608: optype0 = REGOP;
609: else if (offsettable_memref_p (operands[0]))
610: optype0 = OFFSOP;
611: else if (GET_CODE (operands[0]) == MEM)
612: optype0 = MEMOP;
613: else
614: optype0 = RNDOP;
615:
616: if (REG_P (operands[1]))
617: optype1 = REGOP;
618: else if (CONSTANT_P (operands[1])
619: || GET_CODE (operands[1]) == CONST_DOUBLE)
620: optype1 = CNSTOP;
621: else if (offsettable_memref_p (operands[1]))
622: optype1 = OFFSOP;
623: else if (GET_CODE (operands[1]) == MEM)
624: optype1 = MEMOP;
625: else
626: optype1 = RNDOP;
627:
628: /* Check for the cases that the operand constraints are not
629: supposed to allow to happen. Abort if we get one,
630: because generating code for these cases is painful. */
631:
632: if (optype0 == RNDOP || optype1 == RNDOP)
633: abort ();
634:
635: /* If an operand is an unoffsettable memory ref, find a register
636: we can increment temporarily to make it refer to the second word. */
637:
638: if (optype0 == MEMOP)
639: addreg0 = find_addr_reg (XEXP (operands[0], 0));
640:
641: if (optype1 == MEMOP)
642: addreg1 = find_addr_reg (XEXP (operands[1], 0));
643:
644: /* ??? Perhaps in some cases move double words
645: if there is a spare pair of floating regs. */
646:
647: /* Ok, we can do one word at a time.
648: Normally we do the low-numbered word first,
649: but if either operand is autodecrementing then we
650: do the high-numbered word first.
651:
652: In either case, set up in LATEHALF the operands to use
653: for the high-numbered word and in some cases alter the
654: operands in OPERANDS to be suitable for the low-numbered word. */
655:
656: if (optype0 == REGOP)
657: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
658: else if (optype0 == OFFSOP)
659: latehalf[0] = adj_offsettable_operand (operands[0], 4);
660: else
661: latehalf[0] = operands[0];
662:
663: if (optype1 == REGOP)
664: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
665: else if (optype1 == OFFSOP)
666: latehalf[1] = adj_offsettable_operand (operands[1], 4);
667: else if (optype1 == CNSTOP)
668: {
669: if (CONSTANT_P (operands[1]))
670: latehalf[1] = const0_rtx;
671: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
672: {
673: latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
674: CONST_DOUBLE_HIGH (operands[1]));
675: operands[1] = gen_rtx (CONST_INT, VOIDmode,
676: CONST_DOUBLE_LOW (operands[1]));
677: }
678: }
679: else
680: latehalf[1] = operands[1];
681:
682: /* If the first move would clobber the source of the second one,
683: do them in the other order.
684:
685: RMS says "This happens only for registers;
686: such overlap can't happen in memory unless the user explicitly
687: sets it up, and that is an undefined circumstance."
688:
689: but it happens on the sparc when loading parameter registers,
690: so I am going to define that circumstance, and make it work
691: as expected. */
692:
693: if (optype0 == REGOP && optype1 == REGOP
694: && REGNO (operands[0]) == REGNO (latehalf[1]))
695: {
696: /* Make any unoffsettable addresses point at high-numbered word. */
697: if (addreg0)
698: output_asm_insn ("adds 0x4,%0,%0", &addreg0);
699: if (addreg1)
700: output_asm_insn ("adds 0x4,%0,%0", &addreg1);
701:
702: /* Do that word. */
703: output_asm_insn (singlemove_string (latehalf), latehalf);
704:
705: /* Undo the adds we just did. */
706: if (addreg0)
707: output_asm_insn ("adds -0x4,%0,%0", &addreg0);
708: if (addreg1)
709: output_asm_insn ("adds -0x4,%0,%0", &addreg1);
710:
711: /* Do low-numbered word. */
712: return singlemove_string (operands);
713: }
714: else if (optype0 == REGOP && optype1 != REGOP
715: && reg_overlap_mentioned_p (operands[0], operands[1]))
716: {
717: /* Do the late half first. */
718: output_asm_insn (singlemove_string (latehalf), latehalf);
719: /* Then clobber. */
720: return singlemove_string (operands);
721: }
722:
723: /* Normal case: do the two words, low-numbered first. */
724:
725: output_asm_insn (singlemove_string (operands), operands);
726:
727: /* Make any unoffsettable addresses point at high-numbered word. */
728: if (addreg0)
729: output_asm_insn ("adds 0x4,%0,%0", &addreg0);
730: if (addreg1)
731: output_asm_insn ("adds 0x4,%0,%0", &addreg1);
732:
733: /* Do that word. */
734: output_asm_insn (singlemove_string (latehalf), latehalf);
735:
736: /* Undo the adds we just did. */
737: if (addreg0)
738: output_asm_insn ("adds -0x4,%0,%0", &addreg0);
739: if (addreg1)
740: output_asm_insn ("adds -0x4,%0,%0", &addreg1);
741:
742: return "";
743: }
744:
745: static char *
746: output_fp_move_double (operands)
747: rtx *operands;
748: {
749: if (FP_REG_P (operands[0]))
750: {
751: if (FP_REG_P (operands[1]))
752: return "fmov.dd %1,%0";
753: if (GET_CODE (operands[1]) == REG)
754: {
755: output_asm_insn ("ixfr %1,%0", operands);
756: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
757: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
758: return "ixfr %1,%0";
759: }
760: if (operands[1] == dconst0_rtx)
761: return "fmov.dd f0,%0";
762: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
763: {
764: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
765: && (cc_prev_status.flags & CC_HI_R31_ADJ)
766: && cc_prev_status.mdep == XEXP (operands[1], 0)))
767: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
768: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
769: cc_status.mdep = XEXP (operands[1], 0);
770: return "fld.d l%%%m1(r31),%0";
771: }
772: return "fld.d %1,%0";
773: }
774: else if (FP_REG_P (operands[1]))
775: {
776: if (GET_CODE (operands[0]) == REG)
777: {
778: output_asm_insn ("fxfr %1,%0", operands);
779: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
780: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
781: return "fxfr %1,%0";
782: }
783: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
784: {
785: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
786: && (cc_prev_status.flags & CC_HI_R31_ADJ)
787: && cc_prev_status.mdep == XEXP (operands[0], 0)))
788: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
789: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
790: cc_status.mdep = XEXP (operands[0], 0);
791: return "fst.d %1,l%%%m0(r31)";
792: }
793: return "fst.d %1,%0";
794: }
795: else abort ();
796: }
797:
798: /* Return a REG that occurs in ADDR with coefficient 1.
799: ADDR can be effectively incremented by incrementing REG. */
800:
801: static rtx
802: find_addr_reg (addr)
803: rtx addr;
804: {
805: while (GET_CODE (addr) == PLUS)
806: {
807: if (GET_CODE (XEXP (addr, 0)) == REG)
808: addr = XEXP (addr, 0);
809: else if (GET_CODE (XEXP (addr, 1)) == REG)
810: addr = XEXP (addr, 1);
811: else if (CONSTANT_P (XEXP (addr, 0)))
812: addr = XEXP (addr, 1);
813: else if (CONSTANT_P (XEXP (addr, 1)))
814: addr = XEXP (addr, 0);
815: else
816: abort ();
817: }
818: if (GET_CODE (addr) == REG)
819: return addr;
820: abort ();
821: }
822:
823: /* Return a template for a load instruction with mode MODE and
824: arguments from the string ARGS.
825:
826: This string is in static storage. */
827:
828: static char *
829: load_opcode (mode, args, reg)
830: enum machine_mode mode;
831: char *args;
832: rtx reg;
833: {
834: static char buf[30];
835: char *opcode;
836:
837: switch (mode)
838: {
839: case QImode:
840: opcode = "ld.b";
841: break;
842:
843: case HImode:
844: opcode = "ld.s";
845: break;
846:
847: case SImode:
848: case SFmode:
849: if (FP_REG_P (reg))
850: opcode = "fld.l";
851: else
852: opcode = "ld.l";
853: break;
854:
1.1.1.2 ! root 855: case DImode:
! 856: if (!FP_REG_P (reg))
! 857: abort ();
1.1 root 858: case DFmode:
859: opcode = "fld.d";
860: break;
861:
862: default:
863: abort ();
864: }
865:
866: sprintf (buf, "%s %s", opcode, args);
867: return buf;
868: }
869:
870: /* Return a template for a store instruction with mode MODE and
871: arguments from the string ARGS.
872:
873: This string is in static storage. */
874:
875: static char *
876: store_opcode (mode, args, reg)
877: enum machine_mode mode;
878: char *args;
879: rtx reg;
880: {
881: static char buf[30];
882: char *opcode;
883:
884: switch (mode)
885: {
886: case QImode:
887: opcode = "st.b";
888: break;
889:
890: case HImode:
891: opcode = "st.s";
892: break;
893:
894: case SImode:
895: case SFmode:
896: if (FP_REG_P (reg))
897: opcode = "fst.l";
898: else
899: opcode = "st.l";
900: break;
901:
1.1.1.2 ! root 902: case DImode:
! 903: if (!FP_REG_P (reg))
! 904: abort ();
1.1 root 905: case DFmode:
906: opcode = "fst.d";
907: break;
908:
909: default:
910: abort ();
911: }
912:
913: sprintf (buf, "%s %s", opcode, args);
914: return buf;
915: }
916:
917: /* Output a store-in-memory whose operands are OPERANDS[0,1].
918: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
919:
920: This function returns a template for an insn.
921: This is in static storage.
922:
923: It may also output some insns directly.
924: It may alter the values of operands[0] and operands[1]. */
925:
926: char *
927: output_store (operands)
928: rtx *operands;
929: {
930: enum machine_mode mode = GET_MODE (operands[0]);
931: rtx address = XEXP (operands[0], 0);
932: char *string;
933:
934: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
935: cc_status.mdep = address;
936:
937: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
938: && (cc_prev_status.flags & CC_HI_R31_ADJ)
939: && address == cc_prev_status.mdep))
940: {
941: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
942: cc_prev_status.mdep = address;
943: }
944:
945: /* Store zero in two parts when appropriate. */
946: if (mode == DFmode && operands[1] == dconst0_rtx)
947: return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);
948:
949: /* Code below isn't smart enough to move a doubleword in two parts,
950: so use output_move_double to do that in the cases that require it. */
951: if ((mode == DImode || mode == DFmode)
952: && ! FP_REG_P (operands[1]))
953: return output_move_double (operands);
954:
955: return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);
956: }
957:
958: /* Output a load-from-memory whose operands are OPERANDS[0,1].
959: OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
960:
961: This function returns a template for an insn.
962: This is in static storage.
963:
964: It may also output some insns directly.
965: It may alter the values of operands[0] and operands[1]. */
966:
967: char *
968: output_load (operands)
969: rtx *operands;
970: {
971: enum machine_mode mode = GET_MODE (operands[0]);
972: rtx address = XEXP (operands[1], 0);
973:
974: /* We don't bother trying to see if we know %hi(address).
975: This is because we are doing a load, and if we know the
976: %hi value, we probably also know that value in memory. */
977: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
978: cc_status.mdep = address;
979:
980: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
981: && (cc_prev_status.flags & CC_HI_R31_ADJ)
982: && address == cc_prev_status.mdep
983: && cc_prev_status.mdep == cc_status.mdep))
984: {
985: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
986: cc_prev_status.mdep = address;
987: }
988:
989: /* Code below isn't smart enough to move a doubleword in two parts,
990: so use output_move_double to do that in the cases that require it. */
991: if ((mode == DImode || mode == DFmode)
992: && ! FP_REG_P (operands[0]))
993: return output_move_double (operands);
994:
995: return load_opcode (mode, "l%%%m1(r31),%0", operands[0]);
996: }
997:
998: /* Load the address specified by OPERANDS[3] into the register
999: specified by OPERANDS[0].
1000:
1001: OPERANDS[3] may be the result of a sum, hence it could either be:
1002:
1003: (1) CONST
1004: (2) REG
1005: (2) REG + CONST_INT
1006: (3) REG + REG + CONST_INT
1007: (4) REG + REG (special case of 3).
1008:
1009: Note that (3) is not a legitimate address.
1010: All cases are handled here. */
1011:
1012: void
1013: output_load_address (operands)
1014: rtx *operands;
1015: {
1016: rtx base, offset;
1017:
1018: if (CONSTANT_P (operands[3]))
1019: {
1020: output_asm_insn ("mov %3,%0", operands);
1021: return;
1022: }
1023:
1024: if (REG_P (operands[3]))
1025: {
1026: if (REGNO (operands[0]) != REGNO (operands[3]))
1027: output_asm_insn ("mov %3,%0", operands);
1028: return;
1029: }
1030:
1031: if (GET_CODE (operands[3]) != PLUS)
1032: abort ();
1033:
1034: base = XEXP (operands[3], 0);
1035: offset = XEXP (operands[3], 1);
1036:
1037: if (GET_CODE (base) == CONST_INT)
1038: {
1039: rtx tmp = base;
1040: base = offset;
1041: offset = tmp;
1042: }
1043:
1044: if (GET_CODE (offset) != CONST_INT)
1045: {
1046: /* Operand is (PLUS (REG) (REG)). */
1047: base = operands[3];
1048: offset = const0_rtx;
1049: }
1050:
1051: if (REG_P (base))
1052: {
1053: operands[6] = base;
1054: operands[7] = offset;
1055: if (SMALL_INT (offset))
1056: output_asm_insn ("adds %7,%6,%0", operands);
1057: else
1058: output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
1059: }
1060: else if (GET_CODE (base) == PLUS)
1061: {
1062: operands[6] = XEXP (base, 0);
1063: operands[7] = XEXP (base, 1);
1064: operands[8] = offset;
1065:
1066: if (SMALL_INT (offset))
1067: output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
1068: else
1069: output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
1070: }
1071: else
1072: abort ();
1073: }
1074:
1075: /* Output code to place a size count SIZE in register REG.
1076: Because block moves are pipelined, we don't include the
1077: first element in the transfer of SIZE to REG.
1078: For this, we subtract ALIGN. (Actually, I think it is not
1079: right to subtract on this machine, so right now we don't.) */
1080:
1081: static void
1082: output_size_for_block_move (size, reg, align)
1083: rtx size, reg, align;
1084: {
1085: rtx xoperands[3];
1086:
1087: xoperands[0] = reg;
1088: xoperands[1] = size;
1089: xoperands[2] = align;
1090:
1091: #if 1
1092: cc_status.flags &= ~ CC_KNOW_HI_R31;
1093: output_asm_insn ("mov %1,%0", xoperands);
1094: #else
1095: if (GET_CODE (size) == REG)
1096: output_asm_insn ("sub %2,%1,%0", xoperands);
1097: else
1098: {
1099: xoperands[1]
1100: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
1101: cc_status.flags &= ~ CC_KNOW_HI_R31;
1102: output_asm_insn ("mov %1,%0", xoperands);
1103: }
1104: #endif
1105: }
1106:
1107: /* Emit code to perform a block move.
1108:
1109: OPERANDS[0] is the destination.
1110: OPERANDS[1] is the source.
1111: OPERANDS[2] is the size.
1112: OPERANDS[3] is the known safe alignment.
1113: OPERANDS[4..6] are pseudos we can safely clobber as temps. */
1114:
1115: char *
1116: output_block_move (operands)
1117: rtx *operands;
1118: {
1119: /* A vector for our computed operands. Note that load_output_address
1120: makes use of (and can clobber) up to the 8th element of this vector. */
1121: rtx xoperands[10];
1122: rtx zoperands[10];
1123: static int movstrsi_label = 0;
1124: int i, j;
1125: rtx temp1 = operands[4];
1126: rtx alignrtx = operands[3];
1127: int align = INTVAL (alignrtx);
1128:
1129: xoperands[0] = operands[0];
1130: xoperands[1] = operands[1];
1131: xoperands[2] = temp1;
1132:
1133: /* We can't move more than four bytes at a time
1134: because we have only one register to move them through. */
1135: if (align > 4)
1136: {
1137: align = 4;
1138: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
1139: }
1140:
1141: /* Since we clobber untold things, nix the condition codes. */
1142: CC_STATUS_INIT;
1143:
1144: /* Recognize special cases of block moves. These occur
1145: when GNU C++ is forced to treat something as BLKmode
1146: to keep it in memory, when its mode could be represented
1147: with something smaller.
1148:
1149: We cannot do this for global variables, since we don't know
1150: what pages they don't cross. Sigh. */
1151: if (GET_CODE (operands[2]) == CONST_INT
1152: && INTVAL (operands[2]) <= 16
1153: && ! CONSTANT_ADDRESS_P (operands[0])
1154: && ! CONSTANT_ADDRESS_P (operands[1]))
1155: {
1156: int size = INTVAL (operands[2]);
1157: rtx op0 = xoperands[0];
1158: rtx op1 = xoperands[1];
1159:
1160: cc_status.flags &= ~CC_KNOW_HI_R31;
1161: if (align == 1)
1162: {
1163: if (memory_address_p (QImode, plus_constant (op0, size))
1164: && memory_address_p (QImode, plus_constant (op1, size)))
1165: {
1166: for (i = size-1; i >= 0; i--)
1167: {
1168: xoperands[0] = plus_constant (op0, i);
1169: xoperands[1] = plus_constant (op1, i);
1170: output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
1171: xoperands);
1172: }
1173: return "";
1174: }
1175: }
1176: else if (align == 2)
1177: {
1178: if (memory_address_p (HImode, plus_constant (op0, size))
1179: && memory_address_p (HImode, plus_constant (op1, size)))
1180: {
1181: for (i = (size>>1)-1; i >= 0; i--)
1182: {
1183: xoperands[0] = plus_constant (op0, i * 2);
1184: xoperands[1] = plus_constant (op1, i * 2);
1185: output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
1186: xoperands);
1187: }
1188: return "";
1189: }
1190: }
1191: else
1192: {
1193: if (memory_address_p (SImode, plus_constant (op0, size))
1194: && memory_address_p (SImode, plus_constant (op1, size)))
1195: {
1196: for (i = (size>>2)-1; i >= 0; i--)
1197: {
1198: xoperands[0] = plus_constant (op0, i * 4);
1199: xoperands[1] = plus_constant (op1, i * 4);
1200: output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
1201: xoperands);
1202: }
1203: return "";
1204: }
1205: }
1206: }
1207:
1208: /* This is the size of the transfer.
1209: Either use the register which already contains the size,
1210: or use a free register (used by no operands). */
1211: output_size_for_block_move (operands[2], operands[4], alignrtx);
1212:
1213: #if 0
1214: /* Also emit code to decrement the size value by ALIGN. */
1215: zoperands[0] = operands[0];
1216: zoperands[3] = plus_constant (operands[0], align);
1217: output_load_address (zoperands);
1218: #endif
1219:
1220: /* Generate number for unique label. */
1221:
1222: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1223:
1224: /* Copy the increment (negative) to a register for bla insn. */
1225:
1226: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
1227: xoperands[5] = operands[5];
1228: output_asm_insn ("mov %4,%5", xoperands);
1229:
1230: xoperands[6] = operands[6];
1231: output_asm_insn ("adds %0,%2,%6", xoperands);
1232:
1233: /* Now the actual loop.
1234: In xoperands, elements 1 and 0 are the input and output vectors.
1235: Element 2 is the loop index. Element 5 is the increment. */
1236:
1237: if (align == 1)
1238: {
1239: output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
1240: output_asm_insn ("ld.b %1(%2),r31", xoperands);
1241: output_asm_insn ("adds %5,%6,%6", xoperands);
1242: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1243: output_asm_insn ("st.b r31,0(%6)", xoperands);
1244: }
1245: if (align == 2)
1246: {
1247: output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
1248: output_asm_insn ("ld.s %1(%2),r31", xoperands);
1249: output_asm_insn ("adds %5,%6,%6", xoperands);
1250: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1251: output_asm_insn ("st.s r31,0(%6)", xoperands);
1252: }
1253: if (align == 4)
1254: {
1255: output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
1256: output_asm_insn ("ld.l %1(%2),r31", xoperands);
1257: output_asm_insn ("adds %5,%6,%6", xoperands);
1258: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1259: output_asm_insn ("st.l r31,0(%6)", xoperands);
1260: }
1261:
1262: return "";
1263: }
1264:
1265: /* Output a delayed branch insn with the delay insn in its
1266: branch slot. The delayed branch insn template is in TEMPLATE,
1267: with operands OPERANDS. The insn in its delay slot is INSN.
1268:
1269: As a special case, since we know that all memory transfers are via
1270: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
1271: reference around the branch as
1272:
1273: orh ha%x,r0,r31
1274: b ...
1275: ld/st l%x(r31),...
1276:
1277: As another special case, we handle loading (SYMBOL_REF ...) and
1278: other large constants around branches as well:
1279:
1280: orh h%x,r0,%0
1281: b ...
1282: or l%x,%0,%1
1283:
1284: */
1285:
1286: char *
1287: output_delayed_branch (template, operands, insn)
1288: char *template;
1289: rtx *operands;
1290: rtx insn;
1291: {
1292: extern rtx recog_operand[];
1293: rtx src = XVECEXP (PATTERN (insn), 0, 1);
1294: rtx dest = XVECEXP (PATTERN (insn), 0, 0);
1295:
1296: if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
1297: || (GET_CODE (src) == CONST_INT
1298: && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0)))
1299: {
1300: rtx xoperands[2];
1301: xoperands[0] = dest;
1302: xoperands[1] = src;
1303:
1304: /* Output the `orh' insn. */
1305: output_asm_insn ("orh h%%%1,r0,%0", xoperands);
1306:
1307: /* Output the branch instruction next. */
1308: output_asm_insn (template, operands);
1309:
1310: /* Now output the `or' insn. */
1311: output_asm_insn ("or l%%%1,%0,%0", xoperands);
1312: }
1313: else if ((GET_CODE (src) == MEM
1314: && CONSTANT_ADDRESS_P (XEXP (src, 0)))
1315: || (GET_CODE (dest) == MEM
1316: && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
1317: {
1318: rtx xoperands[2];
1319: char *split_template;
1320: xoperands[0] = dest;
1321: xoperands[1] = src;
1322:
1323: /* Output the `orh' insn. */
1324: if (GET_CODE (src) == MEM)
1325: {
1326: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1327: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1328: && cc_prev_status.mdep == XEXP (operands[1], 0)))
1329: output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
1330: split_template = load_opcode (GET_MODE (dest),
1331: "l%%%m1(r31),%0", src);
1332: }
1333: else
1334: {
1335: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1336: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1337: && cc_prev_status.mdep == XEXP (operands[0], 0)))
1338: output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
1339: split_template = store_opcode (GET_MODE (dest),
1340: "%r1,l%%%m0(r31)", src);
1341: }
1342:
1343: /* Output the branch instruction next. */
1344: output_asm_insn (template, operands);
1345:
1346: /* Now output the load or store.
1347: No need to do a CC_STATUS_INIT, because we are branching anyway. */
1348: output_asm_insn (split_template, xoperands);
1349: }
1350: else
1351: {
1352: extern char *insn_template[];
1353: extern char *(*insn_outfun[])();
1354: extern int insn_n_operands[];
1355: extern rtx alter_subreg();
1356: int insn_code_number;
1357: rtx pat = gen_rtx (SET, VOIDmode, dest, src);
1358: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
1359: int i;
1360:
1361: /* Output the branch instruction first. */
1362: output_asm_insn (template, operands);
1363:
1364: /* Now recognize the insn which we put in its delay slot.
1365: We must do this after outputing the branch insn,
1366: since operands may just be a pointer to `recog_operand'. */
1367: insn_code_number = recog (pat, delay_insn);
1368: if (insn_code_number == -1)
1369: abort ();
1370:
1371: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1372: {
1373: if (GET_CODE (recog_operand[i]) == SUBREG)
1374: recog_operand[i] = alter_subreg (recog_operand[i]);
1375: }
1376:
1377: /* Now get the template for what this insn would
1378: have been, without the branch. Its operands are
1379: exactly the same as they would be, so we don't
1380: need to do an insn_extract. */
1381: template = insn_template[insn_code_number];
1382: if (template == 0)
1383: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1384: output_asm_insn (template, recog_operand);
1385: }
1386: CC_STATUS_INIT;
1387: return "";
1388: }
1389:
1390: /* Output a newly constructed insn DELAY_INSN. */
1391: char *
1392: output_delay_insn (delay_insn)
1393: rtx delay_insn;
1394: {
1395: char *template;
1396: extern rtx recog_operand[];
1397: extern char call_used_regs[];
1398: extern char *insn_template[];
1399: extern int insn_n_operands[];
1400: extern char *(*insn_outfun[])();
1401: extern rtx alter_subreg();
1402: int insn_code_number;
1403: extern int insn_n_operands[];
1404: int i;
1405:
1406: /* Now recognize the insn which we put in its delay slot.
1407: We must do this after outputing the branch insn,
1408: since operands may just be a pointer to `recog_operand'. */
1409: insn_code_number = recog_memoized (delay_insn);
1410: if (insn_code_number == -1)
1411: abort ();
1412:
1413: /* Extract the operands of this delay insn. */
1414: INSN_CODE (delay_insn) = insn_code_number;
1415: insn_extract (delay_insn);
1416:
1417: /* It is possible that this insn has not been properly scaned by final
1418: yet. If this insn's operands don't appear in the peephole's
1419: actual operands, then they won't be fixed up by final, so we
1420: make sure they get fixed up here. -- This is a kludge. */
1421: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1422: {
1423: if (GET_CODE (recog_operand[i]) == SUBREG)
1424: recog_operand[i] = alter_subreg (recog_operand[i]);
1425: }
1426:
1427: #ifdef REGISTER_CONSTRAINTS
1428: if (! constrain_operands (insn_code_number))
1429: abort ();
1430: #endif
1431:
1432: cc_prev_status = cc_status;
1433:
1434: /* Update `cc_status' for this instruction.
1435: The instruction's output routine may change it further.
1436: If the output routine for a jump insn needs to depend
1437: on the cc status, it should look at cc_prev_status. */
1438:
1439: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
1440:
1441: /* Now get the template for what this insn would
1442: have been, without the branch. */
1443:
1444: template = insn_template[insn_code_number];
1445: if (template == 0)
1446: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1447: output_asm_insn (template, recog_operand);
1448: return "";
1449: }
1450:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.