|
|
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:
1.1.1.3 ! root 278: case PLUS:
! 279: case MINUS:
! 280: /* Detect cases that require multiple instructions. */
! 281: if (CONSTANT_P (XEXP (op, 1))
! 282: && !(GET_CODE (XEXP (op, 1)) == CONST_INT
! 283: && SMALL_INT (XEXP (op, 1))))
! 284: return 0;
1.1 root 285: case EQ:
286: case NE:
287: case LT:
288: case GT:
289: case LE:
290: case GE:
291: case LTU:
292: case GTU:
293: case LEU:
294: case GEU:
295: /* Not doing floating point, since they probably
296: take longer than the branch slot they might fill. */
297: return (mode != SFmode && mode != DFmode);
1.1.1.3 ! root 298:
1.1 root 299: case AND:
1.1.1.3 ! root 300: if (GET_CODE (XEXP (op, 1)) == NOT)
! 301: {
! 302: rtx arg = XEXP (XEXP (op, 1), 0);
! 303: if (CONSTANT_P (arg)
! 304: && !(GET_CODE (arg) == CONST_INT
! 305: && (SMALL_INT (arg)
! 306: || INTVAL (arg) & 0xffff == 0)))
! 307: return 0;
! 308: }
1.1 root 309: case IOR:
310: case XOR:
1.1.1.3 ! root 311: /* Both small and round numbers take one instruction;
! 312: others take two. */
! 313: if (CONSTANT_P (XEXP (op, 1))
! 314: && !(GET_CODE (XEXP (op, 1)) == CONST_INT
! 315: && (SMALL_INT (XEXP (op, 1))
! 316: || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
! 317: return 0;
! 318:
1.1 root 319: case LSHIFT:
320: case ASHIFT:
321: case ASHIFTRT:
322: case LSHIFTRT:
323: return 1;
324:
325: case SUBREG:
326: if (SUBREG_WORD (op) != 0)
327: return 0;
328: return single_insn_src_p (SUBREG_REG (op), mode);
329:
330: /* Not doing floating point, since they probably
331: take longer than the branch slot they might fill. */
332: case FLOAT_EXTEND:
333: case FLOAT_TRUNCATE:
334: case FLOAT:
335: case FIX:
336: case UNSIGNED_FLOAT:
337: case UNSIGNED_FIX:
338: return 0;
339:
340: default:
341: return 0;
342: }
343: }
344:
345: /* Nonzero only if this *really* is a single insn operand. */
346: int
347: strict_single_insn_op_p (op, mode)
348: rtx op;
349: enum machine_mode mode;
350: {
351: if (mode == VOIDmode)
352: mode = GET_MODE (op);
353:
354: switch (GET_CODE (op))
355: {
356: case CC0:
357: return 1;
358:
359: case CONST_INT:
360: if (SMALL_INT (op))
361: return 1;
362: /* We can put this set insn into delay slot, because this is one
363: insn; 'sethi'. */
364: if ((INTVAL (op) & 0x3ff) == 0)
365: return 1;
366: return 0;
367:
368: case SYMBOL_REF:
369: return 0;
370:
371: case REG:
372: #if 0
373: /* This loses when moving an freg to a general reg. */
374: return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
375: #endif
376: return (mode != DFmode && mode != DImode);
377:
378: case MEM:
379: if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
380: return (mode != DFmode && mode != DImode);
381: return 0;
382:
383: /* We never need to negate or complement constants. */
384: case NEG:
385: return (mode != DFmode);
386: case NOT:
387: case ZERO_EXTEND:
388: return 1;
389:
1.1.1.3 ! root 390: case PLUS:
! 391: case MINUS:
! 392: /* Detect cases that require multiple instructions. */
! 393: if (CONSTANT_P (XEXP (op, 1))
! 394: && !(GET_CODE (XEXP (op, 1)) == CONST_INT
! 395: && SMALL_INT (XEXP (op, 1))))
! 396: return 0;
1.1 root 397: case EQ:
398: case NE:
399: case LT:
400: case GT:
401: case LE:
402: case GE:
403: case LTU:
404: case GTU:
405: case LEU:
406: case GEU:
1.1.1.3 ! root 407: return 1;
! 408:
1.1 root 409: case AND:
1.1.1.3 ! root 410: if (GET_CODE (XEXP (op, 1)) == NOT)
! 411: {
! 412: rtx arg = XEXP (XEXP (op, 1), 0);
! 413: if (CONSTANT_P (arg)
! 414: && !(GET_CODE (arg) == CONST_INT
! 415: && (SMALL_INT (arg)
! 416: || INTVAL (arg) & 0xffff == 0)))
! 417: return 0;
! 418: }
1.1 root 419: case IOR:
420: case XOR:
1.1.1.3 ! root 421: /* Both small and round numbers take one instruction;
! 422: others take two. */
! 423: if (CONSTANT_P (XEXP (op, 1))
! 424: && !(GET_CODE (XEXP (op, 1)) == CONST_INT
! 425: && (SMALL_INT (XEXP (op, 1))
! 426: || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
! 427: return 0;
1.1 root 428: case LSHIFT:
429: case ASHIFT:
430: case ASHIFTRT:
431: case LSHIFTRT:
432: return 1;
433:
434: case SUBREG:
435: if (SUBREG_WORD (op) != 0)
436: return 0;
437: return strict_single_insn_op_p (SUBREG_REG (op), mode);
438:
439: case SIGN_EXTEND:
440: if (GET_CODE (XEXP (op, 0)) == MEM
441: && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
442: return 1;
443: return 0;
444:
445: /* Not doing floating point, since they probably
446: take longer than the branch slot they might fill. */
447: case FLOAT_EXTEND:
448: case FLOAT_TRUNCATE:
449: case FLOAT:
450: case FIX:
451: case UNSIGNED_FLOAT:
452: case UNSIGNED_FIX:
453: return 0;
454:
455: default:
456: return 0;
457: }
458: }
459:
460: /* Return truth value of whether OP is a relational operator. */
461: int
462: relop (op, mode)
463: rtx op;
464: enum machine_mode mode;
465: {
466: switch (GET_CODE (op))
467: {
468: case EQ:
469: case NE:
470: case GT:
471: case GE:
472: case LT:
473: case LE:
474: case GTU:
475: case GEU:
476: case LTU:
477: case LEU:
478: return 1;
479: }
480: return 0;
481: }
482:
483: /* Return truth value of whether OP can be used as an operands in a three
484: address add/subtract insn (such as add %o1,7,%l2) of mode MODE. */
485:
486: int
487: arith_operand (op, mode)
488: rtx op;
489: enum machine_mode mode;
490: {
491: return (register_operand (op, mode)
492: || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
493: }
494:
495: /* Return 1 if OP is a valid first operand for a logical insn of mode MODE. */
496:
497: int
498: logic_operand (op, mode)
499: rtx op;
500: enum machine_mode mode;
501: {
502: return (register_operand (op, mode)
503: || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
504: }
505:
506: /* Return 1 if OP is a valid first operand for either a logical insn
507: or an add insn of mode MODE. */
508:
509: int
510: compare_operand (op, mode)
511: rtx op;
512: enum machine_mode mode;
513: {
514: return (register_operand (op, mode)
515: || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
516: }
517:
518: /* Return truth value of whether OP can be used as an operand
519: of a bte insn. */
520:
521: int
522: bte_operand (op, mode)
523: rtx op;
524: enum machine_mode mode;
525: {
526: return (register_operand (op, mode)
527: || (GET_CODE (op) == CONST_INT
528: && (unsigned) INTVAL (op) < 0x20));
529: }
530:
531: /* Return 1 if OP is an indexed memory reference of mode MODE. */
532:
533: int
534: indexed_operand (op, mode)
535: rtx op;
536: enum machine_mode mode;
537: {
538: return (GET_CODE (op) == MEM && GET_MODE (op) == mode
539: && GET_CODE (XEXP (op, 0)) == PLUS
540: && GET_MODE (XEXP (op, 0)) == SImode
541: && register_operand (XEXP (XEXP (op, 0), 0), SImode)
542: && register_operand (XEXP (XEXP (op, 0), 1), SImode));
543: }
544:
545: /* Return 1 if OP is a suitable source operand for a load insn
546: with mode MODE. */
547:
548: int
549: load_operand (op, mode)
550: rtx op;
551: enum machine_mode mode;
552: {
553: return (memory_operand (op, mode) || indexed_operand (op, mode));
554: }
555:
556: /* Return truth value of whether OP is a integer which fits the
557: range constraining immediate operands in add/subtract insns. */
558:
559: int
560: small_int (op, mode)
561: rtx op;
562: enum machine_mode mode;
563: {
564: return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
565: }
566:
567: /* Return truth value of whether OP is a integer which fits the
568: range constraining immediate operands in logic insns. */
569:
570: int
571: logic_int (op, mode)
572: rtx op;
573: enum machine_mode mode;
574: {
575: return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
576: }
577:
578: /* Return the best assembler insn template
579: for moving operands[1] into operands[0] as a fullword. */
580:
581: static char *
582: singlemove_string (operands)
583: rtx *operands;
584: {
585: if (GET_CODE (operands[0]) == MEM)
586: {
587: if (GET_CODE (operands[1]) != MEM)
588: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
589: {
590: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
591: && (cc_prev_status.flags & CC_HI_R31_ADJ)
592: && cc_prev_status.mdep == XEXP (operands[0], 0)))
593: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
594: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
595: cc_status.mdep = XEXP (operands[0], 0);
596: return "st.l %r1,l%%%m0(r31)";
597: }
598: else
599: return "st.l %r1,%0";
600: else
601: abort ();
602: #if 0
603: {
604: rtx xoperands[2];
605:
606: cc_status.flags &= ~CC_F0_IS_0;
607: xoperands[0] = gen_rtx (REG, SFmode, 32);
608: xoperands[1] = operands[1];
609: output_asm_insn (singlemove_string (xoperands), xoperands);
610: xoperands[1] = xoperands[0];
611: xoperands[0] = operands[0];
612: output_asm_insn (singlemove_string (xoperands), xoperands);
613: return "";
614: }
615: #endif
616: }
617: if (GET_CODE (operands[1]) == MEM)
618: {
619: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
620: {
621: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
622: && (cc_prev_status.flags & CC_HI_R31_ADJ)
623: && cc_prev_status.mdep == XEXP (operands[1], 0)))
624: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
625: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
626: cc_status.mdep = XEXP (operands[1], 0);
627: return "ld.l l%%%m1(r31),%0";
628: }
629: return "ld.l %1,%0";
630: }
631: return "mov %1,%0";
632: }
633:
634: /* Output assembler code to perform a doubleword move insn
635: with operands OPERANDS. */
636:
637: char *
638: output_move_double (operands)
639: rtx *operands;
640: {
641: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
642: rtx latehalf[2];
643: rtx addreg0 = 0, addreg1 = 0;
644:
645: /* First classify both operands. */
646:
647: if (REG_P (operands[0]))
648: optype0 = REGOP;
649: else if (offsettable_memref_p (operands[0]))
650: optype0 = OFFSOP;
651: else if (GET_CODE (operands[0]) == MEM)
652: optype0 = MEMOP;
653: else
654: optype0 = RNDOP;
655:
656: if (REG_P (operands[1]))
657: optype1 = REGOP;
658: else if (CONSTANT_P (operands[1])
659: || GET_CODE (operands[1]) == CONST_DOUBLE)
660: optype1 = CNSTOP;
661: else if (offsettable_memref_p (operands[1]))
662: optype1 = OFFSOP;
663: else if (GET_CODE (operands[1]) == MEM)
664: optype1 = MEMOP;
665: else
666: optype1 = RNDOP;
667:
668: /* Check for the cases that the operand constraints are not
669: supposed to allow to happen. Abort if we get one,
670: because generating code for these cases is painful. */
671:
672: if (optype0 == RNDOP || optype1 == RNDOP)
673: abort ();
674:
675: /* If an operand is an unoffsettable memory ref, find a register
676: we can increment temporarily to make it refer to the second word. */
677:
678: if (optype0 == MEMOP)
679: addreg0 = find_addr_reg (XEXP (operands[0], 0));
680:
681: if (optype1 == MEMOP)
682: addreg1 = find_addr_reg (XEXP (operands[1], 0));
683:
684: /* ??? Perhaps in some cases move double words
685: if there is a spare pair of floating regs. */
686:
687: /* Ok, we can do one word at a time.
688: Normally we do the low-numbered word first,
689: but if either operand is autodecrementing then we
690: do the high-numbered word first.
691:
692: In either case, set up in LATEHALF the operands to use
693: for the high-numbered word and in some cases alter the
694: operands in OPERANDS to be suitable for the low-numbered word. */
695:
696: if (optype0 == REGOP)
697: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
698: else if (optype0 == OFFSOP)
699: latehalf[0] = adj_offsettable_operand (operands[0], 4);
700: else
701: latehalf[0] = operands[0];
702:
703: if (optype1 == REGOP)
704: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
705: else if (optype1 == OFFSOP)
706: latehalf[1] = adj_offsettable_operand (operands[1], 4);
707: else if (optype1 == CNSTOP)
708: {
709: if (CONSTANT_P (operands[1]))
710: latehalf[1] = const0_rtx;
711: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
712: {
713: latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
714: CONST_DOUBLE_HIGH (operands[1]));
715: operands[1] = gen_rtx (CONST_INT, VOIDmode,
716: CONST_DOUBLE_LOW (operands[1]));
717: }
718: }
719: else
720: latehalf[1] = operands[1];
721:
722: /* If the first move would clobber the source of the second one,
723: do them in the other order.
724:
725: RMS says "This happens only for registers;
726: such overlap can't happen in memory unless the user explicitly
727: sets it up, and that is an undefined circumstance."
728:
729: but it happens on the sparc when loading parameter registers,
730: so I am going to define that circumstance, and make it work
731: as expected. */
732:
733: if (optype0 == REGOP && optype1 == REGOP
734: && REGNO (operands[0]) == REGNO (latehalf[1]))
735: {
736: /* Make any unoffsettable addresses point at high-numbered word. */
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: /* Do that word. */
743: output_asm_insn (singlemove_string (latehalf), latehalf);
744:
745: /* Undo the adds we just did. */
746: if (addreg0)
747: output_asm_insn ("adds -0x4,%0,%0", &addreg0);
748: if (addreg1)
749: output_asm_insn ("adds -0x4,%0,%0", &addreg1);
750:
751: /* Do low-numbered word. */
752: return singlemove_string (operands);
753: }
754: else if (optype0 == REGOP && optype1 != REGOP
755: && reg_overlap_mentioned_p (operands[0], operands[1]))
756: {
757: /* Do the late half first. */
758: output_asm_insn (singlemove_string (latehalf), latehalf);
759: /* Then clobber. */
760: return singlemove_string (operands);
761: }
762:
763: /* Normal case: do the two words, low-numbered first. */
764:
765: output_asm_insn (singlemove_string (operands), operands);
766:
767: /* Make any unoffsettable addresses point at high-numbered word. */
768: if (addreg0)
769: output_asm_insn ("adds 0x4,%0,%0", &addreg0);
770: if (addreg1)
771: output_asm_insn ("adds 0x4,%0,%0", &addreg1);
772:
773: /* Do that word. */
774: output_asm_insn (singlemove_string (latehalf), latehalf);
775:
776: /* Undo the adds we just did. */
777: if (addreg0)
778: output_asm_insn ("adds -0x4,%0,%0", &addreg0);
779: if (addreg1)
780: output_asm_insn ("adds -0x4,%0,%0", &addreg1);
781:
782: return "";
783: }
784:
785: static char *
786: output_fp_move_double (operands)
787: rtx *operands;
788: {
789: if (FP_REG_P (operands[0]))
790: {
791: if (FP_REG_P (operands[1]))
792: return "fmov.dd %1,%0";
793: if (GET_CODE (operands[1]) == REG)
794: {
795: output_asm_insn ("ixfr %1,%0", operands);
796: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
797: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
798: return "ixfr %1,%0";
799: }
800: if (operands[1] == dconst0_rtx)
801: return "fmov.dd f0,%0";
802: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
803: {
804: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
805: && (cc_prev_status.flags & CC_HI_R31_ADJ)
806: && cc_prev_status.mdep == XEXP (operands[1], 0)))
807: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
808: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
809: cc_status.mdep = XEXP (operands[1], 0);
810: return "fld.d l%%%m1(r31),%0";
811: }
812: return "fld.d %1,%0";
813: }
814: else if (FP_REG_P (operands[1]))
815: {
816: if (GET_CODE (operands[0]) == REG)
817: {
818: output_asm_insn ("fxfr %1,%0", operands);
819: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
820: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
821: return "fxfr %1,%0";
822: }
823: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
824: {
825: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
826: && (cc_prev_status.flags & CC_HI_R31_ADJ)
827: && cc_prev_status.mdep == XEXP (operands[0], 0)))
828: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
829: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
830: cc_status.mdep = XEXP (operands[0], 0);
831: return "fst.d %1,l%%%m0(r31)";
832: }
833: return "fst.d %1,%0";
834: }
835: else abort ();
836: }
837:
838: /* Return a REG that occurs in ADDR with coefficient 1.
839: ADDR can be effectively incremented by incrementing REG. */
840:
841: static rtx
842: find_addr_reg (addr)
843: rtx addr;
844: {
845: while (GET_CODE (addr) == PLUS)
846: {
847: if (GET_CODE (XEXP (addr, 0)) == REG)
848: addr = XEXP (addr, 0);
849: else if (GET_CODE (XEXP (addr, 1)) == REG)
850: addr = XEXP (addr, 1);
851: else if (CONSTANT_P (XEXP (addr, 0)))
852: addr = XEXP (addr, 1);
853: else if (CONSTANT_P (XEXP (addr, 1)))
854: addr = XEXP (addr, 0);
855: else
856: abort ();
857: }
858: if (GET_CODE (addr) == REG)
859: return addr;
860: abort ();
861: }
862:
863: /* Return a template for a load instruction with mode MODE and
864: arguments from the string ARGS.
865:
866: This string is in static storage. */
867:
868: static char *
869: load_opcode (mode, args, reg)
870: enum machine_mode mode;
871: char *args;
872: rtx reg;
873: {
874: static char buf[30];
875: char *opcode;
876:
877: switch (mode)
878: {
879: case QImode:
880: opcode = "ld.b";
881: break;
882:
883: case HImode:
884: opcode = "ld.s";
885: break;
886:
887: case SImode:
888: case SFmode:
889: if (FP_REG_P (reg))
890: opcode = "fld.l";
891: else
892: opcode = "ld.l";
893: break;
894:
1.1.1.2 root 895: case DImode:
896: if (!FP_REG_P (reg))
897: abort ();
1.1 root 898: case DFmode:
899: opcode = "fld.d";
900: break;
901:
902: default:
903: abort ();
904: }
905:
906: sprintf (buf, "%s %s", opcode, args);
907: return buf;
908: }
909:
910: /* Return a template for a store instruction with mode MODE and
911: arguments from the string ARGS.
912:
913: This string is in static storage. */
914:
915: static char *
916: store_opcode (mode, args, reg)
917: enum machine_mode mode;
918: char *args;
919: rtx reg;
920: {
921: static char buf[30];
922: char *opcode;
923:
924: switch (mode)
925: {
926: case QImode:
927: opcode = "st.b";
928: break;
929:
930: case HImode:
931: opcode = "st.s";
932: break;
933:
934: case SImode:
935: case SFmode:
936: if (FP_REG_P (reg))
937: opcode = "fst.l";
938: else
939: opcode = "st.l";
940: break;
941:
1.1.1.2 root 942: case DImode:
943: if (!FP_REG_P (reg))
944: abort ();
1.1 root 945: case DFmode:
946: opcode = "fst.d";
947: break;
948:
949: default:
950: abort ();
951: }
952:
953: sprintf (buf, "%s %s", opcode, args);
954: return buf;
955: }
956:
957: /* Output a store-in-memory whose operands are OPERANDS[0,1].
958: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
959:
960: This function returns a template for an insn.
961: This is in static storage.
962:
963: It may also output some insns directly.
964: It may alter the values of operands[0] and operands[1]. */
965:
966: char *
967: output_store (operands)
968: rtx *operands;
969: {
970: enum machine_mode mode = GET_MODE (operands[0]);
971: rtx address = XEXP (operands[0], 0);
972: char *string;
973:
974: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
975: cc_status.mdep = address;
976:
977: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
978: && (cc_prev_status.flags & CC_HI_R31_ADJ)
979: && address == cc_prev_status.mdep))
980: {
981: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
982: cc_prev_status.mdep = address;
983: }
984:
985: /* Store zero in two parts when appropriate. */
986: if (mode == DFmode && operands[1] == dconst0_rtx)
987: return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);
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[1]))
993: return output_move_double (operands);
994:
995: return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);
996: }
997:
998: /* Output a load-from-memory whose operands are OPERANDS[0,1].
999: OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
1000:
1001: This function returns a template for an insn.
1002: This is in static storage.
1003:
1004: It may also output some insns directly.
1005: It may alter the values of operands[0] and operands[1]. */
1006:
1007: char *
1008: output_load (operands)
1009: rtx *operands;
1010: {
1011: enum machine_mode mode = GET_MODE (operands[0]);
1012: rtx address = XEXP (operands[1], 0);
1013:
1014: /* We don't bother trying to see if we know %hi(address).
1015: This is because we are doing a load, and if we know the
1016: %hi value, we probably also know that value in memory. */
1017: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
1018: cc_status.mdep = address;
1019:
1020: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1021: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1022: && address == cc_prev_status.mdep
1023: && cc_prev_status.mdep == cc_status.mdep))
1024: {
1025: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
1026: cc_prev_status.mdep = address;
1027: }
1028:
1029: /* Code below isn't smart enough to move a doubleword in two parts,
1030: so use output_move_double to do that in the cases that require it. */
1031: if ((mode == DImode || mode == DFmode)
1032: && ! FP_REG_P (operands[0]))
1033: return output_move_double (operands);
1034:
1035: return load_opcode (mode, "l%%%m1(r31),%0", operands[0]);
1036: }
1037:
1038: /* Load the address specified by OPERANDS[3] into the register
1039: specified by OPERANDS[0].
1040:
1041: OPERANDS[3] may be the result of a sum, hence it could either be:
1042:
1043: (1) CONST
1044: (2) REG
1045: (2) REG + CONST_INT
1046: (3) REG + REG + CONST_INT
1047: (4) REG + REG (special case of 3).
1048:
1049: Note that (3) is not a legitimate address.
1050: All cases are handled here. */
1051:
1052: void
1053: output_load_address (operands)
1054: rtx *operands;
1055: {
1056: rtx base, offset;
1057:
1058: if (CONSTANT_P (operands[3]))
1059: {
1060: output_asm_insn ("mov %3,%0", operands);
1061: return;
1062: }
1063:
1064: if (REG_P (operands[3]))
1065: {
1066: if (REGNO (operands[0]) != REGNO (operands[3]))
1067: output_asm_insn ("mov %3,%0", operands);
1068: return;
1069: }
1070:
1071: if (GET_CODE (operands[3]) != PLUS)
1072: abort ();
1073:
1074: base = XEXP (operands[3], 0);
1075: offset = XEXP (operands[3], 1);
1076:
1077: if (GET_CODE (base) == CONST_INT)
1078: {
1079: rtx tmp = base;
1080: base = offset;
1081: offset = tmp;
1082: }
1083:
1084: if (GET_CODE (offset) != CONST_INT)
1085: {
1086: /* Operand is (PLUS (REG) (REG)). */
1087: base = operands[3];
1088: offset = const0_rtx;
1089: }
1090:
1091: if (REG_P (base))
1092: {
1093: operands[6] = base;
1094: operands[7] = offset;
1095: if (SMALL_INT (offset))
1096: output_asm_insn ("adds %7,%6,%0", operands);
1097: else
1098: output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
1099: }
1100: else if (GET_CODE (base) == PLUS)
1101: {
1102: operands[6] = XEXP (base, 0);
1103: operands[7] = XEXP (base, 1);
1104: operands[8] = offset;
1105:
1106: if (SMALL_INT (offset))
1107: output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
1108: else
1109: output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
1110: }
1111: else
1112: abort ();
1113: }
1114:
1.1.1.3 ! root 1115: /* Output code to place a size count SIZE in register REG. */
1.1 root 1116:
1117: static void
1118: output_size_for_block_move (size, reg, align)
1119: rtx size, reg, align;
1120: {
1121: rtx xoperands[3];
1122:
1123: xoperands[0] = reg;
1124: xoperands[1] = size;
1125: xoperands[2] = align;
1126:
1127: #if 1
1128: cc_status.flags &= ~ CC_KNOW_HI_R31;
1129: output_asm_insn ("mov %1,%0", xoperands);
1130: #else
1131: if (GET_CODE (size) == REG)
1132: output_asm_insn ("sub %2,%1,%0", xoperands);
1133: else
1134: {
1135: xoperands[1]
1136: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
1137: cc_status.flags &= ~ CC_KNOW_HI_R31;
1138: output_asm_insn ("mov %1,%0", xoperands);
1139: }
1140: #endif
1141: }
1142:
1143: /* Emit code to perform a block move.
1144:
1145: OPERANDS[0] is the destination.
1146: OPERANDS[1] is the source.
1147: OPERANDS[2] is the size.
1148: OPERANDS[3] is the known safe alignment.
1149: OPERANDS[4..6] are pseudos we can safely clobber as temps. */
1150:
1151: char *
1152: output_block_move (operands)
1153: rtx *operands;
1154: {
1155: /* A vector for our computed operands. Note that load_output_address
1156: makes use of (and can clobber) up to the 8th element of this vector. */
1157: rtx xoperands[10];
1158: rtx zoperands[10];
1159: static int movstrsi_label = 0;
1160: int i, j;
1161: rtx temp1 = operands[4];
1162: rtx alignrtx = operands[3];
1163: int align = INTVAL (alignrtx);
1164:
1165: xoperands[0] = operands[0];
1166: xoperands[1] = operands[1];
1167: xoperands[2] = temp1;
1168:
1169: /* We can't move more than four bytes at a time
1170: because we have only one register to move them through. */
1171: if (align > 4)
1172: {
1173: align = 4;
1174: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
1175: }
1176:
1177: /* Since we clobber untold things, nix the condition codes. */
1178: CC_STATUS_INIT;
1179:
1180: /* Recognize special cases of block moves. These occur
1181: when GNU C++ is forced to treat something as BLKmode
1182: to keep it in memory, when its mode could be represented
1183: with something smaller.
1184:
1185: We cannot do this for global variables, since we don't know
1186: what pages they don't cross. Sigh. */
1187: if (GET_CODE (operands[2]) == CONST_INT
1188: && INTVAL (operands[2]) <= 16
1189: && ! CONSTANT_ADDRESS_P (operands[0])
1190: && ! CONSTANT_ADDRESS_P (operands[1]))
1191: {
1192: int size = INTVAL (operands[2]);
1193: rtx op0 = xoperands[0];
1194: rtx op1 = xoperands[1];
1195:
1196: cc_status.flags &= ~CC_KNOW_HI_R31;
1197: if (align == 1)
1198: {
1199: if (memory_address_p (QImode, plus_constant (op0, size))
1200: && memory_address_p (QImode, plus_constant (op1, size)))
1201: {
1202: for (i = size-1; i >= 0; i--)
1203: {
1204: xoperands[0] = plus_constant (op0, i);
1205: xoperands[1] = plus_constant (op1, i);
1206: output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
1207: xoperands);
1208: }
1209: return "";
1210: }
1211: }
1212: else if (align == 2)
1213: {
1214: if (memory_address_p (HImode, plus_constant (op0, size))
1215: && memory_address_p (HImode, plus_constant (op1, size)))
1216: {
1217: for (i = (size>>1)-1; i >= 0; i--)
1218: {
1219: xoperands[0] = plus_constant (op0, i * 2);
1220: xoperands[1] = plus_constant (op1, i * 2);
1221: output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
1222: xoperands);
1223: }
1224: return "";
1225: }
1226: }
1227: else
1228: {
1229: if (memory_address_p (SImode, plus_constant (op0, size))
1230: && memory_address_p (SImode, plus_constant (op1, size)))
1231: {
1232: for (i = (size>>2)-1; i >= 0; i--)
1233: {
1234: xoperands[0] = plus_constant (op0, i * 4);
1235: xoperands[1] = plus_constant (op1, i * 4);
1236: output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
1237: xoperands);
1238: }
1239: return "";
1240: }
1241: }
1242: }
1243:
1244: /* This is the size of the transfer.
1245: Either use the register which already contains the size,
1246: or use a free register (used by no operands). */
1247: output_size_for_block_move (operands[2], operands[4], alignrtx);
1248:
1249: #if 0
1250: /* Also emit code to decrement the size value by ALIGN. */
1251: zoperands[0] = operands[0];
1252: zoperands[3] = plus_constant (operands[0], align);
1253: output_load_address (zoperands);
1254: #endif
1255:
1256: /* Generate number for unique label. */
1257:
1258: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1259:
1260: /* Copy the increment (negative) to a register for bla insn. */
1261:
1262: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
1263: xoperands[5] = operands[5];
1264: output_asm_insn ("mov %4,%5", xoperands);
1265:
1.1.1.3 ! root 1266: /* Make available a register which is a temporary. */
! 1267:
1.1 root 1268: xoperands[6] = operands[6];
1269:
1270: /* Now the actual loop.
1271: In xoperands, elements 1 and 0 are the input and output vectors.
1272: Element 2 is the loop index. Element 5 is the increment. */
1273:
1274: if (align == 1)
1275: {
1276: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 ! root 1277: output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
! 1278:
! 1279: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
! 1280:
! 1281: output_asm_insn ("adds %1,%2,%1", xoperands);
! 1282: output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands);
! 1283: output_asm_insn ("ld.b 0(%1),r31", xoperands);
! 1284: output_asm_insn ("adds %5,%1,%1", xoperands);
1.1 root 1285: output_asm_insn ("st.b r31,0(%6)", xoperands);
1.1.1.3 ! root 1286: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
! 1287: output_asm_insn ("adds %5,%6,%6", xoperands);
1.1 root 1288: }
1289: if (align == 2)
1290: {
1291: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 ! root 1292: output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
! 1293:
! 1294: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
! 1295:
! 1296: output_asm_insn ("adds %1,%2,%1", xoperands);
! 1297: output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands);
! 1298: output_asm_insn ("ld.s 0(%1),r31", xoperands);
! 1299: output_asm_insn ("adds %5,%1,%1", xoperands);
1.1 root 1300: output_asm_insn ("st.s r31,0(%6)", xoperands);
1.1.1.3 ! root 1301: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
! 1302: output_asm_insn ("adds %5,%6,%6", xoperands);
1.1 root 1303: }
1304: if (align == 4)
1305: {
1306: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 ! root 1307: output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
! 1308:
! 1309: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
! 1310:
! 1311: output_asm_insn ("adds %1,%2,%1", xoperands);
! 1312: output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands);
! 1313: output_asm_insn ("ld.l 0(%1),r31", xoperands);
! 1314: output_asm_insn ("adds %5,%1,%1", xoperands);
1.1 root 1315: output_asm_insn ("st.l r31,0(%6)", xoperands);
1.1.1.3 ! root 1316: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
! 1317: output_asm_insn ("adds %5,%6,%6", xoperands);
1.1 root 1318: }
1319:
1320: return "";
1321: }
1322:
1323: /* Output a delayed branch insn with the delay insn in its
1324: branch slot. The delayed branch insn template is in TEMPLATE,
1325: with operands OPERANDS. The insn in its delay slot is INSN.
1326:
1327: As a special case, since we know that all memory transfers are via
1328: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
1329: reference around the branch as
1330:
1331: orh ha%x,r0,r31
1332: b ...
1333: ld/st l%x(r31),...
1334:
1335: As another special case, we handle loading (SYMBOL_REF ...) and
1336: other large constants around branches as well:
1337:
1338: orh h%x,r0,%0
1339: b ...
1340: or l%x,%0,%1
1341:
1342: */
1343:
1344: char *
1345: output_delayed_branch (template, operands, insn)
1346: char *template;
1347: rtx *operands;
1348: rtx insn;
1349: {
1350: extern rtx recog_operand[];
1351: rtx src = XVECEXP (PATTERN (insn), 0, 1);
1352: rtx dest = XVECEXP (PATTERN (insn), 0, 0);
1353:
1354: if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
1355: || (GET_CODE (src) == CONST_INT
1.1.1.3 ! root 1356: && !(SMALL_INT (src) || (INTVAL (src) & 0xffff) == 0)))
1.1 root 1357: {
1358: rtx xoperands[2];
1359: xoperands[0] = dest;
1360: xoperands[1] = src;
1361:
1362: /* Output the `orh' insn. */
1363: output_asm_insn ("orh h%%%1,r0,%0", xoperands);
1364:
1365: /* Output the branch instruction next. */
1366: output_asm_insn (template, operands);
1367:
1368: /* Now output the `or' insn. */
1369: output_asm_insn ("or l%%%1,%0,%0", xoperands);
1370: }
1371: else if ((GET_CODE (src) == MEM
1372: && CONSTANT_ADDRESS_P (XEXP (src, 0)))
1373: || (GET_CODE (dest) == MEM
1374: && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
1375: {
1376: rtx xoperands[2];
1377: char *split_template;
1378: xoperands[0] = dest;
1379: xoperands[1] = src;
1380:
1381: /* Output the `orh' insn. */
1382: if (GET_CODE (src) == MEM)
1383: {
1384: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1385: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1386: && cc_prev_status.mdep == XEXP (operands[1], 0)))
1387: output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
1388: split_template = load_opcode (GET_MODE (dest),
1.1.1.3 ! root 1389: "l%%%m1(r31),%0", dest);
1.1 root 1390: }
1391: else
1392: {
1393: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1394: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1395: && cc_prev_status.mdep == XEXP (operands[0], 0)))
1396: output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
1397: split_template = store_opcode (GET_MODE (dest),
1398: "%r1,l%%%m0(r31)", src);
1399: }
1400:
1401: /* Output the branch instruction next. */
1402: output_asm_insn (template, operands);
1403:
1404: /* Now output the load or store.
1405: No need to do a CC_STATUS_INIT, because we are branching anyway. */
1406: output_asm_insn (split_template, xoperands);
1407: }
1408: else
1409: {
1410: extern char *insn_template[];
1411: extern char *(*insn_outfun[])();
1412: extern int insn_n_operands[];
1413: extern rtx alter_subreg();
1414: int insn_code_number;
1415: rtx pat = gen_rtx (SET, VOIDmode, dest, src);
1416: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
1417: int i;
1418:
1419: /* Output the branch instruction first. */
1420: output_asm_insn (template, operands);
1421:
1422: /* Now recognize the insn which we put in its delay slot.
1423: We must do this after outputing the branch insn,
1424: since operands may just be a pointer to `recog_operand'. */
1425: insn_code_number = recog (pat, delay_insn);
1426: if (insn_code_number == -1)
1427: abort ();
1428:
1429: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1430: {
1431: if (GET_CODE (recog_operand[i]) == SUBREG)
1432: recog_operand[i] = alter_subreg (recog_operand[i]);
1433: }
1434:
1435: /* Now get the template for what this insn would
1436: have been, without the branch. Its operands are
1437: exactly the same as they would be, so we don't
1438: need to do an insn_extract. */
1439: template = insn_template[insn_code_number];
1440: if (template == 0)
1441: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1442: output_asm_insn (template, recog_operand);
1443: }
1444: CC_STATUS_INIT;
1445: return "";
1446: }
1447:
1448: /* Output a newly constructed insn DELAY_INSN. */
1449: char *
1450: output_delay_insn (delay_insn)
1451: rtx delay_insn;
1452: {
1453: char *template;
1454: extern rtx recog_operand[];
1455: extern char call_used_regs[];
1456: extern char *insn_template[];
1457: extern int insn_n_operands[];
1458: extern char *(*insn_outfun[])();
1459: extern rtx alter_subreg();
1460: int insn_code_number;
1461: extern int insn_n_operands[];
1462: int i;
1463:
1464: /* Now recognize the insn which we put in its delay slot.
1465: We must do this after outputing the branch insn,
1466: since operands may just be a pointer to `recog_operand'. */
1467: insn_code_number = recog_memoized (delay_insn);
1468: if (insn_code_number == -1)
1469: abort ();
1470:
1471: /* Extract the operands of this delay insn. */
1472: INSN_CODE (delay_insn) = insn_code_number;
1473: insn_extract (delay_insn);
1474:
1475: /* It is possible that this insn has not been properly scaned by final
1476: yet. If this insn's operands don't appear in the peephole's
1477: actual operands, then they won't be fixed up by final, so we
1478: make sure they get fixed up here. -- This is a kludge. */
1479: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1480: {
1481: if (GET_CODE (recog_operand[i]) == SUBREG)
1482: recog_operand[i] = alter_subreg (recog_operand[i]);
1483: }
1484:
1485: #ifdef REGISTER_CONSTRAINTS
1486: if (! constrain_operands (insn_code_number))
1487: abort ();
1488: #endif
1489:
1490: cc_prev_status = cc_status;
1491:
1492: /* Update `cc_status' for this instruction.
1493: The instruction's output routine may change it further.
1494: If the output routine for a jump insn needs to depend
1495: on the cc status, it should look at cc_prev_status. */
1496:
1497: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
1498:
1499: /* Now get the template for what this insn would
1500: have been, without the branch. */
1501:
1502: template = insn_template[insn_code_number];
1503: if (template == 0)
1504: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1505: output_asm_insn (template, recog_operand);
1506: return "";
1507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.