|
|
1.1 root 1: /* Subroutines for insn-output.c for Intel 860
2: Copyright (C) 1989 Free Software Foundation, Inc.
3: Derived from out-sparc.c.
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:
22: /* Global variables for machine-dependend things. */
23:
24: /* This should go away if we pass floats to regs via
25: the stack instead of the frame, and if we learn how
26: to renumber all the registers when we don't do a save (hard!). */
27: extern int frame_pointer_needed;
28:
29: static rtx find_addr_reg ();
30:
31: /* Return non-zero only if OP is a register of mode MODE,
32: or const0_rtx. */
33: int
34: reg_or_0_operand (op, mode)
35: rtx op;
36: enum machine_mode mode;
37: {
38: return (op == const0_rtx || register_operand (op, mode)
39: || op == CONST0_RTX (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: case ZERO_EXTEND:
72: return 1;
73:
74: case EQ:
75: case NE:
76: case LT:
77: case GT:
78: case LE:
79: case GE:
80: case LTU:
81: case GTU:
82: case LEU:
83: case GEU:
84: case MINUS:
85: case PLUS:
86: return (mode != SFmode && mode != DFmode);
87: case AND:
88: case IOR:
89: case XOR:
90: case LSHIFT:
91: case ASHIFT:
92: case ASHIFTRT:
93: case LSHIFTRT:
94: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
95: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
96: return 0;
97: return 1;
98:
99: default:
100: return 0;
101: }
102: }
103:
104: /* Return 1 if REG is clobbered in IN.
105: Return 2 if REG is used in IN.
106: Return 3 if REG is both used and clobbered in IN.
107: Return 0 if neither. */
108:
109: static int
110: reg_clobbered_p (reg, in)
111: rtx reg;
112: rtx in;
113: {
114: register enum rtx_code code;
115:
116: if (in == 0)
117: return 0;
118:
119: code = GET_CODE (in);
120:
121: if (code == SET || code == CLOBBER)
122: {
123: rtx dest = SET_DEST (in);
124: int set = 0;
125: int used = 0;
126:
127: while (GET_CODE (dest) == STRICT_LOW_PART
128: || GET_CODE (dest) == SUBREG
129: || GET_CODE (dest) == SIGN_EXTRACT
130: || GET_CODE (dest) == ZERO_EXTRACT)
131: dest = XEXP (dest, 0);
132:
133: if (dest == reg)
134: set = 1;
135: else if (GET_CODE (dest) == REG
136: && refers_to_regno_p (REGNO (reg),
137: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
138: SET_DEST (in), 0))
139: {
140: set = 1;
141: /* Anything that sets just part of the register
142: is considered using as well as setting it.
143: But note that a straight SUBREG of a single-word value
144: clobbers the entire value. */
145: if (dest != SET_DEST (in)
146: && ! (GET_CODE (SET_DEST (in)) == SUBREG
147: || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))
148: used = 1;
149: }
150:
151: if (code == SET)
152: {
153: if (set)
154: used = refers_to_regno_p (REGNO (reg),
155: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
156: SET_SRC (in), 0);
157: else
158: used = refers_to_regno_p (REGNO (reg),
159: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
160: in, 0);
161: }
162:
163: return set + used * 2;
164: }
165:
166: if (refers_to_regno_p (REGNO (reg),
167: REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
168: in, 0))
169: return 2;
170: return 0;
171: }
172:
173: /* Return non-zero if OP can be written to without screwing up
174: GCC's model of what's going on. It is assumed that this operand
175: appears in the dest position of a SET insn in a conditional
176: branch's delay slot. AFTER is the label to start looking from. */
177: int
178: operand_clobbered_before_used_after (op, after)
179: rtx op;
180: rtx after;
181: {
182: extern char call_used_regs[];
183:
184: /* Just experimenting. */
185: if (GET_CODE (op) == CC0)
186: return 1;
187: if (GET_CODE (op) == REG)
188: {
189: rtx insn;
190:
191: if (op == stack_pointer_rtx)
192: return 0;
193:
194: /* Scan forward from the label, to see if the value of OP
195: is clobbered before the first use. */
196:
197: for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
198: {
199: if (GET_CODE (insn) == NOTE)
200: continue;
201: if (GET_CODE (insn) == INSN
202: || GET_CODE (insn) == JUMP_INSN
203: || GET_CODE (insn) == CALL_INSN)
204: {
205: switch (reg_clobbered_p (op, PATTERN (insn)))
206: {
207: default:
208: return 0;
209: case 1:
210: return 1;
211: case 0:
212: break;
213: }
214: }
215: /* If we reach another label without clobbering OP,
216: then we cannot safely write it here. */
217: else if (GET_CODE (insn) == CODE_LABEL)
218: return 0;
219: if (GET_CODE (insn) == JUMP_INSN)
220: {
221: if (condjump_p (insn))
222: return 0;
223: /* This is a jump insn which has already
224: been mangled. We can't tell what it does. */
225: if (GET_CODE (PATTERN (insn)) == PARALLEL)
226: return 0;
227: if (! JUMP_LABEL (insn))
228: return 0;
229: /* Keep following jumps. */
230: insn = JUMP_LABEL (insn);
231: }
232: }
233: return 1;
234: }
235:
236: /* In both of these cases, the first insn executed
237: for this op will be a orh whatever%h,r0,r31,
238: which is tolerable. */
239: if (GET_CODE (op) == MEM)
240: return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
241:
242: return 0;
243: }
244:
245: /* Return non-zero if this pattern, as a source to a "SET",
246: is known to yield an instruction of unit size. */
247: int
248: single_insn_src_p (op, mode)
249: rtx op;
250: enum machine_mode mode;
251: {
252: switch (GET_CODE (op))
253: {
254: case CONST_INT:
255: /* This is not always a single insn src, technically,
256: but output_delayed_branch knows how to deal with it. */
257: return 1;
258:
259: case SYMBOL_REF:
260: case CONST:
261: /* This is not a single insn src, technically,
262: but output_delayed_branch knows how to deal with it. */
263: return 1;
264:
265: case REG:
266: return 1;
267:
268: case MEM:
269: return 1;
270:
271: /* We never need to negate or complement constants. */
272: case NEG:
273: return (mode != DFmode);
274: case NOT:
275: case ZERO_EXTEND:
276: return 1;
277:
278: case EQ:
279: case NE:
280: case LT:
281: case GT:
282: case LE:
283: case GE:
284: case LTU:
285: case GTU:
286: case LEU:
287: case GEU:
288: case MINUS:
289: case PLUS:
290: /* Not doing floating point, since they probably
291: take longer than the branch slot they might fill. */
292: return (mode != SFmode && mode != DFmode);
293: case AND:
294: case IOR:
295: case XOR:
296: case LSHIFT:
297: case ASHIFT:
298: case ASHIFTRT:
299: case LSHIFTRT:
300: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
301: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
302: return 0;
303: return 1;
304:
305: case SUBREG:
306: if (SUBREG_WORD (op) != 0)
307: return 0;
308: return single_insn_src_p (SUBREG_REG (op), mode);
309:
310: /* Not doing floating point, since they probably
311: take longer than the branch slot they might fill. */
312: case FLOAT_EXTEND:
313: case FLOAT_TRUNCATE:
314: case FLOAT:
315: case FIX:
316: case UNSIGNED_FLOAT:
317: case UNSIGNED_FIX:
318: return 0;
319:
320: default:
321: return 0;
322: }
323: }
324:
325: /* Nonzero only if this *really* is a single insn operand. */
326: int
327: strict_single_insn_op_p (op, mode)
328: rtx op;
329: enum machine_mode mode;
330: {
331: if (mode == VOIDmode)
332: mode = GET_MODE (op);
333:
334: switch (GET_CODE (op))
335: {
336: case CC0:
337: return 1;
338:
339: case CONST_INT:
340: if (SMALL_INT (op))
341: return 1;
342: /* We can put this set insn into delay slot, because this is one
343: insn; 'sethi'. */
344: if ((INTVAL (op) & 0x3ff) == 0)
345: return 1;
346: return 0;
347:
348: case SYMBOL_REF:
349: return 0;
350:
351: case REG:
352: #if 0
353: /* This loses when moving an freg to a general reg. */
354: return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
355: #endif
356: return (mode != DFmode && mode != DImode);
357:
358: case MEM:
359: if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
360: return (mode != DFmode && mode != DImode);
361: return 0;
362:
363: /* We never need to negate or complement constants. */
364: case NEG:
365: return (mode != DFmode);
366: case NOT:
367: case ZERO_EXTEND:
368: return 1;
369:
370: case EQ:
371: case NE:
372: case LT:
373: case GT:
374: case LE:
375: case GE:
376: case LTU:
377: case GTU:
378: case LEU:
379: case GEU:
380: case MINUS:
381: case PLUS:
382: case AND:
383: case IOR:
384: case XOR:
385: case LSHIFT:
386: case ASHIFT:
387: case ASHIFTRT:
388: case LSHIFTRT:
389: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
390: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
391: return 0;
392: return 1;
393:
394: case SUBREG:
395: if (SUBREG_WORD (op) != 0)
396: return 0;
397: return strict_single_insn_op_p (SUBREG_REG (op), mode);
398:
399: case SIGN_EXTEND:
400: if (GET_CODE (XEXP (op, 0)) == MEM
401: && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
402: return 1;
403: return 0;
404:
405: /* Not doing floating point, since they probably
406: take longer than the branch slot they might fill. */
407: case FLOAT_EXTEND:
408: case FLOAT_TRUNCATE:
409: case FLOAT:
410: case FIX:
411: case UNSIGNED_FLOAT:
412: case UNSIGNED_FIX:
413: return 0;
414:
415: default:
416: return 0;
417: }
418: }
419:
420: /* Return truth value of whether OP is a relational operator. */
421: int
422: relop (op, mode)
423: rtx op;
424: enum machine_mode mode;
425: {
426: switch (GET_CODE (op))
427: {
428: case EQ:
429: case NE:
430: case GT:
431: case GE:
432: case LT:
433: case LE:
434: case GTU:
435: case GEU:
436: case LTU:
437: case LEU:
438: return 1;
439: }
440: return 0;
441: }
442:
443: /* Return truth value of whether OP can be used as an operands in a three
444: address add/subtract insn (such as add %o1,7,%l2) of mode MODE. */
445:
446: int
447: arith_operand (op, mode)
448: rtx op;
449: enum machine_mode mode;
450: {
451: return (register_operand (op, mode)
452: || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
453: }
454:
455: /* Return 1 if OP is a valid first operand for a logical insn of mode MODE. */
456:
457: int
458: logic_operand (op, mode)
459: rtx op;
460: enum machine_mode mode;
461: {
462: return (register_operand (op, mode)
463: || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
464: }
465:
466: /* Return 1 if OP is a valid first operand for either a logical insn
467: or an add insn of mode MODE. */
468:
469: int
470: compare_operand (op, mode)
471: rtx op;
472: enum machine_mode mode;
473: {
474: return (register_operand (op, mode)
475: || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
476: }
477:
478: /* Return truth value of whether OP can be used as an operand
479: of a bte insn. */
480:
481: int
482: bte_operand (op, mode)
483: rtx op;
484: enum machine_mode mode;
485: {
486: return (register_operand (op, mode)
487: || (GET_CODE (op) == CONST_INT
488: && (unsigned) INTVAL (op) < 0x20));
489: }
490:
491: /* Return 1 if OP is an indexed memory reference of mode MODE. */
492:
493: int
494: indexed_operand (op, mode)
495: rtx op;
496: enum machine_mode mode;
497: {
498: return (GET_CODE (op) == MEM && GET_MODE (op) == mode
499: && GET_CODE (XEXP (op, 0)) == PLUS
500: && GET_MODE (XEXP (op, 0)) == SImode
501: && register_operand (XEXP (XEXP (op, 0), 0), SImode)
502: && register_operand (XEXP (XEXP (op, 0), 1), SImode));
503: }
504:
505: /* Return 1 if OP is a suitable source operand for a load insn
506: with mode MODE. */
507:
508: int
509: load_operand (op, mode)
510: rtx op;
511: enum machine_mode mode;
512: {
513: return (memory_operand (op, mode) || indexed_operand (op, mode));
514: }
515:
516: /* Return truth value of whether OP is a integer which fits the
517: range constraining immediate operands in add/subtract insns. */
518:
519: int
520: small_int (op, mode)
521: rtx op;
522: enum machine_mode mode;
523: {
524: return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
525: }
526:
527: /* Return truth value of whether OP is a integer which fits the
528: range constraining immediate operands in logic insns. */
529:
530: int
531: logic_int (op, mode)
532: rtx op;
533: enum machine_mode mode;
534: {
535: return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
536: }
537:
538: /* Return the best assembler insn template
539: for moving operands[1] into operands[0] as a fullword. */
540:
541: static char *
542: singlemove_string (operands)
543: rtx *operands;
544: {
545: if (GET_CODE (operands[0]) == MEM)
546: {
547: if (GET_CODE (operands[1]) != MEM)
548: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
549: {
550: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
551: && (cc_prev_status.flags & CC_HI_R31_ADJ)
552: && cc_prev_status.mdep == XEXP (operands[0], 0)))
553: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
554: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
555: cc_status.mdep = XEXP (operands[0], 0);
556: return "st.l %r1,l%%%m0(r31)";
557: }
558: else
559: return "st.l %r1,%0";
560: else
561: abort ();
562: #if 0
563: {
564: rtx xoperands[2];
565:
566: cc_status.flags &= ~CC_F0_IS_0;
567: xoperands[0] = gen_rtx (REG, SFmode, 32);
568: xoperands[1] = operands[1];
569: output_asm_insn (singlemove_string (xoperands), xoperands);
570: xoperands[1] = xoperands[0];
571: xoperands[0] = operands[0];
572: output_asm_insn (singlemove_string (xoperands), xoperands);
573: return "";
574: }
575: #endif
576: }
577: if (GET_CODE (operands[1]) == MEM)
578: {
579: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
580: {
581: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
582: && (cc_prev_status.flags & CC_HI_R31_ADJ)
583: && cc_prev_status.mdep == XEXP (operands[1], 0)))
584: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
585: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
586: cc_status.mdep = XEXP (operands[1], 0);
587: return "ld.l l%%%m1(r31),%0";
588: }
589: return "ld.l %1,%0";
590: }
591: return "mov %1,%0";
592: }
593:
594: /* Output assembler code to perform a doubleword move insn
595: with operands OPERANDS. */
596:
597: char *
598: output_move_double (operands)
599: rtx *operands;
600: {
601: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
602: rtx latehalf[2];
603: rtx addreg0 = 0, addreg1 = 0;
604:
605: /* First classify both operands. */
606:
607: if (REG_P (operands[0]))
608: optype0 = REGOP;
609: else if (offsettable_memref_p (operands[0]))
610: optype0 = OFFSOP;
611: else if (GET_CODE (operands[0]) == MEM)
612: optype0 = MEMOP;
613: else
614: optype0 = RNDOP;
615:
616: if (REG_P (operands[1]))
617: optype1 = REGOP;
618: else if (CONSTANT_P (operands[1])
619: || GET_CODE (operands[1]) == CONST_DOUBLE)
620: optype1 = CNSTOP;
621: else if (offsettable_memref_p (operands[1]))
622: optype1 = OFFSOP;
623: else if (GET_CODE (operands[1]) == MEM)
624: optype1 = MEMOP;
625: else
626: optype1 = RNDOP;
627:
628: /* Check for the cases that the operand constraints are not
629: supposed to allow to happen. Abort if we get one,
630: because generating code for these cases is painful. */
631:
632: if (optype0 == RNDOP || optype1 == RNDOP)
633: abort ();
634:
635: /* If an operand is an unoffsettable memory ref, find a register
636: we can increment temporarily to make it refer to the second word. */
637:
638: if (optype0 == MEMOP)
639: addreg0 = find_addr_reg (XEXP (operands[0], 0));
640:
641: if (optype1 == MEMOP)
642: addreg1 = find_addr_reg (XEXP (operands[1], 0));
643:
644: /* ??? Perhaps in some cases move double words
645: if there is a spare pair of floating regs. */
646:
647: /* Ok, we can do one word at a time.
648: Normally we do the low-numbered word first,
649: but if either operand is autodecrementing then we
650: do the high-numbered word first.
651:
652: In either case, set up in LATEHALF the operands to use
653: for the high-numbered word and in some cases alter the
654: operands in OPERANDS to be suitable for the low-numbered word. */
655:
656: if (optype0 == REGOP)
657: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
658: else if (optype0 == OFFSOP)
659: latehalf[0] = adj_offsettable_operand (operands[0], 4);
660: else
661: latehalf[0] = operands[0];
662:
663: if (optype1 == REGOP)
664: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
665: else if (optype1 == OFFSOP)
666: latehalf[1] = adj_offsettable_operand (operands[1], 4);
667: else if (optype1 == CNSTOP)
668: {
669: if (CONSTANT_P (operands[1]))
670: latehalf[1] = const0_rtx;
671: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
672: {
673: latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
674: CONST_DOUBLE_HIGH (operands[1]));
675: operands[1] = gen_rtx (CONST_INT, VOIDmode,
676: CONST_DOUBLE_LOW (operands[1]));
677: }
678: }
679: else
680: latehalf[1] = operands[1];
681:
682: /* If the first move would clobber the source of the second one,
683: do them in the other order.
684:
685: RMS says "This happens only for registers;
686: such overlap can't happen in memory unless the user explicitly
687: sets it up, and that is an undefined circumstance."
688:
689: but it happens on the sparc when loading parameter registers,
690: so I am going to define that circumstance, and make it work
691: as expected. */
692:
693: if (optype0 == REGOP && optype1 == REGOP
694: && REGNO (operands[0]) == REGNO (latehalf[1]))
695: {
696: /* Make any unoffsettable addresses point at high-numbered word. */
697: if (addreg0)
698: output_asm_insn ("adds 0x4,%0,%0", &addreg0);
699: if (addreg1)
700: output_asm_insn ("adds 0x4,%0,%0", &addreg1);
701:
702: /* Do that word. */
703: output_asm_insn (singlemove_string (latehalf), latehalf);
704:
705: /* Undo the adds we just did. */
706: if (addreg0)
707: output_asm_insn ("adds -0x4,%0,%0", &addreg0);
708: if (addreg1)
709: output_asm_insn ("adds -0x4,%0,%0", &addreg1);
710:
711: /* Do low-numbered word. */
712: return singlemove_string (operands);
713: }
714: else if (optype0 == REGOP && optype1 != REGOP
715: && reg_overlap_mentioned_p (operands[0], operands[1]))
716: {
717: /* Do the late half first. */
718: output_asm_insn (singlemove_string (latehalf), latehalf);
719: /* Then clobber. */
720: return singlemove_string (operands);
721: }
722:
723: /* Normal case: do the two words, low-numbered first. */
724:
725: output_asm_insn (singlemove_string (operands), operands);
726:
727: /* Make any unoffsettable addresses point at high-numbered word. */
728: if (addreg0)
729: output_asm_insn ("adds 0x4,%0,%0", &addreg0);
730: if (addreg1)
731: output_asm_insn ("adds 0x4,%0,%0", &addreg1);
732:
733: /* Do that word. */
734: output_asm_insn (singlemove_string (latehalf), latehalf);
735:
736: /* Undo the adds we just did. */
737: if (addreg0)
738: output_asm_insn ("adds -0x4,%0,%0", &addreg0);
739: if (addreg1)
740: output_asm_insn ("adds -0x4,%0,%0", &addreg1);
741:
742: return "";
743: }
744:
745: static char *
746: output_fp_move_double (operands)
747: rtx *operands;
748: {
749: if (FP_REG_P (operands[0]))
750: {
751: if (FP_REG_P (operands[1]))
752: return "fmov.dd %1,%0";
753: if (GET_CODE (operands[1]) == REG)
754: {
755: output_asm_insn ("ixfr %1,%0", operands);
756: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
757: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
758: return "ixfr %1,%0";
759: }
760: if (operands[1] == dconst0_rtx)
761: return "fmov.dd f0,%0";
762: if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
763: {
764: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
765: && (cc_prev_status.flags & CC_HI_R31_ADJ)
766: && cc_prev_status.mdep == XEXP (operands[1], 0)))
767: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
768: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
769: cc_status.mdep = XEXP (operands[1], 0);
770: return "fld.d l%%%m1(r31),%0";
771: }
772: return "fld.d %1,%0";
773: }
774: else if (FP_REG_P (operands[1]))
775: {
776: if (GET_CODE (operands[0]) == REG)
777: {
778: output_asm_insn ("fxfr %1,%0", operands);
779: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
780: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
781: return "fxfr %1,%0";
782: }
783: if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
784: {
785: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
786: && (cc_prev_status.flags & CC_HI_R31_ADJ)
787: && cc_prev_status.mdep == XEXP (operands[0], 0)))
788: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
789: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
790: cc_status.mdep = XEXP (operands[0], 0);
791: return "fst.d %1,l%%%m0(r31)";
792: }
793: return "fst.d %1,%0";
794: }
795: else abort ();
796: }
797:
798: /* Return a REG that occurs in ADDR with coefficient 1.
799: ADDR can be effectively incremented by incrementing REG. */
800:
801: static rtx
802: find_addr_reg (addr)
803: rtx addr;
804: {
805: while (GET_CODE (addr) == PLUS)
806: {
807: if (GET_CODE (XEXP (addr, 0)) == REG)
808: addr = XEXP (addr, 0);
809: else if (GET_CODE (XEXP (addr, 1)) == REG)
810: addr = XEXP (addr, 1);
811: else if (CONSTANT_P (XEXP (addr, 0)))
812: addr = XEXP (addr, 1);
813: else if (CONSTANT_P (XEXP (addr, 1)))
814: addr = XEXP (addr, 0);
815: else
816: abort ();
817: }
818: if (GET_CODE (addr) == REG)
819: return addr;
820: abort ();
821: }
822:
823: /* Return a template for a load instruction with mode MODE and
824: arguments from the string ARGS.
825:
826: This string is in static storage. */
827:
828: static char *
829: load_opcode (mode, args, reg)
830: enum machine_mode mode;
831: char *args;
832: rtx reg;
833: {
834: static char buf[30];
835: char *opcode;
836:
837: switch (mode)
838: {
839: case QImode:
840: opcode = "ld.b";
841: break;
842:
843: case HImode:
844: opcode = "ld.s";
845: break;
846:
847: case SImode:
848: case SFmode:
849: if (FP_REG_P (reg))
850: opcode = "fld.l";
851: else
852: opcode = "ld.l";
853: break;
854:
855: case DFmode:
856: opcode = "fld.d";
857: break;
858:
859: default:
860: abort ();
861: }
862:
863: sprintf (buf, "%s %s", opcode, args);
864: return buf;
865: }
866:
867: /* Return a template for a store instruction with mode MODE and
868: arguments from the string ARGS.
869:
870: This string is in static storage. */
871:
872: static char *
873: store_opcode (mode, args, reg)
874: enum machine_mode mode;
875: char *args;
876: rtx reg;
877: {
878: static char buf[30];
879: char *opcode;
880:
881: switch (mode)
882: {
883: case QImode:
884: opcode = "st.b";
885: break;
886:
887: case HImode:
888: opcode = "st.s";
889: break;
890:
891: case SImode:
892: case SFmode:
893: if (FP_REG_P (reg))
894: opcode = "fst.l";
895: else
896: opcode = "st.l";
897: break;
898:
899: case DFmode:
900: opcode = "fst.d";
901: break;
902:
903: default:
904: abort ();
905: }
906:
907: sprintf (buf, "%s %s", opcode, args);
908: return buf;
909: }
910:
911: /* Output a store-in-memory whose operands are OPERANDS[0,1].
912: OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
913:
914: This function returns a template for an insn.
915: This is in static storage.
916:
917: It may also output some insns directly.
918: It may alter the values of operands[0] and operands[1]. */
919:
920: char *
921: output_store (operands)
922: rtx *operands;
923: {
924: enum machine_mode mode = GET_MODE (operands[0]);
925: rtx address = XEXP (operands[0], 0);
926: char *string;
927:
928: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
929: cc_status.mdep = address;
930:
931: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
932: && (cc_prev_status.flags & CC_HI_R31_ADJ)
933: && address == cc_prev_status.mdep))
934: {
935: output_asm_insn ("orh ha%%%m0,r0,r31", operands);
936: cc_prev_status.mdep = address;
937: }
938:
939: /* Store zero in two parts when appropriate. */
940: if (mode == DFmode && operands[1] == dconst0_rtx)
941: return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);
942:
943: /* Code below isn't smart enough to move a doubleword in two parts,
944: so use output_move_double to do that in the cases that require it. */
945: if ((mode == DImode || mode == DFmode)
946: && ! FP_REG_P (operands[1]))
947: return output_move_double (operands);
948:
949: return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);
950: }
951:
952: /* Output a load-from-memory whose operands are OPERANDS[0,1].
953: OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
954:
955: This function returns a template for an insn.
956: This is in static storage.
957:
958: It may also output some insns directly.
959: It may alter the values of operands[0] and operands[1]. */
960:
961: char *
962: output_load (operands)
963: rtx *operands;
964: {
965: enum machine_mode mode = GET_MODE (operands[0]);
966: rtx address = XEXP (operands[1], 0);
967:
968: /* We don't bother trying to see if we know %hi(address).
969: This is because we are doing a load, and if we know the
970: %hi value, we probably also know that value in memory. */
971: cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
972: cc_status.mdep = address;
973:
974: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
975: && (cc_prev_status.flags & CC_HI_R31_ADJ)
976: && address == cc_prev_status.mdep
977: && cc_prev_status.mdep == cc_status.mdep))
978: {
979: output_asm_insn ("orh ha%%%m1,r0,r31", operands);
980: cc_prev_status.mdep = address;
981: }
982:
983: /* Code below isn't smart enough to move a doubleword in two parts,
984: so use output_move_double to do that in the cases that require it. */
985: if ((mode == DImode || mode == DFmode)
986: && ! FP_REG_P (operands[0]))
987: return output_move_double (operands);
988:
989: return load_opcode (mode, "l%%%m1(r31),%0", operands[0]);
990: }
991:
992: /* Load the address specified by OPERANDS[3] into the register
993: specified by OPERANDS[0].
994:
995: OPERANDS[3] may be the result of a sum, hence it could either be:
996:
997: (1) CONST
998: (2) REG
999: (2) REG + CONST_INT
1000: (3) REG + REG + CONST_INT
1001: (4) REG + REG (special case of 3).
1002:
1003: Note that (3) is not a legitimate address.
1004: All cases are handled here. */
1005:
1006: void
1007: output_load_address (operands)
1008: rtx *operands;
1009: {
1010: rtx base, offset;
1011:
1012: if (CONSTANT_P (operands[3]))
1013: {
1014: output_asm_insn ("mov %3,%0", operands);
1015: return;
1016: }
1017:
1018: if (REG_P (operands[3]))
1019: {
1020: if (REGNO (operands[0]) != REGNO (operands[3]))
1021: output_asm_insn ("mov %3,%0", operands);
1022: return;
1023: }
1024:
1025: if (GET_CODE (operands[3]) != PLUS)
1026: abort ();
1027:
1028: base = XEXP (operands[3], 0);
1029: offset = XEXP (operands[3], 1);
1030:
1031: if (GET_CODE (base) == CONST_INT)
1032: {
1033: rtx tmp = base;
1034: base = offset;
1035: offset = tmp;
1036: }
1037:
1038: if (GET_CODE (offset) != CONST_INT)
1039: {
1040: /* Operand is (PLUS (REG) (REG)). */
1041: base = operands[3];
1042: offset = const0_rtx;
1043: }
1044:
1045: if (REG_P (base))
1046: {
1047: operands[6] = base;
1048: operands[7] = offset;
1049: if (SMALL_INT (offset))
1050: output_asm_insn ("adds %7,%6,%0", operands);
1051: else
1052: output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
1053: }
1054: else if (GET_CODE (base) == PLUS)
1055: {
1056: operands[6] = XEXP (base, 0);
1057: operands[7] = XEXP (base, 1);
1058: operands[8] = offset;
1059:
1060: if (SMALL_INT (offset))
1061: output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
1062: else
1063: output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
1064: }
1065: else
1066: abort ();
1067: }
1068:
1069: /* Output code to place a size count SIZE in register REG.
1070: Because block moves are pipelined, we don't include the
1071: first element in the transfer of SIZE to REG.
1072: For this, we subtract ALIGN. (Actually, I think it is not
1073: right to subtract on this machine, so right now we don't.) */
1074:
1075: static void
1076: output_size_for_block_move (size, reg, align)
1077: rtx size, reg, align;
1078: {
1079: rtx xoperands[3];
1080:
1081: xoperands[0] = reg;
1082: xoperands[1] = size;
1083: xoperands[2] = align;
1084:
1085: #if 1
1086: cc_status.flags &= ~ CC_KNOW_HI_R31;
1087: output_asm_insn ("mov %1,%0", xoperands);
1088: #else
1089: if (GET_CODE (size) == REG)
1090: output_asm_insn ("sub %2,%1,%0", xoperands);
1091: else
1092: {
1093: xoperands[1]
1094: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
1095: cc_status.flags &= ~ CC_KNOW_HI_R31;
1096: output_asm_insn ("mov %1,%0", xoperands);
1097: }
1098: #endif
1099: }
1100:
1101: /* Emit code to perform a block move.
1102:
1103: OPERANDS[0] is the destination.
1104: OPERANDS[1] is the source.
1105: OPERANDS[2] is the size.
1106: OPERANDS[3] is the known safe alignment.
1107: OPERANDS[4..6] are pseudos we can safely clobber as temps. */
1108:
1109: char *
1110: output_block_move (operands)
1111: rtx *operands;
1112: {
1113: /* A vector for our computed operands. Note that load_output_address
1114: makes use of (and can clobber) up to the 8th element of this vector. */
1115: rtx xoperands[10];
1116: rtx zoperands[10];
1117: static int movstrsi_label = 0;
1118: int i, j;
1119: rtx temp1 = operands[4];
1120: rtx alignrtx = operands[3];
1121: int align = INTVAL (alignrtx);
1122:
1123: xoperands[0] = operands[0];
1124: xoperands[1] = operands[1];
1125: xoperands[2] = temp1;
1126:
1127: /* We can't move more than four bytes at a time
1128: because we have only one register to move them through. */
1129: if (align > 4)
1130: {
1131: align = 4;
1132: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
1133: }
1134:
1135: /* Since we clobber untold things, nix the condition codes. */
1136: CC_STATUS_INIT;
1137:
1138: /* Recognize special cases of block moves. These occur
1139: when GNU C++ is forced to treat something as BLKmode
1140: to keep it in memory, when its mode could be represented
1141: with something smaller.
1142:
1143: We cannot do this for global variables, since we don't know
1144: what pages they don't cross. Sigh. */
1145: if (GET_CODE (operands[2]) == CONST_INT
1146: && INTVAL (operands[2]) <= 16
1147: && ! CONSTANT_ADDRESS_P (operands[0])
1148: && ! CONSTANT_ADDRESS_P (operands[1]))
1149: {
1150: int size = INTVAL (operands[2]);
1151: rtx op0 = xoperands[0];
1152: rtx op1 = xoperands[1];
1153:
1154: cc_status.flags &= ~CC_KNOW_HI_R31;
1155: if (align == 1)
1156: {
1157: if (memory_address_p (QImode, plus_constant (op0, size))
1158: && memory_address_p (QImode, plus_constant (op1, size)))
1159: {
1160: for (i = size-1; i >= 0; i--)
1161: {
1162: xoperands[0] = plus_constant (op0, i);
1163: xoperands[1] = plus_constant (op1, i);
1164: output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
1165: xoperands);
1166: }
1167: return "";
1168: }
1169: }
1170: else if (align == 2)
1171: {
1172: if (memory_address_p (HImode, plus_constant (op0, size))
1173: && memory_address_p (HImode, plus_constant (op1, size)))
1174: {
1175: for (i = (size>>1)-1; i >= 0; i--)
1176: {
1177: xoperands[0] = plus_constant (op0, i * 2);
1178: xoperands[1] = plus_constant (op1, i * 2);
1179: output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
1180: xoperands);
1181: }
1182: return "";
1183: }
1184: }
1185: else
1186: {
1187: if (memory_address_p (SImode, plus_constant (op0, size))
1188: && memory_address_p (SImode, plus_constant (op1, size)))
1189: {
1190: for (i = (size>>2)-1; i >= 0; i--)
1191: {
1192: xoperands[0] = plus_constant (op0, i * 4);
1193: xoperands[1] = plus_constant (op1, i * 4);
1194: output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
1195: xoperands);
1196: }
1197: return "";
1198: }
1199: }
1200: }
1201:
1202: /* This is the size of the transfer.
1203: Either use the register which already contains the size,
1204: or use a free register (used by no operands). */
1205: output_size_for_block_move (operands[2], operands[4], alignrtx);
1206:
1207: #if 0
1208: /* Also emit code to decrement the size value by ALIGN. */
1209: zoperands[0] = operands[0];
1210: zoperands[3] = plus_constant (operands[0], align);
1211: output_load_address (zoperands);
1212: #endif
1213:
1214: /* Generate number for unique label. */
1215:
1216: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1217:
1218: /* Copy the increment (negative) to a register for bla insn. */
1219:
1220: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
1221: xoperands[5] = operands[5];
1222: output_asm_insn ("mov %4,%5", xoperands);
1223:
1224: xoperands[6] = operands[6];
1225: output_asm_insn ("adds %0,%2,%6", xoperands);
1226:
1227: /* Now the actual loop.
1228: In xoperands, elements 1 and 0 are the input and output vectors.
1229: Element 2 is the loop index. Element 5 is the increment. */
1230:
1231: if (align == 1)
1232: {
1233: output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
1234: output_asm_insn ("ld.b %1(%2),r31", xoperands);
1235: output_asm_insn ("adds %5,%6,%6", xoperands);
1236: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1237: output_asm_insn ("st.b r31,0(%6)", xoperands);
1238: }
1239: if (align == 2)
1240: {
1241: output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
1242: output_asm_insn ("ld.s %1(%2),r31", xoperands);
1243: output_asm_insn ("adds %5,%6,%6", xoperands);
1244: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1245: output_asm_insn ("st.s r31,0(%6)", xoperands);
1246: }
1247: if (align == 4)
1248: {
1249: output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
1250: output_asm_insn ("ld.l %1(%2),r31", xoperands);
1251: output_asm_insn ("adds %5,%6,%6", xoperands);
1252: output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1253: output_asm_insn ("st.l r31,0(%6)", xoperands);
1254: }
1255:
1256: return "";
1257: }
1258:
1259: /* Output a delayed branch insn with the delay insn in its
1260: branch slot. The delayed branch insn template is in TEMPLATE,
1261: with operands OPERANDS. The insn in its delay slot is INSN.
1262:
1263: As a special case, since we know that all memory transfers are via
1264: ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
1265: reference around the branch as
1266:
1267: orh ha%x,r0,r31
1268: b ...
1269: ld/st l%x(r31),...
1270:
1271: As another special case, we handle loading (SYMBOL_REF ...) and
1272: other large constants around branches as well:
1273:
1274: orh h%x,r0,%0
1275: b ...
1276: or l%x,%0,%1
1277:
1278: */
1279:
1280: char *
1281: output_delayed_branch (template, operands, insn)
1282: char *template;
1283: rtx *operands;
1284: rtx insn;
1285: {
1286: extern rtx recog_operand[];
1287: rtx src = XVECEXP (PATTERN (insn), 0, 1);
1288: rtx dest = XVECEXP (PATTERN (insn), 0, 0);
1289:
1290: if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
1291: || (GET_CODE (src) == CONST_INT
1292: && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0)))
1293: {
1294: rtx xoperands[2];
1295: xoperands[0] = dest;
1296: xoperands[1] = src;
1297:
1298: /* Output the `orh' insn. */
1299: output_asm_insn ("orh h%%%1,r0,%0", xoperands);
1300:
1301: /* Output the branch instruction next. */
1302: output_asm_insn (template, operands);
1303:
1304: /* Now output the `or' insn. */
1305: output_asm_insn ("or l%%%1,%0,%0", xoperands);
1306: }
1307: else if ((GET_CODE (src) == MEM
1308: && CONSTANT_ADDRESS_P (XEXP (src, 0)))
1309: || (GET_CODE (dest) == MEM
1310: && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
1311: {
1312: rtx xoperands[2];
1313: char *split_template;
1314: xoperands[0] = dest;
1315: xoperands[1] = src;
1316:
1317: /* Output the `orh' insn. */
1318: if (GET_CODE (src) == MEM)
1319: {
1320: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1321: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1322: && cc_prev_status.mdep == XEXP (operands[1], 0)))
1323: output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
1324: split_template = load_opcode (GET_MODE (dest),
1325: "l%%%m1(r31),%0", src);
1326: }
1327: else
1328: {
1329: if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
1330: && (cc_prev_status.flags & CC_HI_R31_ADJ)
1331: && cc_prev_status.mdep == XEXP (operands[0], 0)))
1332: output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
1333: split_template = store_opcode (GET_MODE (dest),
1334: "%r1,l%%%m0(r31)", src);
1335: }
1336:
1337: /* Output the branch instruction next. */
1338: output_asm_insn (template, operands);
1339:
1340: /* Now output the load or store.
1341: No need to do a CC_STATUS_INIT, because we are branching anyway. */
1342: output_asm_insn (split_template, xoperands);
1343: }
1344: else
1345: {
1346: extern char *insn_template[];
1347: extern char *(*insn_outfun[])();
1348: extern int insn_n_operands[];
1349: extern rtx alter_subreg();
1350: int insn_code_number;
1351: rtx pat = gen_rtx (SET, VOIDmode, dest, src);
1352: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
1353: int i;
1354:
1355: /* Output the branch instruction first. */
1356: output_asm_insn (template, operands);
1357:
1358: /* Now recognize the insn which we put in its delay slot.
1359: We must do this after outputing the branch insn,
1360: since operands may just be a pointer to `recog_operand'. */
1361: insn_code_number = recog (pat, delay_insn);
1362: if (insn_code_number == -1)
1363: abort ();
1364:
1365: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1366: {
1367: if (GET_CODE (recog_operand[i]) == SUBREG)
1368: recog_operand[i] = alter_subreg (recog_operand[i]);
1369: }
1370:
1371: /* Now get the template for what this insn would
1372: have been, without the branch. Its operands are
1373: exactly the same as they would be, so we don't
1374: need to do an insn_extract. */
1375: template = insn_template[insn_code_number];
1376: if (template == 0)
1377: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1378: output_asm_insn (template, recog_operand);
1379: }
1380: CC_STATUS_INIT;
1381: return "";
1382: }
1383:
1384: /* Output a newly constructed insn DELAY_INSN. */
1385: char *
1386: output_delay_insn (delay_insn)
1387: rtx delay_insn;
1388: {
1389: char *template;
1390: extern rtx recog_operand[];
1391: extern char call_used_regs[];
1392: extern char *insn_template[];
1393: extern int insn_n_operands[];
1394: extern char *(*insn_outfun[])();
1395: extern rtx alter_subreg();
1396: int insn_code_number;
1397: extern int insn_n_operands[];
1398: int i;
1399:
1400: /* Now recognize the insn which we put in its delay slot.
1401: We must do this after outputing the branch insn,
1402: since operands may just be a pointer to `recog_operand'. */
1403: insn_code_number = recog_memoized (delay_insn);
1404: if (insn_code_number == -1)
1405: abort ();
1406:
1407: /* Extract the operands of this delay insn. */
1408: INSN_CODE (delay_insn) = insn_code_number;
1409: insn_extract (delay_insn);
1410:
1411: /* It is possible that this insn has not been properly scaned by final
1412: yet. If this insn's operands don't appear in the peephole's
1413: actual operands, then they won't be fixed up by final, so we
1414: make sure they get fixed up here. -- This is a kludge. */
1415: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1416: {
1417: if (GET_CODE (recog_operand[i]) == SUBREG)
1418: recog_operand[i] = alter_subreg (recog_operand[i]);
1419: }
1420:
1421: #ifdef REGISTER_CONSTRAINTS
1422: if (! constrain_operands (insn_code_number))
1423: abort ();
1424: #endif
1425:
1426: cc_prev_status = cc_status;
1427:
1428: /* Update `cc_status' for this instruction.
1429: The instruction's output routine may change it further.
1430: If the output routine for a jump insn needs to depend
1431: on the cc status, it should look at cc_prev_status. */
1432:
1433: NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
1434:
1435: /* Now get the template for what this insn would
1436: have been, without the branch. */
1437:
1438: template = insn_template[insn_code_number];
1439: if (template == 0)
1440: template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
1441: output_asm_insn (template, recog_operand);
1442: return "";
1443: }
1444:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.