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