|
|
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
1.1.1.4 ! root 363: insn; `orh'. */
! 364: if ((INTVAL (op) & 0xffff) == 0)
1.1 root 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:
1.1.1.4 ! root 1038: #if 0
1.1 root 1039: /* Load the address specified by OPERANDS[3] into the register
1040: specified by OPERANDS[0].
1041:
1042: OPERANDS[3] may be the result of a sum, hence it could either be:
1043:
1044: (1) CONST
1045: (2) REG
1046: (2) REG + CONST_INT
1047: (3) REG + REG + CONST_INT
1048: (4) REG + REG (special case of 3).
1049:
1050: Note that (3) is not a legitimate address.
1051: All cases are handled here. */
1052:
1053: void
1054: output_load_address (operands)
1055: rtx *operands;
1056: {
1057: rtx base, offset;
1058:
1059: if (CONSTANT_P (operands[3]))
1060: {
1061: output_asm_insn ("mov %3,%0", operands);
1062: return;
1063: }
1064:
1065: if (REG_P (operands[3]))
1066: {
1067: if (REGNO (operands[0]) != REGNO (operands[3]))
1068: output_asm_insn ("mov %3,%0", operands);
1069: return;
1070: }
1071:
1072: if (GET_CODE (operands[3]) != PLUS)
1073: abort ();
1074:
1075: base = XEXP (operands[3], 0);
1076: offset = XEXP (operands[3], 1);
1077:
1078: if (GET_CODE (base) == CONST_INT)
1079: {
1080: rtx tmp = base;
1081: base = offset;
1082: offset = tmp;
1083: }
1084:
1085: if (GET_CODE (offset) != CONST_INT)
1086: {
1087: /* Operand is (PLUS (REG) (REG)). */
1088: base = operands[3];
1089: offset = const0_rtx;
1090: }
1091:
1092: if (REG_P (base))
1093: {
1094: operands[6] = base;
1095: operands[7] = offset;
1096: if (SMALL_INT (offset))
1097: output_asm_insn ("adds %7,%6,%0", operands);
1098: else
1099: output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
1100: }
1101: else if (GET_CODE (base) == PLUS)
1102: {
1103: operands[6] = XEXP (base, 0);
1104: operands[7] = XEXP (base, 1);
1105: operands[8] = offset;
1106:
1107: if (SMALL_INT (offset))
1108: output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
1109: else
1110: output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
1111: }
1112: else
1113: abort ();
1114: }
1.1.1.4 ! root 1115: #endif
1.1 root 1116:
1.1.1.3 root 1117: /* Output code to place a size count SIZE in register REG. */
1.1 root 1118:
1119: static void
1120: output_size_for_block_move (size, reg, align)
1121: rtx size, reg, align;
1122: {
1123: rtx xoperands[3];
1124:
1125: xoperands[0] = reg;
1126: xoperands[1] = size;
1127: xoperands[2] = align;
1128:
1129: #if 1
1130: cc_status.flags &= ~ CC_KNOW_HI_R31;
1131: output_asm_insn ("mov %1,%0", xoperands);
1132: #else
1133: if (GET_CODE (size) == REG)
1134: output_asm_insn ("sub %2,%1,%0", xoperands);
1135: else
1136: {
1137: xoperands[1]
1138: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
1139: cc_status.flags &= ~ CC_KNOW_HI_R31;
1140: output_asm_insn ("mov %1,%0", xoperands);
1141: }
1142: #endif
1143: }
1144:
1145: /* Emit code to perform a block move.
1146:
1147: OPERANDS[0] is the destination.
1148: OPERANDS[1] is the source.
1149: OPERANDS[2] is the size.
1150: OPERANDS[3] is the known safe alignment.
1151: OPERANDS[4..6] are pseudos we can safely clobber as temps. */
1152:
1153: char *
1154: output_block_move (operands)
1155: rtx *operands;
1156: {
1157: /* A vector for our computed operands. Note that load_output_address
1158: makes use of (and can clobber) up to the 8th element of this vector. */
1159: rtx xoperands[10];
1160: rtx zoperands[10];
1161: static int movstrsi_label = 0;
1162: int i, j;
1163: rtx temp1 = operands[4];
1164: rtx alignrtx = operands[3];
1165: int align = INTVAL (alignrtx);
1166:
1167: xoperands[0] = operands[0];
1168: xoperands[1] = operands[1];
1169: xoperands[2] = temp1;
1170:
1171: /* We can't move more than four bytes at a time
1172: because we have only one register to move them through. */
1173: if (align > 4)
1174: {
1175: align = 4;
1176: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
1177: }
1178:
1179: /* Since we clobber untold things, nix the condition codes. */
1180: CC_STATUS_INIT;
1181:
1182: /* Recognize special cases of block moves. These occur
1183: when GNU C++ is forced to treat something as BLKmode
1184: to keep it in memory, when its mode could be represented
1185: with something smaller.
1186:
1187: We cannot do this for global variables, since we don't know
1188: what pages they don't cross. Sigh. */
1189: if (GET_CODE (operands[2]) == CONST_INT
1190: && INTVAL (operands[2]) <= 16
1191: && ! CONSTANT_ADDRESS_P (operands[0])
1192: && ! CONSTANT_ADDRESS_P (operands[1]))
1193: {
1194: int size = INTVAL (operands[2]);
1195: rtx op0 = xoperands[0];
1196: rtx op1 = xoperands[1];
1197:
1198: cc_status.flags &= ~CC_KNOW_HI_R31;
1199: if (align == 1)
1200: {
1201: if (memory_address_p (QImode, plus_constant (op0, size))
1202: && memory_address_p (QImode, plus_constant (op1, size)))
1203: {
1204: for (i = size-1; i >= 0; i--)
1205: {
1206: xoperands[0] = plus_constant (op0, i);
1207: xoperands[1] = plus_constant (op1, i);
1208: output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
1209: xoperands);
1210: }
1211: return "";
1212: }
1213: }
1214: else if (align == 2)
1215: {
1216: if (memory_address_p (HImode, plus_constant (op0, size))
1217: && memory_address_p (HImode, plus_constant (op1, size)))
1218: {
1219: for (i = (size>>1)-1; i >= 0; i--)
1220: {
1221: xoperands[0] = plus_constant (op0, i * 2);
1222: xoperands[1] = plus_constant (op1, i * 2);
1223: output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
1224: xoperands);
1225: }
1226: return "";
1227: }
1228: }
1229: else
1230: {
1231: if (memory_address_p (SImode, plus_constant (op0, size))
1232: && memory_address_p (SImode, plus_constant (op1, size)))
1233: {
1234: for (i = (size>>2)-1; i >= 0; i--)
1235: {
1236: xoperands[0] = plus_constant (op0, i * 4);
1237: xoperands[1] = plus_constant (op1, i * 4);
1238: output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
1239: xoperands);
1240: }
1241: return "";
1242: }
1243: }
1244: }
1245:
1246: /* This is the size of the transfer.
1247: Either use the register which already contains the size,
1248: or use a free register (used by no operands). */
1249: output_size_for_block_move (operands[2], operands[4], alignrtx);
1250:
1251: #if 0
1252: /* Also emit code to decrement the size value by ALIGN. */
1253: zoperands[0] = operands[0];
1254: zoperands[3] = plus_constant (operands[0], align);
1255: output_load_address (zoperands);
1256: #endif
1257:
1258: /* Generate number for unique label. */
1259:
1260: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1261:
1262: /* Copy the increment (negative) to a register for bla insn. */
1263:
1264: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
1265: xoperands[5] = operands[5];
1266: output_asm_insn ("mov %4,%5", xoperands);
1267:
1.1.1.3 root 1268: /* Make available a register which is a temporary. */
1269:
1.1 root 1270: xoperands[6] = operands[6];
1271:
1272: /* Now the actual loop.
1273: In xoperands, elements 1 and 0 are the input and output vectors.
1274: Element 2 is the loop index. Element 5 is the increment. */
1275:
1276: if (align == 1)
1277: {
1278: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 root 1279: output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
1280:
1281: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1282:
1283: output_asm_insn ("adds %1,%2,%1", xoperands);
1284: output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands);
1285: output_asm_insn ("ld.b 0(%1),r31", xoperands);
1286: output_asm_insn ("adds %5,%1,%1", xoperands);
1.1 root 1287: output_asm_insn ("st.b r31,0(%6)", xoperands);
1.1.1.3 root 1288: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1289: output_asm_insn ("adds %5,%6,%6", xoperands);
1.1 root 1290: }
1291: if (align == 2)
1292: {
1293: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 root 1294: output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
1295:
1296: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1297:
1298: output_asm_insn ("adds %1,%2,%1", xoperands);
1299: output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands);
1300: output_asm_insn ("ld.s 0(%1),r31", xoperands);
1301: output_asm_insn ("adds %5,%1,%1", xoperands);
1.1 root 1302: output_asm_insn ("st.s r31,0(%6)", xoperands);
1.1.1.3 root 1303: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1304: output_asm_insn ("adds %5,%6,%6", xoperands);
1.1 root 1305: }
1306: if (align == 4)
1307: {
1308: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 root 1309: output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
1310:
1311: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1312:
1313: output_asm_insn ("adds %1,%2,%1", xoperands);
1314: output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands);
1315: output_asm_insn ("ld.l 0(%1),r31", xoperands);
1316: output_asm_insn ("adds %5,%1,%1", xoperands);
1.1 root 1317: output_asm_insn ("st.l r31,0(%6)", xoperands);
1.1.1.3 root 1318: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1319: output_asm_insn ("adds %5,%6,%6", xoperands);
1.1 root 1320: }
1321:
1322: return "";
1323: }
1324:
1325: /* Output a delayed branch insn with the delay insn in its
1326: branch slot. The delayed branch insn template is in TEMPLATE,
1327: with operands OPERANDS. The insn in its delay slot is INSN.
1328:
1329: As a special case, since we know that all memory transfers are via
1330: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
1331: reference around the branch as
1332:
1333: orh ha%x,r0,r31
1334: b ...
1335: ld/st l%x(r31),...
1336:
1337: As another special case, we handle loading (SYMBOL_REF ...) and
1338: other large constants around branches as well:
1339:
1340: orh h%x,r0,%0
1341: b ...
1342: or l%x,%0,%1
1343:
1344: */
1345:
1346: char *
1347: output_delayed_branch (template, operands, insn)
1348: char *template;
1349: rtx *operands;
1350: rtx insn;
1351: {
1352: extern rtx recog_operand[];
1353: rtx src = XVECEXP (PATTERN (insn), 0, 1);
1354: rtx dest = XVECEXP (PATTERN (insn), 0, 0);
1355:
1356: if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
1357: || (GET_CODE (src) == CONST_INT
1.1.1.3 root 1358: && !(SMALL_INT (src) || (INTVAL (src) & 0xffff) == 0)))
1.1 root 1359: {
1360: rtx xoperands[2];
1361: xoperands[0] = dest;
1362: xoperands[1] = src;
1363:
1364: /* Output the `orh' insn. */
1365: output_asm_insn ("orh h%%%1,r0,%0", xoperands);
1366:
1367: /* Output the branch instruction next. */
1368: output_asm_insn (template, operands);
1369:
1370: /* Now output the `or' insn. */
1371: output_asm_insn ("or l%%%1,%0,%0", xoperands);
1372: }
1373: else if ((GET_CODE (src) == MEM
1374: && CONSTANT_ADDRESS_P (XEXP (src, 0)))
1375: || (GET_CODE (dest) == MEM
1376: && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
1377: {
1378: rtx xoperands[2];
1379: char *split_template;
1380: xoperands[0] = dest;
1381: xoperands[1] = src;
1382:
1383: /* Output the `orh' insn. */
1384: if (GET_CODE (src) == MEM)
1385: {
1386: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1387: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1388: && cc_prev_status.mdep == XEXP (operands[1], 0)))
1389: output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
1390: split_template = load_opcode (GET_MODE (dest),
1.1.1.3 root 1391: "l%%%m1(r31),%0", dest);
1.1 root 1392: }
1393: else
1394: {
1395: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1396: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1397: && cc_prev_status.mdep == XEXP (operands[0], 0)))
1398: output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
1399: split_template = store_opcode (GET_MODE (dest),
1400: "%r1,l%%%m0(r31)", src);
1401: }
1402:
1403: /* Output the branch instruction next. */
1404: output_asm_insn (template, operands);
1405:
1406: /* Now output the load or store.
1407: No need to do a CC_STATUS_INIT, because we are branching anyway. */
1408: output_asm_insn (split_template, xoperands);
1409: }
1410: else
1411: {
1412: extern char *insn_template[];
1413: extern char *(*insn_outfun[])();
1414: extern int insn_n_operands[];
1415: extern rtx alter_subreg();
1416: int insn_code_number;
1417: rtx pat = gen_rtx (SET, VOIDmode, dest, src);
1418: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
1419: int i;
1420:
1421: /* Output the branch instruction first. */
1422: output_asm_insn (template, operands);
1423:
1424: /* Now recognize the insn which we put in its delay slot.
1425: We must do this after outputing the branch insn,
1426: since operands may just be a pointer to `recog_operand'. */
1427: insn_code_number = recog (pat, delay_insn);
1428: if (insn_code_number == -1)
1429: abort ();
1430:
1431: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1432: {
1433: if (GET_CODE (recog_operand[i]) == SUBREG)
1434: recog_operand[i] = alter_subreg (recog_operand[i]);
1435: }
1436:
1437: /* Now get the template for what this insn would
1438: have been, without the branch. Its operands are
1439: exactly the same as they would be, so we don't
1440: need to do an insn_extract. */
1441: template = insn_template[insn_code_number];
1442: if (template == 0)
1443: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1444: output_asm_insn (template, recog_operand);
1445: }
1446: CC_STATUS_INIT;
1447: return "";
1448: }
1449:
1450: /* Output a newly constructed insn DELAY_INSN. */
1451: char *
1452: output_delay_insn (delay_insn)
1453: rtx delay_insn;
1454: {
1455: char *template;
1456: extern rtx recog_operand[];
1457: extern char call_used_regs[];
1458: extern char *insn_template[];
1459: extern int insn_n_operands[];
1460: extern char *(*insn_outfun[])();
1461: extern rtx alter_subreg();
1462: int insn_code_number;
1463: extern int insn_n_operands[];
1464: int i;
1465:
1466: /* Now recognize the insn which we put in its delay slot.
1467: We must do this after outputing the branch insn,
1468: since operands may just be a pointer to `recog_operand'. */
1469: insn_code_number = recog_memoized (delay_insn);
1470: if (insn_code_number == -1)
1471: abort ();
1472:
1473: /* Extract the operands of this delay insn. */
1474: INSN_CODE (delay_insn) = insn_code_number;
1475: insn_extract (delay_insn);
1476:
1477: /* It is possible that this insn has not been properly scaned by final
1478: yet. If this insn's operands don't appear in the peephole's
1479: actual operands, then they won't be fixed up by final, so we
1480: make sure they get fixed up here. -- This is a kludge. */
1481: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1482: {
1483: if (GET_CODE (recog_operand[i]) == SUBREG)
1484: recog_operand[i] = alter_subreg (recog_operand[i]);
1485: }
1486:
1487: #ifdef REGISTER_CONSTRAINTS
1488: if (! constrain_operands (insn_code_number))
1489: abort ();
1490: #endif
1491:
1492: cc_prev_status = cc_status;
1493:
1494: /* Update `cc_status' for this instruction.
1495: The instruction's output routine may change it further.
1496: If the output routine for a jump insn needs to depend
1497: on the cc status, it should look at cc_prev_status. */
1498:
1499: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
1500:
1501: /* Now get the template for what this insn would
1502: have been, without the branch. */
1503:
1504: template = insn_template[insn_code_number];
1505: if (template == 0)
1506: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1507: output_asm_insn (template, recog_operand);
1508: return "";
1509: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.