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