|
|
1.1 root 1: /* Subroutines for insn-output.c for Sun SPARC.
2: Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
4:
5: This file is part of GNU CC.
6:
7: GNU CC is 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: /* Global variables for machine-dependend things. */
22:
23: /* This should go away if we pass floats to regs via
24: the stack instead of the frame, and if we learn how
25: to renumber all the registers when we don't do a save (hard!). */
26: extern int frame_pointer_needed;
27:
28: static rtx find_addr_reg ();
29:
30: rtx next_real_insn_no_labels ();
31:
32: /* Return non-zero only if OP is a register of mode MODE,
33: or const0_rtx. */
34: int
35: reg_or_0_operand (op, mode)
36: rtx op;
37: enum machine_mode mode;
38: {
39: return (op == const0_rtx || register_operand (op, mode));
40: }
41:
1.1.1.3 root 42: /* Return non-zero if INSN is a conditional insn with a predicate
43: valid after an addcc or subcc instruction. */
44:
45: int
46: ignore_overflow_conditional_p (insn)
47: rtx insn;
48: {
49: rtx x = SET_SRC (PATTERN (insn));
50: RTX_CODE code;
51: if (GET_CODE (x) == IF_THEN_ELSE)
52: x = XEXP (x, 0);
53: code = GET_CODE (x);
54: return code == EQ || code == NE || code == GE || code == LT;
55: }
56:
1.1 root 57: /* Return non-zero if this pattern, can be evaluated safely, even if it
58: was not asked for. */
59: int
60: safe_insn_src_p (op, mode)
61: rtx op;
62: enum machine_mode mode;
63: {
64: /* Just experimenting. */
65:
66: /* No floating point src is safe if it contains an arithmetic
67: operation, since that operation may trap. */
68: switch (GET_CODE (op))
69: {
70: case CONST_INT:
71: case LABEL_REF:
72: case SYMBOL_REF:
73: case CONST:
74: return 1;
75:
76: case REG:
77: return 1;
78:
79: case MEM:
80: return CONSTANT_ADDRESS_P (XEXP (op, 0));
81:
82: /* We never need to negate or complement constants. */
83: case NEG:
84: return (mode != SFmode && mode != DFmode);
85: case NOT:
86: return 1;
87:
88: case COMPARE:
89: case MINUS:
90: case PLUS:
91: return (mode != SFmode && mode != DFmode);
92: case AND:
93: case IOR:
94: case XOR:
95: case LSHIFT:
96: case ASHIFT:
97: case ASHIFTRT:
98: case LSHIFTRT:
99: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
100: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
101: return 0;
102: return 1;
103:
104: default:
105: return 0;
106: }
107: }
108:
109: /* Return 1 if REG is clobbered in IN.
110: Return 0 if REG is used in IN (other than being clobbered).
111: Return 2 if REG does not appear in IN. */
112:
113: static int
114: reg_clobbered_p (reg, in)
115: rtx reg;
116: rtx in;
117: {
118: register char *fmt;
119: register int i, result = 0;
120:
121: register enum rtx_code code;
122:
123: if (in == 0)
124: return 2;
125:
126: code = GET_CODE (in);
127:
128: switch (code)
129: {
130: /* Let these fail out quickly. */
131: case CONST_INT:
132: case SYMBOL_REF:
133: case CONST:
134: return 2;
135:
136: case SUBREG:
137: if (SUBREG_WORD (in) != 0)
138: in = gen_rtx (REG, SImode, REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
139: else
140: in = SUBREG_REG (in);
141:
142: case REG:
143: if (in == reg
144: || refers_to_regno_p (REGNO (reg),
145: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
146: in, 0))
147: return 0;
148: return 2;
149:
150: case SET:
151: if (SET_SRC (in) == reg
152: || refers_to_regno_p (REGNO (reg),
153: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
154: SET_SRC (in), 0))
155: return 0;
156:
157: if (SET_DEST (in) == reg)
158: return 1;
159:
160: if (refers_to_regno_p (REGNO (reg),
161: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
162: SET_DEST (in), 0))
163: if (GET_CODE (SET_DEST (in)) == REG
164: || GET_CODE (SET_DEST (in)) == SUBREG)
165: return 1;
166: else
167: return 0;
168: return 2;
169:
170: case USE:
171: if (XEXP (in, 0) == reg
172: || refers_to_regno_p (REGNO (reg),
173: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
174: XEXP (in, 0), 0))
175: return 0;
176: return 2;
177:
178: case CLOBBER:
179: if (XEXP (in, 0) == reg)
180: return 1;
181: /* If the CLOBBER expression is a SUBREG, accept that as a
182: clobber. But if it is some expression based on this register,
183: that is like a USE as far as this register is concerned,
184: so we won't take it. */
185: if (refers_to_regno_p (REGNO (reg),
186: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
187: XEXP (in, 0), 0))
188: if (GET_CODE (XEXP (in, 0)) == REG
189: || GET_CODE (XEXP (in, 0)) == SUBREG)
190: return 1;
191: else
192: return 0;
193: return 2;
194: }
195:
196: fmt = GET_RTX_FORMAT (code);
197:
198: result = 2;
199:
200: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
201: {
202: if (fmt[i] == 'E')
203: {
204: register int j;
205: for (j = XVECLEN (in, i) - 1; j >= 0; j--)
206: switch (reg_clobbered_p (reg, XVECEXP (in, i, j)))
207: {
208: case 0:
209: return 0;
210: case 2:
211: continue;
212: case 1:
213: result = 1;
214: break;
215: }
216: }
217: else if (fmt[i] == 'e')
218: switch (reg_clobbered_p (reg, XEXP (in, i)))
219: {
220: case 0:
221: return 0;
222: case 2:
223: continue;
224: case 1:
225: result = 1;
226: break;
227: }
228: }
229: return result;
230: }
231:
232: /* Return non-zero if OP can be written to without screwing up
233: GCC's model of what's going on. It is assumed that this operand
234: appears in the dest position of a SET insn in a conditional
235: branch's delay slot. AFTER is the label to start looking from. */
236: int
237: operand_clobbered_before_used_after (op, after)
238: rtx op;
239: rtx after;
240: {
241: extern char call_used_regs[];
242:
243: /* Just experimenting. */
244: if (GET_CODE (op) == CC0)
245: return 1;
246: if (GET_CODE (op) == REG)
247: {
248: rtx insn;
249:
250: if (op == stack_pointer_rtx)
251: return 0;
252:
253: for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
254: {
255: if (GET_CODE (insn) == NOTE)
256: continue;
257: if (GET_CODE (insn) == INSN
258: || GET_CODE (insn) == JUMP_INSN
259: || GET_CODE (insn) == CALL_INSN)
260: {
261: switch (reg_clobbered_p (op, PATTERN (insn)))
262: {
263: case 0:
264: return 0;
265: case 2:
266: break;
267: case 1:
268: return 1;
269: }
270: if (dead_or_set_p (insn, op))
271: return 1;
272: }
273: else if (GET_CODE (insn) == CODE_LABEL)
274: return 0;
275: if (GET_CODE (insn) == JUMP_INSN)
276: {
277: if (condjump_p (insn))
278: return 0;
279: /* This is a jump insn which has already
280: been mangled. We can't tell what it does. */
281: if (GET_CODE (PATTERN (insn)) == PARALLEL)
282: return 0;
283: if (! JUMP_LABEL (insn))
284: return 0;
285: /* Keep following jumps. */
286: insn = JUMP_LABEL (insn);
287: }
288: }
289: return 1;
290: }
291:
292: /* In both of these cases, the first insn executed
293: for this op will be a sethi %hi(whatever),%g1,
294: which is tolerable. */
295: if (GET_CODE (op) == MEM)
296: return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
297:
298: return 0;
299: }
300:
301: /* Return non-zero if this pattern, as a source to a "SET",
302: is known to yield an instruction of unit size. */
303: int
304: single_insn_src_p (op, mode)
305: rtx op;
306: enum machine_mode mode;
307: {
308: switch (GET_CODE (op))
309: {
310: case CONST_INT:
311: #if 1
312: /* This is not always a single insn src, technically,
313: but output_delayed_branch knows how to deal with it. */
314: return 1;
315: #else
316: if (SMALL_INT (op))
317: return 1;
318: /* We can put this set insn into delay slot, because this is one
319: insn; 'sethi'. */
320: if ((INTVAL (op) & 0x3ff) == 0)
321: return 1;
322:
323: /* This is not a single insn src, technically,
324: but output_delayed_branch knows how to deal with it. */
325: return 1;
326: #endif
327:
328: #if 1
329: case SYMBOL_REF:
330: /* This is not a single insn src, technically,
331: but output_delayed_branch knows how to deal with it. */
332: return 1;
333: #else
334: return 0;
335: #endif
336:
337: case REG:
338: return 1;
339:
340: case MEM:
341: #if 0
342: /* This is not a single insn src, technically,
343: but output_delayed_branch knows how to deal with it. */
344: if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF)
345: return 0;
346: #endif
347: return 1;
348:
349: /* We never need to negate or complement constants. */
350: case NEG:
351: return (mode != DFmode);
352: case NOT:
353: return 1;
354:
355: case COMPARE:
356: case MINUS:
357: /* If the target is cc0, then these insns will take
358: two insns (one being a nop). */
359: return (mode != SFmode && mode != DFmode);
360: case PLUS:
361: case AND:
362: case IOR:
363: case XOR:
364: case LSHIFT:
365: case ASHIFT:
366: case ASHIFTRT:
367: case LSHIFTRT:
368: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
369: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
370: return 0;
371: return 1;
372:
373: case SUBREG:
374: if (SUBREG_WORD (op) != 0)
375: return 0;
376: return single_insn_src_p (SUBREG_REG (op), mode);
377:
378: case SIGN_EXTEND:
379: case ZERO_EXTEND:
380: /* Lazy... could check for more cases. */
381: if (GET_CODE (XEXP (op, 0)) == MEM
382: && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
383: return 1;
384: return 0;
385:
386: /* Not doing floating point, since they probably
387: take longer than the branch slot they might fill. */
388: case FLOAT_EXTEND:
389: case FLOAT_TRUNCATE:
390: case FLOAT:
391: case FIX:
392: case UNSIGNED_FLOAT:
393: case UNSIGNED_FIX:
394: return 0;
395:
396: default:
397: return 0;
398: }
399: }
400:
1.1.1.2 root 401: /* This extra test must be done to verify that a move insn
402: really is just one assembler insn. */
403:
404: int
405: single_insn_extra_test (dest, src)
406: rtx dest, src;
407: {
408: /* Moves between FP regs and CPU regs are two insns. */
409: return (!(GET_CODE (src) == REG
410: && GET_CODE (dest) == REG
411: && (FP_REG_P (src) != FP_REG_P (dest))));
412: }
413:
1.1 root 414: /* Nonzero only if this *really* is a single insn operand. */
415: int
416: strict_single_insn_op_p (op, mode)
417: rtx op;
418: enum machine_mode mode;
419: {
420: if (mode == VOIDmode)
421: mode = GET_MODE (op);
422:
423: switch (GET_CODE (op))
424: {
425: case CC0:
426: return 1;
427:
428: case CONST_INT:
429: if (SMALL_INT (op))
430: return 1;
431: /* We can put this set insn into delay slot, because this is one
432: insn; 'sethi'. */
433: if ((INTVAL (op) & 0x3ff) == 0)
434: return 1;
435: return 0;
436:
437: case SYMBOL_REF:
438: return 0;
439:
440: case REG:
441: return (mode != DFmode && mode != DImode);
442:
443: case MEM:
444: if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
445: return (mode != DFmode && mode != DImode);
446: return 0;
447:
448: /* We never need to negate or complement constants. */
449: case NEG:
450: return (mode != DFmode);
451: case NOT:
452: return 1;
453:
454: case COMPARE:
455: case MINUS:
456: /* If the target is cc0, then these insns will take
457: two insns (one being a nop). */
458: return (mode != SFmode && mode != DFmode);
459: case PLUS:
460: case AND:
461: case IOR:
462: case XOR:
463: case LSHIFT:
464: case ASHIFT:
465: case ASHIFTRT:
466: case LSHIFTRT:
467: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
468: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
469: return 0;
470: return 1;
471:
472: case SUBREG:
473: if (SUBREG_WORD (op) != 0)
474: return 0;
475: return strict_single_insn_op_p (SUBREG_REG (op), mode);
476:
477: case SIGN_EXTEND:
478: case ZERO_EXTEND:
479: if (GET_CODE (XEXP (op, 0)) == MEM
480: && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
481: return 1;
482: return 0;
483:
484: /* Not doing floating point, since they probably
485: take longer than the branch slot they might fill. */
486: case FLOAT_EXTEND:
487: case FLOAT_TRUNCATE:
488: case FLOAT:
489: case FIX:
490: case UNSIGNED_FLOAT:
491: case UNSIGNED_FIX:
492: return 0;
493:
494: default:
495: return 0;
496: }
497: }
498:
499: /* Return truth value of whether OP is a relational operator. */
500: int
501: relop (op, mode)
502: rtx op;
503: enum machine_mode mode;
504: {
505: switch (GET_CODE (op))
506: {
507: case EQ:
508: case NE:
509: case GT:
510: case GE:
511: case LT:
512: case LE:
513: case GTU:
514: case GEU:
515: case LTU:
516: case LEU:
517: return 1;
518: }
519: return 0;
520: }
521:
522: /* Return truth value of wheterh OP is EQ or NE. */
523: int
524: eq_or_neq (op, mode)
525: rtx op;
526: enum machine_mode mode;
527: {
528: return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
529: }
530:
531: /* Return truth value of whether OP can be used as an operands in a three
532: address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */
533:
534: int
535: arith_operand (op, mode)
536: rtx op;
537: enum machine_mode mode;
538: {
539: return (register_operand (op, mode)
540: || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
541: }
542:
543: /* Return truth value of whether OP can be used as an operand in a two
544: address arithmetic insn (such as set 123456,%o4) of mode MODE. */
545:
546: int
547: arith32_operand (op, mode)
548: rtx op;
549: enum machine_mode mode;
550: {
551: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
552: }
553:
554: /* Return truth value of whether OP is a integer which fits the
555: range constraining immediate operands in three-address insns. */
556:
557: int
558: small_int (op, mode)
559: rtx op;
560: enum machine_mode mode;
561: {
562: return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
563: }
564:
565: /* Return the best assembler insn template
566: for moving operands[1] into operands[0] as a fullword. */
567:
568: static char *
569: singlemove_string (operands)
570: rtx *operands;
571: {
572: if (GET_CODE (operands[0]) == MEM)
573: {
574: if (GET_CODE (operands[1]) != MEM)
575: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
576: {
577: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
578: && cc_prev_status.mdep == XEXP (operands[0], 0)))
579: output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
580: cc_status.flags |= CC_KNOW_HI_G1;
581: cc_status.mdep = XEXP (operands[0], 0);
582: return "st %1,[%%lo(%m0)+%%g1]";
583: }
584: else
585: return "st %r1,%0";
586: else
587: {
588: rtx xoperands[2];
589:
590: cc_status.flags &= ~CC_F0_IS_0;
591: xoperands[0] = gen_rtx (REG, SFmode, 32);
592: xoperands[1] = operands[1];
593: output_asm_insn (singlemove_string (xoperands), xoperands);
594: xoperands[1] = xoperands[0];
595: xoperands[0] = operands[0];
596: output_asm_insn (singlemove_string (xoperands), xoperands);
597: return "";
598: }
599: }
600: if (GET_CODE (operands[1]) == MEM)
601: {
602: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
603: {
604: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
605: && cc_prev_status.mdep == XEXP (operands[1], 0)))
606: output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
607: cc_status.flags |= CC_KNOW_HI_G1;
608: cc_status.mdep = XEXP (operands[1], 0);
609: return "ld [%%lo(%m1)+%%g1],%0";
610: }
611: return "ld %1,%0";
612: }
613: return "mov %1,%0";
614: }
615:
616: /* Output assembler code to perform a doubleword move insn
617: with operands OPERANDS. */
618:
619: char *
620: output_move_double (operands)
621: rtx *operands;
622: {
623: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
624: rtx latehalf[2];
625: rtx addreg0 = 0, addreg1 = 0;
626:
627: /* First classify both operands. */
628:
629: if (REG_P (operands[0]))
630: optype0 = REGOP;
631: else if (offsettable_memref_p (operands[0]))
632: optype0 = OFFSOP;
633: else if (GET_CODE (operands[0]) == MEM)
634: optype0 = MEMOP;
635: else
636: optype0 = RNDOP;
637:
638: if (REG_P (operands[1]))
639: optype1 = REGOP;
640: else if (CONSTANT_P (operands[1])
641: || GET_CODE (operands[1]) == CONST_DOUBLE)
642: optype1 = CNSTOP;
643: else if (offsettable_memref_p (operands[1]))
644: optype1 = OFFSOP;
645: else if (GET_CODE (operands[1]) == MEM)
646: optype1 = MEMOP;
647: else
648: optype1 = RNDOP;
649:
650: /* Check for the cases that the operand constraints are not
651: supposed to allow to happen. Abort if we get one,
652: because generating code for these cases is painful. */
653:
654: if (optype0 == RNDOP || optype1 == RNDOP)
655: abort ();
656:
657: /* If an operand is an unoffsettable memory ref, find a register
658: we can increment temporarily to make it refer to the second word. */
659:
660: if (optype0 == MEMOP)
661: addreg0 = find_addr_reg (XEXP (operands[0], 0));
662:
663: if (optype1 == MEMOP)
664: addreg1 = find_addr_reg (XEXP (operands[1], 0));
665:
666: /* Ok, we can do one word at a time.
667: Normally we do the low-numbered word first,
668: but if either operand is autodecrementing then we
669: do the high-numbered word first.
670:
671: In either case, set up in LATEHALF the operands to use
672: for the high-numbered word and in some cases alter the
673: operands in OPERANDS to be suitable for the low-numbered word. */
674:
675: if (optype0 == REGOP)
676: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
677: else if (optype0 == OFFSOP)
678: latehalf[0] = adj_offsettable_operand (operands[0], 4);
679: else
680: latehalf[0] = operands[0];
681:
682: if (optype1 == REGOP)
683: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
684: else if (optype1 == OFFSOP)
685: latehalf[1] = adj_offsettable_operand (operands[1], 4);
686: else if (optype1 == CNSTOP)
687: {
688: if (CONSTANT_P (operands[1]))
689: latehalf[1] = const0_rtx;
690: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
691: {
692: latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
693: CONST_DOUBLE_HIGH (operands[1]));
694: operands[1] = gen_rtx (CONST_INT, VOIDmode,
695: CONST_DOUBLE_LOW (operands[1]));
696: }
697: }
698: else
699: latehalf[1] = operands[1];
700:
701: /* If the first move would clobber the source of the second one,
702: do them in the other order.
703:
704: RMS says "This happens only for registers;
705: such overlap can't happen in memory unless the user explicitly
706: sets it up, and that is an undefined circumstance."
707:
708: but it happens on the sparc when loading parameter registers,
709: so I am going to define that circumstance, and make it work
710: as expected. */
711:
712: /* Easy case: try moving both words at once. */
713: /* First check for moving between an even/odd register pair
714: and a memory location. */
715: if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP
716: && (REGNO (operands[0]) & 1) == 0)
717: || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP
718: && (REGNO (operands[1]) & 1) == 0))
719: {
720: rtx op1, op2;
721: rtx base = 0, offset = const0_rtx;
722:
723: /* OP1 gets the register pair, and OP2 gets the memory address. */
724: if (optype0 == REGOP)
725: op1 = operands[0], op2 = XEXP (operands[1], 0);
726: else
727: op1 = operands[1], op2 = XEXP (operands[0], 0);
728:
729: /* Now see if we can trust the address to be 8-byte aligned. */
730: /* Trust global variables. */
731: if (CONSTANT_ADDRESS_P (op2))
732: {
733: operands[0] = op1;
734: operands[1] = op2;
735: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
736: && cc_prev_status.mdep == op2))
737: output_asm_insn ("sethi %%hi(%1),%%g1", operands);
738: cc_status.flags |= CC_KNOW_HI_G1;
739: cc_status.mdep = op2;
740: if (op1 == operands[0])
741: return "ldd [%%lo(%1)+%%g1],%0";
742: else
743: return "std [%%lo(%1)+%%g1],%0";
744: }
745:
746: if (GET_CODE (op2) == PLUS)
747: {
748: if (GET_CODE (XEXP (op2, 0)) == REG)
749: base = XEXP (op2, 0), offset = XEXP (op2, 1);
750: else if (GET_CODE (XEXP (op2, 1)) == REG)
751: base = XEXP (op2, 1), offset = XEXP (op2, 0);
752: }
753:
754: /* Trust round enough offsets from the stack or frame pointer. */
755: if (base
756: && (REGNO (base) == FRAME_POINTER_REGNUM
757: || REGNO (base) == STACK_POINTER_REGNUM))
758: {
759: if (GET_CODE (offset) == CONST_INT
760: && (INTVAL (offset) & 0x7) == 0)
761: {
762: if (op1 == operands[0])
763: return "ldd %1,%0";
764: else
765: return "std %1,%0";
766: }
767: }
768: else
769: {
770: /* We know structs not on the stack are properly aligned.
771: Since a double asks for 8-byte alignment,
772: we know it must have got that if it is in a struct.
773: But a DImode need not be 8-byte aligned, because it could be a
774: struct containing two ints or pointers. */
775:
776: /* Sun fucks us here. We cannot trust references
777: to doubles via varying addresses. It might be on the stack
778: even if we don't know that it is; and then it might not be
779: double-word aligned. */
780: #if 0
781: if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode
782: && MEM_IN_STRUCT_P (operands[1]))
783: return "ldd %1,%0";
784: else if (GET_CODE (operands[0]) == MEM
785: && GET_MODE (operands[0]) == DFmode
786: && MEM_IN_STRUCT_P (operands[0]))
787: return "std %1,%0";
788: #endif
789: }
790: }
791:
792: if (optype0 == REGOP && optype1 == REGOP
793: && REGNO (operands[0]) == REGNO (latehalf[1]))
794: {
795: /* Make any unoffsettable addresses point at high-numbered word. */
796: if (addreg0)
797: output_asm_insn ("add %0,0x4,%0", &addreg0);
798: if (addreg1)
799: output_asm_insn ("add %0,0x4,%0", &addreg1);
800:
801: /* Do that word. */
802: output_asm_insn (singlemove_string (latehalf), latehalf);
803:
804: /* Undo the adds we just did. */
805: if (addreg0)
806: output_asm_insn ("add %0,-0x4,%0", &addreg0);
807: if (addreg1)
808: output_asm_insn ("add %0,-0x4,%0", &addreg0);
809:
810: /* Do low-numbered word. */
811: return singlemove_string (operands);
812: }
813: else if (optype0 == REGOP && optype1 != REGOP
814: && reg_overlap_mentioned_p (operands[0], operands[1]))
815: {
816: /* Do the late half first. */
817: output_asm_insn (singlemove_string (latehalf), latehalf);
818: /* Then clobber. */
819: return singlemove_string (operands);
820: }
821:
822: /* Normal case: do the two words, low-numbered first. */
823:
824: output_asm_insn (singlemove_string (operands), operands);
825:
826: /* Make any unoffsettable addresses point at high-numbered word. */
827: if (addreg0)
828: output_asm_insn ("add %0,0x4,%0", &addreg0);
829: if (addreg1)
830: output_asm_insn ("add %0,0x4,%0", &addreg1);
831:
832: /* Do that word. */
833: output_asm_insn (singlemove_string (latehalf), latehalf);
834:
835: /* Undo the adds we just did. */
836: if (addreg0)
837: output_asm_insn ("add %0,-0x4,%0", &addreg0);
838: if (addreg1)
839: output_asm_insn ("add %0,-0x4,%0", &addreg1);
840:
841: return "";
842: }
843:
844: static char *
845: output_fp_move_double (operands)
846: rtx *operands;
847: {
848: if (FP_REG_P (operands[0]))
849: {
850: if (FP_REG_P (operands[1]))
851: {
852: output_asm_insn ("fmovs %1,%0", operands);
853: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
854: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
855: return "fmovs %1,%0";
856: }
857: if (GET_CODE (operands[1]) == REG)
858: {
859: if ((REGNO (operands[1]) & 1) == 0)
860: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
861: else
862: {
863: rtx xoperands[3];
864: xoperands[0] = operands[0];
865: xoperands[1] = operands[1];
866: xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
867: output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands);
868: return "";
869: }
870: }
1.1.1.2 root 871: /* Use ldd if known to be aligned. */
1.1 root 872: if (GET_CODE (XEXP (operands[1], 0)) == PLUS
1.1.1.2 root 873: && (((XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx
874: || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx)
875: && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT
876: && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) == 0)
1.1.1.3 root 877: #if 0 /* An array in a structure that is a parm need not be aligned! */
1.1.1.2 root 878: /* Arrays are known to be aligned,
879: and reg+reg addresses are used (on this machine)
880: only for array accesses. */
881: || (REG_P (XEXP (XEXP (operands[1], 0), 0))
1.1.1.3 root 882: && REG_P (XEXP (XEXP (operands[1], 0), 1)))
883: #endif
884: ))
1.1.1.2 root 885: return "ldd %1,%0";
1.1 root 886: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
887: {
888: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
889: && cc_prev_status.mdep == XEXP (operands[1], 0)))
890: output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
891: cc_status.flags |= CC_KNOW_HI_G1;
892: cc_status.mdep = XEXP (operands[1], 0);
893: return "ldd [%%lo(%m1)+%%g1],%0";
894: }
1.1.1.2 root 895: /* Otherwise use two ld insns. */
896: {
897: rtx xoperands[2];
898: output_asm_insn ("ld %1,%0", operands);
899: xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]),
900: REGNO (operands[0]) + 1);
1.1.1.3 root 901: if (GET_CODE (XEXP (operands[1], 0)) == PLUS
902: && offsettable_address_p (1, GET_MODE (operands[1]),
903: XEXP (operands[1], 0)))
904: {
905: xoperands[1] = adj_offsettable_operand (operands[1], 4);
906: output_asm_insn ("ld %1,%0", xoperands);
907: }
908: else if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
909: {
1.1.1.4 ! root 910: rtx memref = operands[1];
1.1.1.3 root 911: rtx inc_reg = XEXP (XEXP (operands[1], 0), 0);
912: if (inc_reg == frame_pointer_rtx
913: && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == REG
1.1.1.4 ! root 914: && XEXP (XEXP (operands[1], 0), 1) != frame_pointer_rtx)
1.1.1.3 root 915: inc_reg = XEXP (XEXP (operands[1], 0), 1);
916: if (inc_reg == frame_pointer_rtx)
917: {
918: output_asm_insn ("mov %%fp,%%g1", xoperands);
919: inc_reg = gen_rtx (REG, SImode, 1);
1.1.1.4 ! root 920: memref = gen_rtx (GET_CODE (operands[1]),
! 921: GET_MODE (operands[1]),
! 922: gen_rtx (PLUS, GET_MODE (XEXP (operands[1], 0)),
! 923: inc_reg,
! 924: XEXP (XEXP (operands[1], 0), 1)));
1.1.1.3 root 925: }
926: xoperands[1] = inc_reg;
927: output_asm_insn ("add 4,%1,%1", xoperands);
1.1.1.4 ! root 928: xoperands[1] = memref;
1.1.1.3 root 929: output_asm_insn ("ld %1,%0", xoperands);
930: xoperands[1] = inc_reg;
931: output_asm_insn ("add -4,%1,%1", xoperands);
932: }
933: else
934: {
935: xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]),
1.1.1.2 root 936: plus_constant (XEXP (operands[1], 0), 4));
1.1.1.3 root 937: output_asm_insn ("ld %1,%0", xoperands);
938: }
1.1.1.2 root 939: return "";
940: }
1.1 root 941: }
942: else if (FP_REG_P (operands[1]))
943: {
944: if (GET_CODE (operands[0]) == REG)
945: {
946: if ((REGNO (operands[0]) & 1) == 0)
947: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
948: else
949: {
950: rtx xoperands[3];
951: xoperands[2] = operands[1];
952: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
953: xoperands[0] = operands[0];
954: output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);
955: return "";
956: }
957: }
958: /* Use std if we can be sure it is well-aligned. */
959: if (GET_CODE (XEXP (operands[0], 0)) == PLUS
960: && (((XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx
961: || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx)
962: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT
963: && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) == 0)
1.1.1.3 root 964: #if 0 /* An array in a structure that is a parm need not be aligned! */
1.1 root 965: /* Arrays are known to be aligned,
966: and reg+reg addresses are used (on this machine)
967: only for array accesses. */
968: || (REG_P (XEXP (XEXP (operands[0], 0), 0))
1.1.1.3 root 969: && REG_P (XEXP (XEXP (operands[0], 0), 1)))
970: #endif
971: ))
1.1 root 972: return "std %1,%0";
973: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
974: {
975: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
976: && cc_prev_status.mdep == XEXP (operands[0], 0)))
977: output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
978: cc_status.flags |= CC_KNOW_HI_G1;
979: cc_status.mdep = XEXP (operands[0], 0);
980: return "std %1,[%%lo(%m0)+%%g1]";
981: }
982: /* Otherwise use two st insns. */
983: {
984: rtx xoperands[2];
985: output_asm_insn ("st %r1,%0", operands);
986: xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]),
987: REGNO (operands[1]) + 1);
1.1.1.3 root 988: if (GET_CODE (XEXP (operands[0], 0)) == PLUS
989: && offsettable_address_p (1, GET_MODE (operands[0]),
990: XEXP (operands[0], 0)))
991: {
992: xoperands[0] = adj_offsettable_operand (operands[0], 4);
993: output_asm_insn ("st %r1,%0", xoperands);
994: }
995: else if (GET_CODE (XEXP (operands[0], 0)) == PLUS)
996: {
1.1.1.4 ! root 997: rtx memref = operands[0];
1.1.1.3 root 998: rtx inc_reg = XEXP (XEXP (operands[0], 0), 0);
999: if (inc_reg == frame_pointer_rtx
1000: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG
1.1.1.4 ! root 1001: && XEXP (XEXP (operands[0], 0), 1) != frame_pointer_rtx)
1.1.1.3 root 1002: inc_reg = XEXP (XEXP (operands[0], 0), 1);
1003: if (inc_reg == frame_pointer_rtx)
1004: {
1005: output_asm_insn ("mov %%fp,%%g1", xoperands);
1006: inc_reg = gen_rtx (REG, SImode, 1);
1.1.1.4 ! root 1007: memref = gen_rtx (GET_CODE (operands[0]),
! 1008: GET_MODE (operands[0]),
! 1009: gen_rtx (PLUS, GET_MODE (XEXP (operands[0], 0)),
! 1010: inc_reg,
! 1011: XEXP (XEXP (operands[0], 0), 1)));
1.1.1.3 root 1012: }
1013: xoperands[0] = inc_reg;
1014: output_asm_insn ("add 4,%0,%0", xoperands);
1.1.1.4 ! root 1015: xoperands[0] = memref;
1.1.1.3 root 1016: output_asm_insn ("st %r1,%0", xoperands);
1017: xoperands[0] = inc_reg;
1018: output_asm_insn ("add -4,%0,%0", xoperands);
1019: }
1020: else
1021: {
1022: xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]),
1.1 root 1023: plus_constant (XEXP (operands[0], 0), 4));
1.1.1.3 root 1024: output_asm_insn ("st %r1,%0", xoperands);
1025: }
1.1 root 1026: return "";
1027: }
1028: }
1029: else abort ();
1030: }
1031:
1032: /* Return a REG that occurs in ADDR with coefficient 1.
1033: ADDR can be effectively incremented by incrementing REG. */
1034:
1035: static rtx
1036: find_addr_reg (addr)
1037: rtx addr;
1038: {
1039: while (GET_CODE (addr) == PLUS)
1040: {
1.1.1.3 root 1041: if (GET_CODE (XEXP (addr, 0)) == REG
1042: && !(GET_CODE (XEXP (addr, 1)) == REG
1043: && XEXP (addr, 0) == frame_pointer_rtx))
1.1 root 1044: addr = XEXP (addr, 0);
1045: else if (GET_CODE (XEXP (addr, 1)) == REG)
1046: addr = XEXP (addr, 1);
1047: else if (CONSTANT_P (XEXP (addr, 0)))
1048: addr = XEXP (addr, 1);
1049: else if (CONSTANT_P (XEXP (addr, 1)))
1050: addr = XEXP (addr, 0);
1051: else
1052: abort ();
1053: }
1054: if (GET_CODE (addr) == REG)
1055: return addr;
1056: abort ();
1057: }
1058:
1059: void
1060: output_sized_memop (opname, mode)
1061: char *opname;
1062: enum machine_mode mode;
1063: {
1064: extern struct _iobuf *asm_out_file;
1065:
1066: static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" };
1067: static char *st_size_suffix[] = { "b", "h", "", "?", "d" };
1068: char *modename
1069: = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1];
1070:
1071: fprintf (asm_out_file, "\t%s%s", opname, modename);
1072: }
1073:
1074: /* Output a store-in-memory whose operands are OPERANDS[0,1].
1075: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. */
1076:
1077: char *
1078: output_store (operands)
1079: rtx *operands;
1080: {
1081: enum machine_mode mode = GET_MODE (operands[0]);
1082: rtx address = XEXP (operands[0], 0);
1083:
1084: cc_status.flags |= CC_KNOW_HI_G1;
1085: cc_status.mdep = address;
1086:
1087: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1088: && address == cc_prev_status.mdep))
1089: {
1090: output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
1091: cc_prev_status.mdep = address;
1092: }
1093:
1094: /* Store zero in two parts when appropriate. */
1095: if (mode == DFmode && operands[1] == dconst0_rtx)
1096: {
1097: /* We can't cross a page boundary here because the
1098: SYMBOL_REF must be double word aligned, and for this
1099: to be the case, SYMBOL_REF+4 cannot cross. */
1100: output_sized_memop ("st", SImode);
1101: output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands);
1102: output_sized_memop ("st", SImode);
1103: return "%r1,[%%g1+%%lo(%m0)+4]";
1104: }
1105:
1106: /* Code below isn't smart enough to move a doubleword in two parts,
1107: so use output_move_double to do that in the cases that require it. */
1108: if ((mode == DImode || mode == DFmode)
1109: && (GET_CODE (operands[1]) == REG
1110: && (REGNO (operands[1]) & 1)))
1111: return output_move_double (operands);
1112:
1113: output_sized_memop ("st", mode);
1114: return "%r1,[%%g1+%%lo(%m0)]";
1115: }
1116:
1117: /* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1].
1118: OPERANDS[0] is a reg, and OPERANDS[1] is a mem. */
1119:
1120: char *
1121: output_load_fixed (operands)
1122: rtx *operands;
1123: {
1124: enum machine_mode mode = GET_MODE (operands[0]);
1125: rtx address = XEXP (operands[1], 0);
1126:
1127: /* We don't bother trying to see if we know %hi(address).
1128: This is because we are doing a load, and if we know the
1129: %hi value, we probably also know that value in memory. */
1130: cc_status.flags |= CC_KNOW_HI_G1;
1131: cc_status.mdep = address;
1132:
1133: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1134: && address == cc_prev_status.mdep
1135: && cc_prev_status.mdep == cc_status.mdep))
1136: {
1137: output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
1138: cc_prev_status.mdep = address;
1139: }
1140:
1141: /* Code below isn't smart enough to do a doubleword in two parts.
1142: So handle that case the slow way. */
1143: if (mode == DImode
1144: && GET_CODE (operands[0]) == REG /* Moving to nonaligned reg pair */
1145: && (REGNO (operands[0]) & 1))
1146: return output_move_double (operands);
1147:
1148: output_sized_memop ("ld", mode);
1149: if (GET_CODE (operands[0]) == REG)
1150: return "[%%g1+%%lo(%m1)],%0";
1151: abort ();
1152: }
1153:
1154: /* Output a floating-point load-from-memory whose operands are OPERANDS[0,1].
1155: OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
1156: We also handle the case where OPERANDS[0] is a mem. */
1157:
1158: char *
1159: output_load_floating (operands)
1160: rtx *operands;
1161: {
1162: enum machine_mode mode = GET_MODE (operands[0]);
1163: rtx address = XEXP (operands[1], 0);
1164:
1165: /* We don't bother trying to see if we know %hi(address).
1166: This is because we are doing a load, and if we know the
1167: %hi value, we probably also know that value in memory. */
1168: cc_status.flags |= CC_KNOW_HI_G1;
1169: cc_status.mdep = address;
1170:
1171: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1172: && address == cc_prev_status.mdep
1173: && cc_prev_status.mdep == cc_status.mdep))
1174: {
1175: output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
1176: cc_prev_status.mdep = address;
1177: }
1178:
1179: if (mode == DFmode)
1180: {
1181: if (REG_P (operands[0]))
1182: {
1183: if (REGNO (operands[0]) & 1)
1184: return output_move_double (operands);
1185: else
1186: return "ldd [%%g1+%%lo(%m1)],%0";
1187: }
1188: cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0);
1189: output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands);
1190: operands[1] = gen_rtx (REG, DFmode, 32);
1191: return output_fp_move_double (operands);
1192: }
1193:
1194: if (GET_CODE (operands[0]) == MEM)
1195: {
1196: cc_status.flags &= ~CC_F1_IS_0;
1197: output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands);
1198: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
1199: {
1200: cc_status.mdep = XEXP (operands[0], 0);
1201: return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]";
1202: }
1203: else
1204: return "st %%f1,%0";
1205: }
1206: return "ld [%%g1+%%lo(%m1)],%0";
1207: }
1208:
1209: /* Load the address specified by OPERANDS[3] into the register
1210: specified by OPERANDS[0].
1211:
1212: OPERANDS[3] may be the result of a sum, hence it could either be:
1213:
1214: (1) CONST
1215: (2) REG
1216: (2) REG + CONST_INT
1217: (3) REG + REG + CONST_INT
1218: (4) REG + REG (special case of 3).
1219:
1220: Note that (3) is not a legitimate address.
1221: All cases are handled here. */
1222:
1223: void
1224: output_load_address (operands)
1225: rtx *operands;
1226: {
1227: rtx base, offset;
1228:
1229: if (CONSTANT_P (operands[3]))
1230: {
1231: output_asm_insn ("set %3,%0", operands);
1232: return;
1233: }
1234:
1235: if (REG_P (operands[3]))
1236: {
1237: if (REGNO (operands[0]) != REGNO (operands[3]))
1238: output_asm_insn ("mov %3,%0", operands);
1239: return;
1240: }
1241:
1242: if (GET_CODE (operands[3]) != PLUS)
1243: abort ();
1244:
1245: base = XEXP (operands[3], 0);
1246: offset = XEXP (operands[3], 1);
1247:
1248: if (GET_CODE (base) == CONST_INT)
1249: {
1250: rtx tmp = base;
1251: base = offset;
1252: offset = tmp;
1253: }
1254:
1255: if (GET_CODE (offset) != CONST_INT)
1256: {
1257: /* Operand is (PLUS (REG) (REG)). */
1258: base = operands[3];
1259: offset = const0_rtx;
1260: }
1261:
1262: if (REG_P (base))
1263: {
1264: operands[6] = base;
1265: operands[7] = offset;
1266: if (SMALL_INT (offset))
1267: output_asm_insn ("add %6,%7,%0", operands);
1268: else
1269: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
1270: }
1271: else if (GET_CODE (base) == PLUS)
1272: {
1273: operands[6] = XEXP (base, 0);
1274: operands[7] = XEXP (base, 1);
1275: operands[8] = offset;
1276:
1277: if (SMALL_INT (offset))
1278: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
1279: else
1280: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
1281: }
1282: else
1283: abort ();
1284: }
1285:
1286: /* Output code to place a size count SIZE in register REG.
1287: ALIGN is the size of the unit of transfer.
1288:
1289: Because block moves are pipelined, we don't include the
1290: first element in the transfer of SIZE to REG. */
1291:
1292: static void
1293: output_size_for_block_move (size, reg, align)
1294: rtx size, reg;
1295: rtx align;
1296: {
1297: rtx xoperands[3];
1298:
1299: xoperands[0] = reg;
1300: xoperands[1] = size;
1301: xoperands[2] = align;
1302: if (GET_CODE (size) == REG)
1303: output_asm_insn ("sub %1,%2,%0", xoperands);
1304: else
1305: {
1306: xoperands[1]
1307: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
1308: cc_status.flags &= ~ CC_KNOW_HI_G1;
1309: output_asm_insn ("set %1,%0", xoperands);
1310: }
1311: }
1312:
1313: /* Emit code to perform a block move.
1314:
1315: OPERANDS[0] is the destination.
1316: OPERANDS[1] is the source.
1317: OPERANDS[2] is the size.
1318: OPERANDS[3] is the alignment safe to use.
1319: OPERANDS[4] is a register we can safely clobber as a temp. */
1320:
1321: char *
1322: output_block_move (operands)
1323: rtx *operands;
1324: {
1325: /* A vector for our computed operands. Note that load_output_address
1326: makes use of (and can clobber) up to the 8th element of this vector. */
1327: rtx xoperands[10];
1328: rtx zoperands[10];
1329: static int movstrsi_label = 0;
1330: int i, j;
1331: rtx temp1 = operands[4];
1332: rtx alignrtx = operands[3];
1333: int align = INTVAL (alignrtx);
1334:
1335: xoperands[0] = operands[0];
1336: xoperands[1] = operands[1];
1337: xoperands[2] = temp1;
1338:
1339: /* We can't move more than four bytes at a time
1340: because we have only one register to move them through. */
1341: if (align > 4)
1342: {
1343: align = 4;
1344: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
1345: }
1346:
1347: /* Since we clobber untold things, nix the condition codes. */
1348: CC_STATUS_INIT;
1349:
1350: /* Recognize special cases of block moves. These occur
1351: when GNU C++ is forced to treat something as BLKmode
1352: to keep it in memory, when its mode could be represented
1353: with something smaller.
1354:
1355: We cannot do this for global variables, since we don't know
1356: what pages they don't cross. Sigh. */
1357: if (GET_CODE (operands[2]) == CONST_INT
1358: && INTVAL (operands[2]) <= 16
1359: && ! CONSTANT_ADDRESS_P (operands[0])
1360: && ! CONSTANT_ADDRESS_P (operands[1]))
1361: {
1362: int size = INTVAL (operands[2]);
1363:
1364: cc_status.flags &= ~CC_KNOW_HI_G1;
1365: if (align == 1)
1366: {
1367: if (memory_address_p (QImode, plus_constant (xoperands[0], size))
1368: && memory_address_p (QImode, plus_constant (xoperands[1], size)))
1369: {
1370: /* We will store different integers into this particular RTX. */
1371: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1372: for (i = size-1; i >= 0; i--)
1373: {
1374: INTVAL (xoperands[2]) = i;
1375: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
1376: xoperands);
1377: }
1378: return "";
1379: }
1380: }
1381: else if (align == 2)
1382: {
1383: if (memory_address_p (HImode, plus_constant (xoperands[0], size))
1384: && memory_address_p (HImode, plus_constant (xoperands[1], size)))
1385: {
1386: /* We will store different integers into this particular RTX. */
1387: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1388: for (i = (size>>1)-1; i >= 0; i--)
1389: {
1390: INTVAL (xoperands[2]) = i<<1;
1391: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
1392: xoperands);
1393: }
1394: return "";
1395: }
1396: }
1397: else
1398: {
1399: if (memory_address_p (SImode, plus_constant (xoperands[0], size))
1400: && memory_address_p (SImode, plus_constant (xoperands[1], size)))
1401: {
1402: /* We will store different integers into this particular RTX. */
1403: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1404: for (i = (size>>2)-1; i >= 0; i--)
1405: {
1406: INTVAL (xoperands[2]) = i<<2;
1407: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
1408: xoperands);
1409: }
1410: return "";
1411: }
1412: }
1413: }
1414:
1415: /* This is the size of the transfer.
1416: Either use the register which already contains the size,
1417: or use a free register (used by no operands).
1418: Also emit code to decrement the size value by ALIGN. */
1419: output_size_for_block_move (operands[2], temp1, alignrtx);
1420:
1421: zoperands[0] = operands[0];
1422: zoperands[3] = plus_constant (operands[0], align);
1423: output_load_address (zoperands);
1424:
1425: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1426: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
1427:
1.1.1.4 ! root 1428: #ifdef NO_UNDERSCORES
! 1429: if (align == 1)
! 1430: output_asm_insn ("\n.Lm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tstb %%g1,[%0+%2]", xoperands);
! 1431: else if (align == 2)
! 1432: output_asm_insn ("\n.Lm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tsth %%g1,[%0+%2]", xoperands);
! 1433: else
! 1434: output_asm_insn ("\n.Lm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tst %%g1,[%0+%2]", xoperands);
! 1435: #else
1.1 root 1436: if (align == 1)
1437: output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands);
1438: else if (align == 2)
1439: output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands);
1440: else
1441: output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands);
1.1.1.4 ! root 1442: #endif
1.1 root 1443: return "";
1444: }
1445:
1446: /* What the sparc lacks in hardware, make up for in software.
1447: Compute a fairly good sequence of shift and add insns
1448: to make a multiply happen. */
1449:
1450: #define ABS(x) ((x) < 0 ? -(x) : x)
1451:
1452: char *
1453: output_mul_by_constant (insn, operands, unsignedp)
1454: rtx insn;
1455: rtx *operands;
1456: int unsignedp;
1457: {
1458: int c; /* Size of constant */
1459: int shifts[BITS_PER_WORD]; /* Table of shifts */
1460: unsigned int p, log; /* A power of two, and its log */
1461: int d1, d2; /* Differences of c and p */
1462: int first = 1; /* True if dst has unknown data in it */
1463: int i;
1464:
1465: CC_STATUS_INIT;
1466:
1467: c = INTVAL (operands[2]);
1468: if (c == 0)
1469: {
1.1.1.2 root 1470: /* Does happen, at least when not optimizing. */
1.1 root 1471: if (GET_CODE (operands[0]) == MEM)
1472: return "st %%g0,%0";
1473: return "mov %%g0,%0";
1474: }
1475:
1476: output_asm_insn ("! start open coded multiply");
1477:
1478: /* Clear out the table of shifts. */
1479: for (i = 0; i < BITS_PER_WORD; ++i)
1480: shifts[i] = 0;
1481:
1482: while (c)
1483: {
1484: /* Find the power of two nearest ABS(c) */
1485: p = 1, log = 0;
1486: do
1487: {
1488: d1 = ABS(c) - p;
1489: p *= 2;
1490: ++log;
1491: }
1492: while (p < ABS(c));
1493: d2 = p - ABS(c);
1494:
1495: /* Make an appropriate entry in shifts for p. */
1496: if (d2 < d1)
1497: {
1498: shifts[log] = c < 0 ? -1 : 1;
1499: c = c < 0 ? d2 : -d2;
1500: }
1501: else
1502: {
1503: shifts[log - 1] = c < 0 ? -1 : 1;
1504: c = c < 0 ? -d1 : d1;
1505: }
1506: }
1507:
1508: /* Take care of the first insn in sequence.
1509: We know we have at least one. */
1510:
1511: /* A value of -1 in shifts says to subtract that power of two, and a value
1512: of 1 says to add that power of two. */
1513: for (i = 0; ; i++)
1514: if (shifts[i])
1515: {
1516: if (i)
1517: {
1518: operands[2] = gen_rtx (CONST_INT, VOIDmode, i);
1519: output_asm_insn ("sll %1,%2,%%g1", operands);
1520: }
1521: else output_asm_insn ("mov %1,%%g1", operands);
1522:
1523: log = i;
1524: if (shifts[i] < 0)
1525: output_asm_insn ("sub %%g0,%%g1,%0", operands);
1526: else
1527: output_asm_insn ("mov %%g1,%0", operands);
1528: break;
1529: }
1530:
1531: /* A value of -1 in shifts says to subtract that power of two, and a value
1532: of 1 says to add that power of two--continued. */
1533: for (i += 1; i < BITS_PER_WORD; ++i)
1534: if (shifts[i])
1535: {
1536: if (i - log > 0)
1537: {
1538: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log);
1539: output_asm_insn ("sll %%g1,%2,%%g1", operands);
1540: }
1541: else
1542: {
1543: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i);
1544: output_asm_insn ("sra %%g1,%2,%%g1", operands);
1545: }
1546: log = i;
1547: if (shifts[i] < 0)
1548: output_asm_insn ("sub %0,%%g1,%0", operands);
1549: else
1550: output_asm_insn ("add %0,%%g1,%0", operands);
1551: }
1552:
1553: output_asm_insn ("! end open coded multiply");
1554:
1555: return "";
1556: }
1557:
1558: char *
1559: output_mul_insn (operands, unsignedp)
1560: rtx *operands;
1561: int unsignedp;
1562: {
1563: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1;
1564: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1;
1565:
1566: CC_STATUS_INIT;
1567:
1568: if (lucky1)
1569: {
1570: if (lucky2)
1571: {
1572: if (REGNO (operands[1]) == REGNO (operands[2]))
1573: {
1574: if (REGNO (operands[1]) == 8)
1575: output_asm_insn ("mov %%o0,%%o1");
1576: else
1577: output_asm_insn ("mov %%o1,%%o0");
1578: }
1579: output_asm_insn ("call .mul,2\n\tnop", operands);
1580: }
1581: else
1582: {
1583: rtx xoperands[2];
1584: xoperands[0] = gen_rtx (REG, SImode,
1585: 8 ^ (REGNO (operands[1]) == 8));
1586: xoperands[1] = operands[2];
1587: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
1588: }
1589: }
1590: else if (lucky2)
1591: {
1592: rtx xoperands[2];
1593: xoperands[0] = gen_rtx (REG, SImode,
1594: 8 ^ (REGNO (operands[2]) == 8));
1595: xoperands[1] = operands[1];
1596: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
1597: }
1598: else
1599: {
1600: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1",
1601: operands);
1602: }
1603:
1604: if (REGNO (operands[0]) == 8)
1605: return "";
1606: return "mov %%o0,%0";
1607: }
1608:
1609: /* Make floating point register f0 contain 0.
1610: SIZE is the number of registers (including f0)
1611: which should contain 0. */
1612:
1613: void
1614: make_f0_contain_0 (size)
1615: int size;
1616: {
1617: if (size == 1)
1618: {
1619: if ((cc_status.flags & (CC_F0_IS_0)) == 0)
1620: output_asm_insn ("ld [%%fp-16],%%f0", 0);
1621: cc_status.flags |= CC_F0_IS_0;
1622: }
1623: else if (size == 2)
1624: {
1625: if ((cc_status.flags & CC_F0_IS_0) == 0)
1626: output_asm_insn ("ld [%%fp-16],%%f0", 0);
1627: if ((cc_status.flags & (CC_F1_IS_0)) == 0)
1628: output_asm_insn ("ld [%%fp-12],%%f1", 0);
1629: cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0;
1630: }
1631: }
1632:
1633: /* Since condition codes don't have logical links, we need to keep
1634: their setting and use together for set-cc insns. */
1635: void
1636: gen_scc_insn (code, mode, operands)
1637: enum rtx_code code;
1638: enum machine_mode mode;
1639: rtx *operands;
1640: {
1641: extern rtx sequence_stack;
1642: rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0);
1643: rtx last_pat;
1644:
1645: /* Skip back over the CLOBBERs that may precede this insn. */
1646: while (last_insn && GET_CODE (last_insn) == INSN
1647: && GET_CODE (PATTERN (last_insn)) == CLOBBER)
1648: last_insn = PREV_INSN (last_insn);
1649: /* We should have found the preceding compare. */
1650: if (last_insn == 0 || GET_CODE (last_insn) != INSN)
1651: abort ();
1652: last_pat = PATTERN (last_insn);
1653: if (GET_CODE (last_pat) != SET
1654: || GET_CODE (SET_DEST (last_pat)) != CC0)
1655: abort ();
1656:
1657: /* Turn off that previous insn, now that we have got the data out of it. */
1658: PUT_CODE (last_insn, NOTE);
1659: NOTE_LINE_NUMBER (last_insn) = NOTE_INSN_DELETED;
1660:
1661: /* Emit one replacement insn to compare operands and store result. */
1662: emit_insn (gen_rtx (SET, VOIDmode, operands[0],
1663: gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx)));
1664: }
1665:
1666: /* Output reasonable peephole for set-on-condition-code insns.
1667: Note that these insns assume a particular way of defining
1668: labels. Therefore, *both* tm-sparc.h and this function must
1669: be changed if a new syntax is needed. */
1670:
1671: char *
1672: output_scc_insn (code, operand)
1673: enum rtx_code code;
1674: rtx operand;
1675: {
1676: rtx xoperands[2];
1677: rtx label = gen_label_rtx ();
1678: int cc_in_fccr = cc_status.flags & CC_IN_FCCR;
1679: int antisymmetric = 0;
1680:
1681: xoperands[0] = operand;
1682: xoperands[1] = label;
1683:
1684: switch (code)
1685: {
1686: case NE:
1687: if (cc_in_fccr)
1688: output_asm_insn ("fbne,a %l0", &label);
1689: else
1690: output_asm_insn ("bne,a %l0", &label);
1691: break;
1692: case EQ:
1693: if (cc_in_fccr)
1694: output_asm_insn ("fbe,a %l0", &label);
1695: else
1696: output_asm_insn ("be,a %l0", &label);
1697: break;
1698: case GE:
1699: if (cc_in_fccr)
1700: output_asm_insn ("fbge,a %l0", &label);
1701: else
1702: output_asm_insn ("bge,a %l0", &label);
1703: antisymmetric = 1;
1704: break;
1705: case GT:
1706: if (cc_in_fccr)
1707: output_asm_insn ("fbg,a %l0", &label);
1708: else
1709: output_asm_insn ("bg,a %l0", &label);
1710: antisymmetric = 1;
1711: break;
1712: case LE:
1713: if (cc_in_fccr)
1714: output_asm_insn ("fble,a %l0", &label);
1715: else
1716: output_asm_insn ("ble,a %l0", &label);
1717: antisymmetric = 1;
1718: break;
1719: case LT:
1720: if (cc_in_fccr)
1721: output_asm_insn ("fbl,a %l0", &label);
1722: else
1723: output_asm_insn ("bl,a %l0", &label);
1724: antisymmetric = 1;
1725: break;
1726: case GEU:
1727: if (cc_in_fccr)
1728: abort ();
1729: else
1730: output_asm_insn ("bgeu,a %l0", &label);
1731: antisymmetric = 1;
1732: break;
1733: case GTU:
1734: if (cc_in_fccr)
1735: abort ();
1736: else
1737: output_asm_insn ("bgu,a %l0", &label);
1738: antisymmetric = 1;
1739: break;
1740: case LEU:
1741: if (cc_in_fccr)
1742: abort ();
1743: else
1744: output_asm_insn ("bleu,a %l0", &label);
1745: antisymmetric = 1;
1746: break;
1747: case LTU:
1748: if (cc_in_fccr)
1749: abort ();
1750: else
1751: output_asm_insn ("blu,a %l0", &label);
1752: antisymmetric = 1;
1753: break;
1754: default:
1755: abort ();
1756: }
1.1.1.3 root 1757:
1.1 root 1758: if (antisymmetric
1759: && (cc_status.flags & CC_REVERSED))
1760: output_asm_insn ("orcc %%g0,0,%0\n\torcc %%g0,1,%0\n%l1:", xoperands);
1761: else
1762: output_asm_insn ("orcc %%g0,1,%0\n\torcc %%g0,0,%0\n%l1:", xoperands);
1.1.1.3 root 1763: cc_status.flags &= ~CC_IN_FCCR;
1764:
1.1 root 1765: return "";
1766: }
1767:
1768: /* Output a delayed branch insn with the delay insn in its
1769: branch slot. The delayed branch insn template is in TEMPLATE,
1770: with operands OPERANDS. The insn in its delay slot is INSN.
1771:
1772: As a special case, since we know that all memory transfers are via
1773: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
1774: reference around the branch as
1775:
1776: sethi %hi(x),%%g1
1777: b ...
1778: ld/st [%g1+%lo(x)],...
1779:
1780: As another special case, we handle loading (SYMBOL_REF ...) and
1781: other large constants around branches as well:
1782:
1783: sethi %hi(x),%0
1784: b ...
1785: or %0,%lo(x),%1
1786:
1787: */
1788:
1789: char *
1790: output_delayed_branch (template, operands, insn)
1791: char *template;
1792: rtx *operands;
1793: rtx insn;
1794: {
1795: extern rtx recog_operand[];
1796: rtx src = XVECEXP (PATTERN (insn), 0, 1);
1797: rtx dest = XVECEXP (PATTERN (insn), 0, 0);
1798:
1799: if (GET_CODE (src) == SYMBOL_REF
1800: || (GET_CODE (src) == CONST_INT
1801: && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0)))
1802: {
1803: rtx xoperands[2];
1804: xoperands[0] = dest;
1805: xoperands[1] = src;
1806:
1807: /* Output the `sethi' insn. */
1808: output_asm_insn ("sethi %%hi(%1),%0", xoperands);
1809:
1810: /* Output the branch instruction next. */
1811: output_asm_insn (template, operands);
1812:
1813: /* Now output the `or' insn. */
1814: output_asm_insn ("or %0,%%lo(%1),%0", xoperands);
1815: }
1816: else if ((GET_CODE (src) == MEM
1817: && CONSTANT_ADDRESS_P (XEXP (src, 0)))
1818: || (GET_CODE (dest) == MEM
1819: && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
1820: {
1821: rtx xoperands[2];
1822: char *split_template;
1823: xoperands[0] = dest;
1824: xoperands[1] = src;
1825:
1826: /* Output the `sethi' insn. */
1827: if (GET_CODE (src) == MEM)
1828: {
1829: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1830: && cc_prev_status.mdep == XEXP (operands[1], 0)))
1831: output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands);
1832: split_template = "ld [%%g1+%%lo(%m1)],%0";
1833: }
1834: else
1835: {
1836: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1837: && cc_prev_status.mdep == XEXP (operands[0], 0)))
1838: output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands);
1839: split_template = "st %r1,[%%g1+%%lo(%m0)]";
1840: }
1841:
1842: /* Output the branch instruction next. */
1843: output_asm_insn (template, operands);
1844:
1845: /* Now output the load or store.
1846: No need to do a CC_STATUS_INIT, because we are branching anyway. */
1847: output_asm_insn (split_template, xoperands);
1848: }
1849: else
1850: {
1851: extern char *insn_template[];
1852: extern char *(*insn_outfun[])();
1853: int insn_code_number;
1854: rtx pat = gen_rtx (SET, VOIDmode, dest, src);
1855: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
1856: int i;
1857: extern rtx alter_subreg();
1858: extern int insn_n_operands[];
1859:
1860: /* Output the branch instruction first. */
1861: output_asm_insn (template, operands);
1862:
1863: /* Now recognize the insn which we put in its delay slot.
1864: We must do this after outputing the branch insn,
1865: since operands may just be a pointer to `recog_operand'. */
1866: insn_code_number = recog (pat, delay_insn);
1867: if (insn_code_number == -1)
1868: abort ();
1869:
1870: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1871: {
1872: if (GET_CODE (recog_operand[i]) == SUBREG)
1873: recog_operand[i] = alter_subreg (recog_operand[i]);
1874: }
1875:
1876: /* Now get the template for what this insn would
1877: have been, without the branch. Its operands are
1878: exactly the same as they would be, so we don't
1879: need to do an insn_extract. */
1880: template = insn_template[insn_code_number];
1881: if (template == 0)
1882: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1883: output_asm_insn (template, recog_operand);
1884: }
1885: CC_STATUS_INIT;
1886: return "";
1887: }
1888:
1889: /* Output a newly constructed insn DELAY_INSN. */
1890: char *
1891: output_delay_insn (delay_insn)
1892: rtx delay_insn;
1893: {
1894: char *template;
1895: extern rtx recog_operand[];
1896: extern char call_used_regs[];
1897: extern char *insn_template[];
1898: extern int insn_n_operands[];
1899: extern char *(*insn_outfun[])();
1900: extern rtx alter_subreg();
1901: int insn_code_number;
1902: extern int insn_n_operands[];
1903: int i;
1904:
1905: /* Now recognize the insn which we put in its delay slot.
1906: We must do this after outputing the branch insn,
1907: since operands may just be a pointer to `recog_operand'. */
1908: insn_code_number = recog_memoized (delay_insn);
1909: if (insn_code_number == -1)
1910: abort ();
1911:
1912: /* Extract the operands of this delay insn. */
1913: INSN_CODE (delay_insn) = insn_code_number;
1914: insn_extract (delay_insn);
1915:
1916: /* It is possible that this insn has not been properly scaned by final
1917: yet. If this insn's operands don't appear in the peephole's
1918: actual operands, then they won't be fixed up by final, so we
1919: make sure they get fixed up here. -- This is a kludge. */
1920: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1921: {
1922: if (GET_CODE (recog_operand[i]) == SUBREG)
1923: recog_operand[i] = alter_subreg (recog_operand[i]);
1924: }
1925:
1926: #ifdef REGISTER_CONSTRAINTS
1927: if (! constrain_operands (insn_code_number))
1928: abort ();
1929: #endif
1930:
1931: cc_prev_status = cc_status;
1932:
1933: /* Update `cc_status' for this instruction.
1934: The instruction's output routine may change it further.
1935: If the output routine for a jump insn needs to depend
1936: on the cc status, it should look at cc_prev_status. */
1937:
1938: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
1939:
1940: /* Now get the template for what this insn would
1941: have been, without the branch. */
1942:
1943: template = insn_template[insn_code_number];
1944: if (template == 0)
1945: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1946: output_asm_insn (template, recog_operand);
1947: return "";
1948: }
1949:
1950: /* Output the insn HEAD, keeping OPERANDS protected (wherever they are).
1951: HEAD comes from the target of some branch, so before we output it,
1952: we delete it from the target, lest we execute it twice. The caller
1953: of this function promises that such code motion is permissable. */
1954: char *
1955: output_eager_then_insn (head, operands)
1956: rtx head;
1957: rtx *operands;
1958: {
1959: extern rtx alter_subreg ();
1960: extern int insn_n_operands[];
1961: extern rtx recog_operand[];
1962: rtx xoperands[MAX_RECOG_OPERANDS];
1963: int insn_code_number, i, nbytes;
1964: rtx nhead;
1965:
1966: /* Micro-hack: run peephole on head if it looks like a good idea.
1967: Right now there's only one such case worth doing...
1968:
1969: This could be made smarter if the peephole for ``2-insn combine''
1970: were also made smarter. */
1971: if (GET_CODE (PATTERN (head)) == SET
1972: && REG_P (SET_SRC (PATTERN (head)))
1973: && REG_P (SET_DEST (PATTERN (head)))
1974: && (nhead = next_real_insn_no_labels (head))
1975: && GET_CODE (nhead) == INSN
1976: && GET_CODE (PATTERN (nhead)) == SET
1977: && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0
1978: && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head))
1979: || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head))))
1980: /* Something's wrong if this does not fly. */
1981: if (! peephole (head))
1982: abort ();
1983:
1984: /* Save our contents of `operands', since output_delay_insn sets them. */
1985: insn_code_number = recog_memoized (head);
1986: nbytes = insn_n_operands[insn_code_number] * sizeof (rtx);
1987: bcopy (operands, xoperands, nbytes);
1988:
1989: /* Output the delay insn, and prevent duplication later. */
1990: delete_insn (head);
1991: output_delay_insn (head);
1992:
1993: /* Restore this insn's operands. */
1994: bcopy (xoperands, operands, nbytes);
1995: }
1996:
1997: /* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL;
1998: or 0, if there is none. Also return 0 if we cross a label. */
1999:
2000: rtx
2001: next_real_insn_no_labels (label)
2002: rtx label;
2003: {
2004: register rtx insn = NEXT_INSN (label);
2005: register RTX_CODE code;
2006:
2007: while (insn)
2008: {
2009: code = GET_CODE (insn);
2010: if (code == INSN)
2011: {
2012: if (GET_CODE (PATTERN (insn)) != CLOBBER
2013: && GET_CODE (PATTERN (insn)) != USE)
2014: return insn;
2015: }
2016: if (code == CALL_INSN || code == JUMP_INSN)
2017: return insn;
2018: if (code == CODE_LABEL)
2019: return 0;
2020: insn = NEXT_INSN (insn);
2021: }
2022:
2023: return 0;
2024: }
2025:
2026: int
2027: operands_satisfy_eager_branch_peephole (operands, conditional)
2028: rtx *operands;
2029: int conditional;
2030: {
2031: rtx label;
2032:
2033: if (conditional)
2034: {
2035: if (GET_CODE (operands[0]) != IF_THEN_ELSE)
2036: return 0;
2037:
2038: if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF)
2039: label = XEXP (XEXP (operands[0], 1), 0);
2040: else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF)
2041: label = XEXP (XEXP (operands[0], 2), 0);
2042: else return 0;
2043: }
2044: else
2045: {
2046: label = operands[0];
2047: }
2048:
2049: if (LABEL_NUSES (label) == 1)
2050: {
2051: rtx prev = PREV_INSN (label);
2052: while (prev && GET_CODE (prev) == NOTE)
2053: prev = PREV_INSN (prev);
2054: if (prev == 0
2055: || GET_CODE (prev) == BARRIER)
2056: {
2057: rtx head = next_real_insn_no_labels (label);
2058:
2059: if (head
2060: && ! INSN_DELETED_P (head)
2061: && GET_CODE (head) == INSN
2062: && GET_CODE (PATTERN (head)) == SET
2063: && strict_single_insn_op_p (SET_SRC (PATTERN (head)),
2064: GET_MODE (SET_DEST (PATTERN (head))))
2065: && strict_single_insn_op_p (SET_DEST (PATTERN (head)),
1.1.1.2 root 2066: GET_MODE (SET_DEST (PATTERN (head))))
2067: /* Moves between FP regs and CPU regs are two insns. */
2068: && !(GET_CODE (SET_SRC (PATTERN (head))) == REG
2069: && GET_CODE (SET_DEST (PATTERN (head))) == REG
2070: && (FP_REG_P (SET_SRC (PATTERN (head)))
2071: != FP_REG_P (SET_DEST (PATTERN (head))))))
1.1 root 2072: {
2073: if (conditional == 2)
2074: return (GET_CODE (operands[1]) != PC
2075: && safe_insn_src_p (operands[2], VOIDmode)
2076: && strict_single_insn_op_p (operands[2], VOIDmode)
2077: && operand_clobbered_before_used_after (operands[1], label));
2078: return 1;
2079: }
2080: }
2081: }
2082:
2083: if (conditional == 1
2084: && GET_CODE (operands[1]) != PC
2085: && safe_insn_src_p (operands[2], VOIDmode)
2086: && strict_single_insn_op_p (operands[2], VOIDmode)
2087: && operand_clobbered_before_used_after (operands[1], label))
2088: return 1;
2089:
2090: return 0;
2091: }
2092:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.