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