|
|
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: {
! 910: rtx inc_reg = XEXP (XEXP (operands[1], 0), 0);
! 911: if (inc_reg == frame_pointer_rtx
! 912: && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == REG
! 913: && XEXP (XEXP (operands[1], 0), 0) != frame_pointer_rtx)
! 914: inc_reg = XEXP (XEXP (operands[1], 0), 1);
! 915: if (inc_reg == frame_pointer_rtx)
! 916: {
! 917: output_asm_insn ("mov %%fp,%%g1", xoperands);
! 918: inc_reg = gen_rtx (REG, SImode, 1);
! 919: }
! 920: xoperands[1] = inc_reg;
! 921: output_asm_insn ("add 4,%1,%1", xoperands);
! 922: xoperands[1] = operands[1];
! 923: output_asm_insn ("ld %1,%0", xoperands);
! 924: xoperands[1] = inc_reg;
! 925: output_asm_insn ("add -4,%1,%1", xoperands);
! 926: }
! 927: else
! 928: {
! 929: xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]),
1.1.1.2 root 930: plus_constant (XEXP (operands[1], 0), 4));
1.1.1.3 ! root 931: output_asm_insn ("ld %1,%0", xoperands);
! 932: }
1.1.1.2 root 933: return "";
934: }
1.1 root 935: }
936: else if (FP_REG_P (operands[1]))
937: {
938: if (GET_CODE (operands[0]) == REG)
939: {
940: if ((REGNO (operands[0]) & 1) == 0)
941: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
942: else
943: {
944: rtx xoperands[3];
945: xoperands[2] = operands[1];
946: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
947: xoperands[0] = operands[0];
948: output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);
949: return "";
950: }
951: }
952: /* Use std if we can be sure it is well-aligned. */
953: if (GET_CODE (XEXP (operands[0], 0)) == PLUS
954: && (((XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx
955: || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx)
956: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT
957: && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) == 0)
1.1.1.3 ! root 958: #if 0 /* An array in a structure that is a parm need not be aligned! */
1.1 root 959: /* Arrays are known to be aligned,
960: and reg+reg addresses are used (on this machine)
961: only for array accesses. */
962: || (REG_P (XEXP (XEXP (operands[0], 0), 0))
1.1.1.3 ! root 963: && REG_P (XEXP (XEXP (operands[0], 0), 1)))
! 964: #endif
! 965: ))
1.1 root 966: return "std %1,%0";
967: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
968: {
969: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
970: && cc_prev_status.mdep == XEXP (operands[0], 0)))
971: output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
972: cc_status.flags |= CC_KNOW_HI_G1;
973: cc_status.mdep = XEXP (operands[0], 0);
974: return "std %1,[%%lo(%m0)+%%g1]";
975: }
976: /* Otherwise use two st insns. */
977: {
978: rtx xoperands[2];
979: output_asm_insn ("st %r1,%0", operands);
980: xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]),
981: REGNO (operands[1]) + 1);
1.1.1.3 ! root 982: if (GET_CODE (XEXP (operands[0], 0)) == PLUS
! 983: && offsettable_address_p (1, GET_MODE (operands[0]),
! 984: XEXP (operands[0], 0)))
! 985: {
! 986: xoperands[0] = adj_offsettable_operand (operands[0], 4);
! 987: output_asm_insn ("st %r1,%0", xoperands);
! 988: }
! 989: else if (GET_CODE (XEXP (operands[0], 0)) == PLUS)
! 990: {
! 991: rtx inc_reg = XEXP (XEXP (operands[0], 0), 0);
! 992: if (inc_reg == frame_pointer_rtx
! 993: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG
! 994: && XEXP (XEXP (operands[0], 0), 0) != frame_pointer_rtx)
! 995: inc_reg = XEXP (XEXP (operands[0], 0), 1);
! 996: if (inc_reg == frame_pointer_rtx)
! 997: {
! 998: output_asm_insn ("mov %%fp,%%g1", xoperands);
! 999: inc_reg = gen_rtx (REG, SImode, 1);
! 1000: }
! 1001: xoperands[0] = inc_reg;
! 1002: output_asm_insn ("add 4,%0,%0", xoperands);
! 1003: xoperands[0] = operands[0];
! 1004: output_asm_insn ("st %r1,%0", xoperands);
! 1005: xoperands[0] = inc_reg;
! 1006: output_asm_insn ("add -4,%0,%0", xoperands);
! 1007: }
! 1008: else
! 1009: {
! 1010: xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]),
1.1 root 1011: plus_constant (XEXP (operands[0], 0), 4));
1.1.1.3 ! root 1012: output_asm_insn ("st %r1,%0", xoperands);
! 1013: }
1.1 root 1014: return "";
1015: }
1016: }
1017: else abort ();
1018: }
1019:
1020: /* Return a REG that occurs in ADDR with coefficient 1.
1021: ADDR can be effectively incremented by incrementing REG. */
1022:
1023: static rtx
1024: find_addr_reg (addr)
1025: rtx addr;
1026: {
1027: while (GET_CODE (addr) == PLUS)
1028: {
1.1.1.3 ! root 1029: if (GET_CODE (XEXP (addr, 0)) == REG
! 1030: && !(GET_CODE (XEXP (addr, 1)) == REG
! 1031: && XEXP (addr, 0) == frame_pointer_rtx))
1.1 root 1032: addr = XEXP (addr, 0);
1033: else if (GET_CODE (XEXP (addr, 1)) == REG)
1034: addr = XEXP (addr, 1);
1035: else if (CONSTANT_P (XEXP (addr, 0)))
1036: addr = XEXP (addr, 1);
1037: else if (CONSTANT_P (XEXP (addr, 1)))
1038: addr = XEXP (addr, 0);
1039: else
1040: abort ();
1041: }
1042: if (GET_CODE (addr) == REG)
1043: return addr;
1044: abort ();
1045: }
1046:
1047: void
1048: output_sized_memop (opname, mode)
1049: char *opname;
1050: enum machine_mode mode;
1051: {
1052: extern struct _iobuf *asm_out_file;
1053:
1054: static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" };
1055: static char *st_size_suffix[] = { "b", "h", "", "?", "d" };
1056: char *modename
1057: = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1];
1058:
1059: fprintf (asm_out_file, "\t%s%s", opname, modename);
1060: }
1061:
1062: /* Output a store-in-memory whose operands are OPERANDS[0,1].
1063: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. */
1064:
1065: char *
1066: output_store (operands)
1067: rtx *operands;
1068: {
1069: enum machine_mode mode = GET_MODE (operands[0]);
1070: rtx address = XEXP (operands[0], 0);
1071:
1072: cc_status.flags |= CC_KNOW_HI_G1;
1073: cc_status.mdep = address;
1074:
1075: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1076: && address == cc_prev_status.mdep))
1077: {
1078: output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
1079: cc_prev_status.mdep = address;
1080: }
1081:
1082: /* Store zero in two parts when appropriate. */
1083: if (mode == DFmode && operands[1] == dconst0_rtx)
1084: {
1085: /* We can't cross a page boundary here because the
1086: SYMBOL_REF must be double word aligned, and for this
1087: to be the case, SYMBOL_REF+4 cannot cross. */
1088: output_sized_memop ("st", SImode);
1089: output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands);
1090: output_sized_memop ("st", SImode);
1091: return "%r1,[%%g1+%%lo(%m0)+4]";
1092: }
1093:
1094: /* Code below isn't smart enough to move a doubleword in two parts,
1095: so use output_move_double to do that in the cases that require it. */
1096: if ((mode == DImode || mode == DFmode)
1097: && (GET_CODE (operands[1]) == REG
1098: && (REGNO (operands[1]) & 1)))
1099: return output_move_double (operands);
1100:
1101: output_sized_memop ("st", mode);
1102: return "%r1,[%%g1+%%lo(%m0)]";
1103: }
1104:
1105: /* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1].
1106: OPERANDS[0] is a reg, and OPERANDS[1] is a mem. */
1107:
1108: char *
1109: output_load_fixed (operands)
1110: rtx *operands;
1111: {
1112: enum machine_mode mode = GET_MODE (operands[0]);
1113: rtx address = XEXP (operands[1], 0);
1114:
1115: /* We don't bother trying to see if we know %hi(address).
1116: This is because we are doing a load, and if we know the
1117: %hi value, we probably also know that value in memory. */
1118: cc_status.flags |= CC_KNOW_HI_G1;
1119: cc_status.mdep = address;
1120:
1121: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1122: && address == cc_prev_status.mdep
1123: && cc_prev_status.mdep == cc_status.mdep))
1124: {
1125: output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
1126: cc_prev_status.mdep = address;
1127: }
1128:
1129: /* Code below isn't smart enough to do a doubleword in two parts.
1130: So handle that case the slow way. */
1131: if (mode == DImode
1132: && GET_CODE (operands[0]) == REG /* Moving to nonaligned reg pair */
1133: && (REGNO (operands[0]) & 1))
1134: return output_move_double (operands);
1135:
1136: output_sized_memop ("ld", mode);
1137: if (GET_CODE (operands[0]) == REG)
1138: return "[%%g1+%%lo(%m1)],%0";
1139: abort ();
1140: }
1141:
1142: /* Output a floating-point load-from-memory whose operands are OPERANDS[0,1].
1143: OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
1144: We also handle the case where OPERANDS[0] is a mem. */
1145:
1146: char *
1147: output_load_floating (operands)
1148: rtx *operands;
1149: {
1150: enum machine_mode mode = GET_MODE (operands[0]);
1151: rtx address = XEXP (operands[1], 0);
1152:
1153: /* We don't bother trying to see if we know %hi(address).
1154: This is because we are doing a load, and if we know the
1155: %hi value, we probably also know that value in memory. */
1156: cc_status.flags |= CC_KNOW_HI_G1;
1157: cc_status.mdep = address;
1158:
1159: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1160: && address == cc_prev_status.mdep
1161: && cc_prev_status.mdep == cc_status.mdep))
1162: {
1163: output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
1164: cc_prev_status.mdep = address;
1165: }
1166:
1167: if (mode == DFmode)
1168: {
1169: if (REG_P (operands[0]))
1170: {
1171: if (REGNO (operands[0]) & 1)
1172: return output_move_double (operands);
1173: else
1174: return "ldd [%%g1+%%lo(%m1)],%0";
1175: }
1176: cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0);
1177: output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands);
1178: operands[1] = gen_rtx (REG, DFmode, 32);
1179: return output_fp_move_double (operands);
1180: }
1181:
1182: if (GET_CODE (operands[0]) == MEM)
1183: {
1184: cc_status.flags &= ~CC_F1_IS_0;
1185: output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands);
1186: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
1187: {
1188: cc_status.mdep = XEXP (operands[0], 0);
1189: return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]";
1190: }
1191: else
1192: return "st %%f1,%0";
1193: }
1194: return "ld [%%g1+%%lo(%m1)],%0";
1195: }
1196:
1197: /* Load the address specified by OPERANDS[3] into the register
1198: specified by OPERANDS[0].
1199:
1200: OPERANDS[3] may be the result of a sum, hence it could either be:
1201:
1202: (1) CONST
1203: (2) REG
1204: (2) REG + CONST_INT
1205: (3) REG + REG + CONST_INT
1206: (4) REG + REG (special case of 3).
1207:
1208: Note that (3) is not a legitimate address.
1209: All cases are handled here. */
1210:
1211: void
1212: output_load_address (operands)
1213: rtx *operands;
1214: {
1215: rtx base, offset;
1216:
1217: if (CONSTANT_P (operands[3]))
1218: {
1219: output_asm_insn ("set %3,%0", operands);
1220: return;
1221: }
1222:
1223: if (REG_P (operands[3]))
1224: {
1225: if (REGNO (operands[0]) != REGNO (operands[3]))
1226: output_asm_insn ("mov %3,%0", operands);
1227: return;
1228: }
1229:
1230: if (GET_CODE (operands[3]) != PLUS)
1231: abort ();
1232:
1233: base = XEXP (operands[3], 0);
1234: offset = XEXP (operands[3], 1);
1235:
1236: if (GET_CODE (base) == CONST_INT)
1237: {
1238: rtx tmp = base;
1239: base = offset;
1240: offset = tmp;
1241: }
1242:
1243: if (GET_CODE (offset) != CONST_INT)
1244: {
1245: /* Operand is (PLUS (REG) (REG)). */
1246: base = operands[3];
1247: offset = const0_rtx;
1248: }
1249:
1250: if (REG_P (base))
1251: {
1252: operands[6] = base;
1253: operands[7] = offset;
1254: if (SMALL_INT (offset))
1255: output_asm_insn ("add %6,%7,%0", operands);
1256: else
1257: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
1258: }
1259: else if (GET_CODE (base) == PLUS)
1260: {
1261: operands[6] = XEXP (base, 0);
1262: operands[7] = XEXP (base, 1);
1263: operands[8] = offset;
1264:
1265: if (SMALL_INT (offset))
1266: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
1267: else
1268: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
1269: }
1270: else
1271: abort ();
1272: }
1273:
1274: /* Output code to place a size count SIZE in register REG.
1275: ALIGN is the size of the unit of transfer.
1276:
1277: Because block moves are pipelined, we don't include the
1278: first element in the transfer of SIZE to REG. */
1279:
1280: static void
1281: output_size_for_block_move (size, reg, align)
1282: rtx size, reg;
1283: rtx align;
1284: {
1285: rtx xoperands[3];
1286:
1287: xoperands[0] = reg;
1288: xoperands[1] = size;
1289: xoperands[2] = align;
1290: if (GET_CODE (size) == REG)
1291: output_asm_insn ("sub %1,%2,%0", xoperands);
1292: else
1293: {
1294: xoperands[1]
1295: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
1296: cc_status.flags &= ~ CC_KNOW_HI_G1;
1297: output_asm_insn ("set %1,%0", xoperands);
1298: }
1299: }
1300:
1301: /* Emit code to perform a block move.
1302:
1303: OPERANDS[0] is the destination.
1304: OPERANDS[1] is the source.
1305: OPERANDS[2] is the size.
1306: OPERANDS[3] is the alignment safe to use.
1307: OPERANDS[4] is a register we can safely clobber as a temp. */
1308:
1309: char *
1310: output_block_move (operands)
1311: rtx *operands;
1312: {
1313: /* A vector for our computed operands. Note that load_output_address
1314: makes use of (and can clobber) up to the 8th element of this vector. */
1315: rtx xoperands[10];
1316: rtx zoperands[10];
1317: static int movstrsi_label = 0;
1318: int i, j;
1319: rtx temp1 = operands[4];
1320: rtx alignrtx = operands[3];
1321: int align = INTVAL (alignrtx);
1322:
1323: xoperands[0] = operands[0];
1324: xoperands[1] = operands[1];
1325: xoperands[2] = temp1;
1326:
1327: /* We can't move more than four bytes at a time
1328: because we have only one register to move them through. */
1329: if (align > 4)
1330: {
1331: align = 4;
1332: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
1333: }
1334:
1335: /* Since we clobber untold things, nix the condition codes. */
1336: CC_STATUS_INIT;
1337:
1338: /* Recognize special cases of block moves. These occur
1339: when GNU C++ is forced to treat something as BLKmode
1340: to keep it in memory, when its mode could be represented
1341: with something smaller.
1342:
1343: We cannot do this for global variables, since we don't know
1344: what pages they don't cross. Sigh. */
1345: if (GET_CODE (operands[2]) == CONST_INT
1346: && INTVAL (operands[2]) <= 16
1347: && ! CONSTANT_ADDRESS_P (operands[0])
1348: && ! CONSTANT_ADDRESS_P (operands[1]))
1349: {
1350: int size = INTVAL (operands[2]);
1351:
1352: cc_status.flags &= ~CC_KNOW_HI_G1;
1353: if (align == 1)
1354: {
1355: if (memory_address_p (QImode, plus_constant (xoperands[0], size))
1356: && memory_address_p (QImode, plus_constant (xoperands[1], size)))
1357: {
1358: /* We will store different integers into this particular RTX. */
1359: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1360: for (i = size-1; i >= 0; i--)
1361: {
1362: INTVAL (xoperands[2]) = i;
1363: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
1364: xoperands);
1365: }
1366: return "";
1367: }
1368: }
1369: else if (align == 2)
1370: {
1371: if (memory_address_p (HImode, plus_constant (xoperands[0], size))
1372: && memory_address_p (HImode, plus_constant (xoperands[1], size)))
1373: {
1374: /* We will store different integers into this particular RTX. */
1375: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1376: for (i = (size>>1)-1; i >= 0; i--)
1377: {
1378: INTVAL (xoperands[2]) = i<<1;
1379: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
1380: xoperands);
1381: }
1382: return "";
1383: }
1384: }
1385: else
1386: {
1387: if (memory_address_p (SImode, plus_constant (xoperands[0], size))
1388: && memory_address_p (SImode, plus_constant (xoperands[1], size)))
1389: {
1390: /* We will store different integers into this particular RTX. */
1391: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1392: for (i = (size>>2)-1; i >= 0; i--)
1393: {
1394: INTVAL (xoperands[2]) = i<<2;
1395: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
1396: xoperands);
1397: }
1398: return "";
1399: }
1400: }
1401: }
1402:
1403: /* This is the size of the transfer.
1404: Either use the register which already contains the size,
1405: or use a free register (used by no operands).
1406: Also emit code to decrement the size value by ALIGN. */
1407: output_size_for_block_move (operands[2], temp1, alignrtx);
1408:
1409: zoperands[0] = operands[0];
1410: zoperands[3] = plus_constant (operands[0], align);
1411: output_load_address (zoperands);
1412:
1413: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1414: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
1415:
1416: if (align == 1)
1417: 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);
1418: else if (align == 2)
1419: 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);
1420: else
1421: 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);
1422: return "";
1423: }
1424:
1425: /* What the sparc lacks in hardware, make up for in software.
1426: Compute a fairly good sequence of shift and add insns
1427: to make a multiply happen. */
1428:
1429: #define ABS(x) ((x) < 0 ? -(x) : x)
1430:
1431: char *
1432: output_mul_by_constant (insn, operands, unsignedp)
1433: rtx insn;
1434: rtx *operands;
1435: int unsignedp;
1436: {
1437: int c; /* Size of constant */
1438: int shifts[BITS_PER_WORD]; /* Table of shifts */
1439: unsigned int p, log; /* A power of two, and its log */
1440: int d1, d2; /* Differences of c and p */
1441: int first = 1; /* True if dst has unknown data in it */
1442: int i;
1443:
1444: CC_STATUS_INIT;
1445:
1446: c = INTVAL (operands[2]);
1447: if (c == 0)
1448: {
1.1.1.2 root 1449: /* Does happen, at least when not optimizing. */
1.1 root 1450: if (GET_CODE (operands[0]) == MEM)
1451: return "st %%g0,%0";
1452: return "mov %%g0,%0";
1453: }
1454:
1455: output_asm_insn ("! start open coded multiply");
1456:
1457: /* Clear out the table of shifts. */
1458: for (i = 0; i < BITS_PER_WORD; ++i)
1459: shifts[i] = 0;
1460:
1461: while (c)
1462: {
1463: /* Find the power of two nearest ABS(c) */
1464: p = 1, log = 0;
1465: do
1466: {
1467: d1 = ABS(c) - p;
1468: p *= 2;
1469: ++log;
1470: }
1471: while (p < ABS(c));
1472: d2 = p - ABS(c);
1473:
1474: /* Make an appropriate entry in shifts for p. */
1475: if (d2 < d1)
1476: {
1477: shifts[log] = c < 0 ? -1 : 1;
1478: c = c < 0 ? d2 : -d2;
1479: }
1480: else
1481: {
1482: shifts[log - 1] = c < 0 ? -1 : 1;
1483: c = c < 0 ? -d1 : d1;
1484: }
1485: }
1486:
1487: /* Take care of the first insn in sequence.
1488: We know we have at least one. */
1489:
1490: /* A value of -1 in shifts says to subtract that power of two, and a value
1491: of 1 says to add that power of two. */
1492: for (i = 0; ; i++)
1493: if (shifts[i])
1494: {
1495: if (i)
1496: {
1497: operands[2] = gen_rtx (CONST_INT, VOIDmode, i);
1498: output_asm_insn ("sll %1,%2,%%g1", operands);
1499: }
1500: else output_asm_insn ("mov %1,%%g1", operands);
1501:
1502: log = i;
1503: if (shifts[i] < 0)
1504: output_asm_insn ("sub %%g0,%%g1,%0", operands);
1505: else
1506: output_asm_insn ("mov %%g1,%0", operands);
1507: break;
1508: }
1509:
1510: /* A value of -1 in shifts says to subtract that power of two, and a value
1511: of 1 says to add that power of two--continued. */
1512: for (i += 1; i < BITS_PER_WORD; ++i)
1513: if (shifts[i])
1514: {
1515: if (i - log > 0)
1516: {
1517: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log);
1518: output_asm_insn ("sll %%g1,%2,%%g1", operands);
1519: }
1520: else
1521: {
1522: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i);
1523: output_asm_insn ("sra %%g1,%2,%%g1", operands);
1524: }
1525: log = i;
1526: if (shifts[i] < 0)
1527: output_asm_insn ("sub %0,%%g1,%0", operands);
1528: else
1529: output_asm_insn ("add %0,%%g1,%0", operands);
1530: }
1531:
1532: output_asm_insn ("! end open coded multiply");
1533:
1534: return "";
1535: }
1536:
1537: char *
1538: output_mul_insn (operands, unsignedp)
1539: rtx *operands;
1540: int unsignedp;
1541: {
1542: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1;
1543: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1;
1544:
1545: CC_STATUS_INIT;
1546:
1547: if (lucky1)
1548: {
1549: if (lucky2)
1550: {
1551: if (REGNO (operands[1]) == REGNO (operands[2]))
1552: {
1553: if (REGNO (operands[1]) == 8)
1554: output_asm_insn ("mov %%o0,%%o1");
1555: else
1556: output_asm_insn ("mov %%o1,%%o0");
1557: }
1558: output_asm_insn ("call .mul,2\n\tnop", operands);
1559: }
1560: else
1561: {
1562: rtx xoperands[2];
1563: xoperands[0] = gen_rtx (REG, SImode,
1564: 8 ^ (REGNO (operands[1]) == 8));
1565: xoperands[1] = operands[2];
1566: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
1567: }
1568: }
1569: else if (lucky2)
1570: {
1571: rtx xoperands[2];
1572: xoperands[0] = gen_rtx (REG, SImode,
1573: 8 ^ (REGNO (operands[2]) == 8));
1574: xoperands[1] = operands[1];
1575: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
1576: }
1577: else
1578: {
1579: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1",
1580: operands);
1581: }
1582:
1583: if (REGNO (operands[0]) == 8)
1584: return "";
1585: return "mov %%o0,%0";
1586: }
1587:
1588: /* Make floating point register f0 contain 0.
1589: SIZE is the number of registers (including f0)
1590: which should contain 0. */
1591:
1592: void
1593: make_f0_contain_0 (size)
1594: int size;
1595: {
1596: if (size == 1)
1597: {
1598: if ((cc_status.flags & (CC_F0_IS_0)) == 0)
1599: output_asm_insn ("ld [%%fp-16],%%f0", 0);
1600: cc_status.flags |= CC_F0_IS_0;
1601: }
1602: else if (size == 2)
1603: {
1604: if ((cc_status.flags & CC_F0_IS_0) == 0)
1605: output_asm_insn ("ld [%%fp-16],%%f0", 0);
1606: if ((cc_status.flags & (CC_F1_IS_0)) == 0)
1607: output_asm_insn ("ld [%%fp-12],%%f1", 0);
1608: cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0;
1609: }
1610: }
1611:
1612: /* Since condition codes don't have logical links, we need to keep
1613: their setting and use together for set-cc insns. */
1614: void
1615: gen_scc_insn (code, mode, operands)
1616: enum rtx_code code;
1617: enum machine_mode mode;
1618: rtx *operands;
1619: {
1620: extern rtx sequence_stack;
1621: rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0);
1622: rtx last_pat;
1623:
1624: /* Skip back over the CLOBBERs that may precede this insn. */
1625: while (last_insn && GET_CODE (last_insn) == INSN
1626: && GET_CODE (PATTERN (last_insn)) == CLOBBER)
1627: last_insn = PREV_INSN (last_insn);
1628: /* We should have found the preceding compare. */
1629: if (last_insn == 0 || GET_CODE (last_insn) != INSN)
1630: abort ();
1631: last_pat = PATTERN (last_insn);
1632: if (GET_CODE (last_pat) != SET
1633: || GET_CODE (SET_DEST (last_pat)) != CC0)
1634: abort ();
1635:
1636: /* Turn off that previous insn, now that we have got the data out of it. */
1637: PUT_CODE (last_insn, NOTE);
1638: NOTE_LINE_NUMBER (last_insn) = NOTE_INSN_DELETED;
1639:
1640: /* Emit one replacement insn to compare operands and store result. */
1641: emit_insn (gen_rtx (SET, VOIDmode, operands[0],
1642: gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx)));
1643: }
1644:
1645: /* Output reasonable peephole for set-on-condition-code insns.
1646: Note that these insns assume a particular way of defining
1647: labels. Therefore, *both* tm-sparc.h and this function must
1648: be changed if a new syntax is needed. */
1649:
1650: char *
1651: output_scc_insn (code, operand)
1652: enum rtx_code code;
1653: rtx operand;
1654: {
1655: rtx xoperands[2];
1656: rtx label = gen_label_rtx ();
1657: int cc_in_fccr = cc_status.flags & CC_IN_FCCR;
1658: int antisymmetric = 0;
1659:
1660: xoperands[0] = operand;
1661: xoperands[1] = label;
1662:
1663: switch (code)
1664: {
1665: case NE:
1666: if (cc_in_fccr)
1667: output_asm_insn ("fbne,a %l0", &label);
1668: else
1669: output_asm_insn ("bne,a %l0", &label);
1670: break;
1671: case EQ:
1672: if (cc_in_fccr)
1673: output_asm_insn ("fbe,a %l0", &label);
1674: else
1675: output_asm_insn ("be,a %l0", &label);
1676: break;
1677: case GE:
1678: if (cc_in_fccr)
1679: output_asm_insn ("fbge,a %l0", &label);
1680: else
1681: output_asm_insn ("bge,a %l0", &label);
1682: antisymmetric = 1;
1683: break;
1684: case GT:
1685: if (cc_in_fccr)
1686: output_asm_insn ("fbg,a %l0", &label);
1687: else
1688: output_asm_insn ("bg,a %l0", &label);
1689: antisymmetric = 1;
1690: break;
1691: case LE:
1692: if (cc_in_fccr)
1693: output_asm_insn ("fble,a %l0", &label);
1694: else
1695: output_asm_insn ("ble,a %l0", &label);
1696: antisymmetric = 1;
1697: break;
1698: case LT:
1699: if (cc_in_fccr)
1700: output_asm_insn ("fbl,a %l0", &label);
1701: else
1702: output_asm_insn ("bl,a %l0", &label);
1703: antisymmetric = 1;
1704: break;
1705: case GEU:
1706: if (cc_in_fccr)
1707: abort ();
1708: else
1709: output_asm_insn ("bgeu,a %l0", &label);
1710: antisymmetric = 1;
1711: break;
1712: case GTU:
1713: if (cc_in_fccr)
1714: abort ();
1715: else
1716: output_asm_insn ("bgu,a %l0", &label);
1717: antisymmetric = 1;
1718: break;
1719: case LEU:
1720: if (cc_in_fccr)
1721: abort ();
1722: else
1723: output_asm_insn ("bleu,a %l0", &label);
1724: antisymmetric = 1;
1725: break;
1726: case LTU:
1727: if (cc_in_fccr)
1728: abort ();
1729: else
1730: output_asm_insn ("blu,a %l0", &label);
1731: antisymmetric = 1;
1732: break;
1733: default:
1734: abort ();
1735: }
1.1.1.3 ! root 1736:
1.1 root 1737: if (antisymmetric
1738: && (cc_status.flags & CC_REVERSED))
1739: output_asm_insn ("orcc %%g0,0,%0\n\torcc %%g0,1,%0\n%l1:", xoperands);
1740: else
1741: output_asm_insn ("orcc %%g0,1,%0\n\torcc %%g0,0,%0\n%l1:", xoperands);
1.1.1.3 ! root 1742: cc_status.flags &= ~CC_IN_FCCR;
! 1743:
1.1 root 1744: return "";
1745: }
1746:
1747: /* Output a delayed branch insn with the delay insn in its
1748: branch slot. The delayed branch insn template is in TEMPLATE,
1749: with operands OPERANDS. The insn in its delay slot is INSN.
1750:
1751: As a special case, since we know that all memory transfers are via
1752: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
1753: reference around the branch as
1754:
1755: sethi %hi(x),%%g1
1756: b ...
1757: ld/st [%g1+%lo(x)],...
1758:
1759: As another special case, we handle loading (SYMBOL_REF ...) and
1760: other large constants around branches as well:
1761:
1762: sethi %hi(x),%0
1763: b ...
1764: or %0,%lo(x),%1
1765:
1766: */
1767:
1768: char *
1769: output_delayed_branch (template, operands, insn)
1770: char *template;
1771: rtx *operands;
1772: rtx insn;
1773: {
1774: extern rtx recog_operand[];
1775: rtx src = XVECEXP (PATTERN (insn), 0, 1);
1776: rtx dest = XVECEXP (PATTERN (insn), 0, 0);
1777:
1778: if (GET_CODE (src) == SYMBOL_REF
1779: || (GET_CODE (src) == CONST_INT
1780: && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0)))
1781: {
1782: rtx xoperands[2];
1783: xoperands[0] = dest;
1784: xoperands[1] = src;
1785:
1786: /* Output the `sethi' insn. */
1787: output_asm_insn ("sethi %%hi(%1),%0", xoperands);
1788:
1789: /* Output the branch instruction next. */
1790: output_asm_insn (template, operands);
1791:
1792: /* Now output the `or' insn. */
1793: output_asm_insn ("or %0,%%lo(%1),%0", xoperands);
1794: }
1795: else if ((GET_CODE (src) == MEM
1796: && CONSTANT_ADDRESS_P (XEXP (src, 0)))
1797: || (GET_CODE (dest) == MEM
1798: && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
1799: {
1800: rtx xoperands[2];
1801: char *split_template;
1802: xoperands[0] = dest;
1803: xoperands[1] = src;
1804:
1805: /* Output the `sethi' insn. */
1806: if (GET_CODE (src) == MEM)
1807: {
1808: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1809: && cc_prev_status.mdep == XEXP (operands[1], 0)))
1810: output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands);
1811: split_template = "ld [%%g1+%%lo(%m1)],%0";
1812: }
1813: else
1814: {
1815: if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
1816: && cc_prev_status.mdep == XEXP (operands[0], 0)))
1817: output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands);
1818: split_template = "st %r1,[%%g1+%%lo(%m0)]";
1819: }
1820:
1821: /* Output the branch instruction next. */
1822: output_asm_insn (template, operands);
1823:
1824: /* Now output the load or store.
1825: No need to do a CC_STATUS_INIT, because we are branching anyway. */
1826: output_asm_insn (split_template, xoperands);
1827: }
1828: else
1829: {
1830: extern char *insn_template[];
1831: extern char *(*insn_outfun[])();
1832: int insn_code_number;
1833: rtx pat = gen_rtx (SET, VOIDmode, dest, src);
1834: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
1835: int i;
1836: extern rtx alter_subreg();
1837: extern int insn_n_operands[];
1838:
1839: /* Output the branch instruction first. */
1840: output_asm_insn (template, operands);
1841:
1842: /* Now recognize the insn which we put in its delay slot.
1843: We must do this after outputing the branch insn,
1844: since operands may just be a pointer to `recog_operand'. */
1845: insn_code_number = recog (pat, delay_insn);
1846: if (insn_code_number == -1)
1847: abort ();
1848:
1849: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1850: {
1851: if (GET_CODE (recog_operand[i]) == SUBREG)
1852: recog_operand[i] = alter_subreg (recog_operand[i]);
1853: }
1854:
1855: /* Now get the template for what this insn would
1856: have been, without the branch. Its operands are
1857: exactly the same as they would be, so we don't
1858: need to do an insn_extract. */
1859: template = insn_template[insn_code_number];
1860: if (template == 0)
1861: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1862: output_asm_insn (template, recog_operand);
1863: }
1864: CC_STATUS_INIT;
1865: return "";
1866: }
1867:
1868: /* Output a newly constructed insn DELAY_INSN. */
1869: char *
1870: output_delay_insn (delay_insn)
1871: rtx delay_insn;
1872: {
1873: char *template;
1874: extern rtx recog_operand[];
1875: extern char call_used_regs[];
1876: extern char *insn_template[];
1877: extern int insn_n_operands[];
1878: extern char *(*insn_outfun[])();
1879: extern rtx alter_subreg();
1880: int insn_code_number;
1881: extern int insn_n_operands[];
1882: int i;
1883:
1884: /* Now recognize the insn which we put in its delay slot.
1885: We must do this after outputing the branch insn,
1886: since operands may just be a pointer to `recog_operand'. */
1887: insn_code_number = recog_memoized (delay_insn);
1888: if (insn_code_number == -1)
1889: abort ();
1890:
1891: /* Extract the operands of this delay insn. */
1892: INSN_CODE (delay_insn) = insn_code_number;
1893: insn_extract (delay_insn);
1894:
1895: /* It is possible that this insn has not been properly scaned by final
1896: yet. If this insn's operands don't appear in the peephole's
1897: actual operands, then they won't be fixed up by final, so we
1898: make sure they get fixed up here. -- This is a kludge. */
1899: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1900: {
1901: if (GET_CODE (recog_operand[i]) == SUBREG)
1902: recog_operand[i] = alter_subreg (recog_operand[i]);
1903: }
1904:
1905: #ifdef REGISTER_CONSTRAINTS
1906: if (! constrain_operands (insn_code_number))
1907: abort ();
1908: #endif
1909:
1910: cc_prev_status = cc_status;
1911:
1912: /* Update `cc_status' for this instruction.
1913: The instruction's output routine may change it further.
1914: If the output routine for a jump insn needs to depend
1915: on the cc status, it should look at cc_prev_status. */
1916:
1917: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
1918:
1919: /* Now get the template for what this insn would
1920: have been, without the branch. */
1921:
1922: template = insn_template[insn_code_number];
1923: if (template == 0)
1924: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1925: output_asm_insn (template, recog_operand);
1926: return "";
1927: }
1928:
1929: /* Output the insn HEAD, keeping OPERANDS protected (wherever they are).
1930: HEAD comes from the target of some branch, so before we output it,
1931: we delete it from the target, lest we execute it twice. The caller
1932: of this function promises that such code motion is permissable. */
1933: char *
1934: output_eager_then_insn (head, operands)
1935: rtx head;
1936: rtx *operands;
1937: {
1938: extern rtx alter_subreg ();
1939: extern int insn_n_operands[];
1940: extern rtx recog_operand[];
1941: rtx xoperands[MAX_RECOG_OPERANDS];
1942: int insn_code_number, i, nbytes;
1943: rtx nhead;
1944:
1945: /* Micro-hack: run peephole on head if it looks like a good idea.
1946: Right now there's only one such case worth doing...
1947:
1948: This could be made smarter if the peephole for ``2-insn combine''
1949: were also made smarter. */
1950: if (GET_CODE (PATTERN (head)) == SET
1951: && REG_P (SET_SRC (PATTERN (head)))
1952: && REG_P (SET_DEST (PATTERN (head)))
1953: && (nhead = next_real_insn_no_labels (head))
1954: && GET_CODE (nhead) == INSN
1955: && GET_CODE (PATTERN (nhead)) == SET
1956: && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0
1957: && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head))
1958: || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head))))
1959: /* Something's wrong if this does not fly. */
1960: if (! peephole (head))
1961: abort ();
1962:
1963: /* Save our contents of `operands', since output_delay_insn sets them. */
1964: insn_code_number = recog_memoized (head);
1965: nbytes = insn_n_operands[insn_code_number] * sizeof (rtx);
1966: bcopy (operands, xoperands, nbytes);
1967:
1968: /* Output the delay insn, and prevent duplication later. */
1969: delete_insn (head);
1970: output_delay_insn (head);
1971:
1972: /* Restore this insn's operands. */
1973: bcopy (xoperands, operands, nbytes);
1974: }
1975:
1976: /* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL;
1977: or 0, if there is none. Also return 0 if we cross a label. */
1978:
1979: rtx
1980: next_real_insn_no_labels (label)
1981: rtx label;
1982: {
1983: register rtx insn = NEXT_INSN (label);
1984: register RTX_CODE code;
1985:
1986: while (insn)
1987: {
1988: code = GET_CODE (insn);
1989: if (code == INSN)
1990: {
1991: if (GET_CODE (PATTERN (insn)) != CLOBBER
1992: && GET_CODE (PATTERN (insn)) != USE)
1993: return insn;
1994: }
1995: if (code == CALL_INSN || code == JUMP_INSN)
1996: return insn;
1997: if (code == CODE_LABEL)
1998: return 0;
1999: insn = NEXT_INSN (insn);
2000: }
2001:
2002: return 0;
2003: }
2004:
2005: int
2006: operands_satisfy_eager_branch_peephole (operands, conditional)
2007: rtx *operands;
2008: int conditional;
2009: {
2010: rtx label;
2011:
2012: if (conditional)
2013: {
2014: if (GET_CODE (operands[0]) != IF_THEN_ELSE)
2015: return 0;
2016:
2017: if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF)
2018: label = XEXP (XEXP (operands[0], 1), 0);
2019: else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF)
2020: label = XEXP (XEXP (operands[0], 2), 0);
2021: else return 0;
2022: }
2023: else
2024: {
2025: label = operands[0];
2026: }
2027:
2028: if (LABEL_NUSES (label) == 1)
2029: {
2030: rtx prev = PREV_INSN (label);
2031: while (prev && GET_CODE (prev) == NOTE)
2032: prev = PREV_INSN (prev);
2033: if (prev == 0
2034: || GET_CODE (prev) == BARRIER)
2035: {
2036: rtx head = next_real_insn_no_labels (label);
2037:
2038: if (head
2039: && ! INSN_DELETED_P (head)
2040: && GET_CODE (head) == INSN
2041: && GET_CODE (PATTERN (head)) == SET
2042: && strict_single_insn_op_p (SET_SRC (PATTERN (head)),
2043: GET_MODE (SET_DEST (PATTERN (head))))
2044: && strict_single_insn_op_p (SET_DEST (PATTERN (head)),
1.1.1.2 root 2045: GET_MODE (SET_DEST (PATTERN (head))))
2046: /* Moves between FP regs and CPU regs are two insns. */
2047: && !(GET_CODE (SET_SRC (PATTERN (head))) == REG
2048: && GET_CODE (SET_DEST (PATTERN (head))) == REG
2049: && (FP_REG_P (SET_SRC (PATTERN (head)))
2050: != FP_REG_P (SET_DEST (PATTERN (head))))))
1.1 root 2051: {
2052: if (conditional == 2)
2053: return (GET_CODE (operands[1]) != PC
2054: && safe_insn_src_p (operands[2], VOIDmode)
2055: && strict_single_insn_op_p (operands[2], VOIDmode)
2056: && operand_clobbered_before_used_after (operands[1], label));
2057: return 1;
2058: }
2059: }
2060: }
2061:
2062: if (conditional == 1
2063: && GET_CODE (operands[1]) != PC
2064: && safe_insn_src_p (operands[2], VOIDmode)
2065: && strict_single_insn_op_p (operands[2], VOIDmode)
2066: && operand_clobbered_before_used_after (operands[1], label))
2067: return 1;
2068:
2069: return 0;
2070: }
2071:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.