|
|
1.1 root 1: /* Subroutines for insn-output.c for HPPA.
2: Copyright (C) 1992, 1993 Free Software Foundation, Inc.
3: Contributed by Tim Moore ([email protected]), based on 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 2, 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: #include <stdio.h>
22: #include "config.h"
23: #include "rtl.h"
24: #include "regs.h"
25: #include "hard-reg-set.h"
26: #include "real.h"
27: #include "insn-config.h"
28: #include "conditions.h"
29: #include "insn-flags.h"
30: #include "output.h"
31: #include "insn-attr.h"
32: #include "flags.h"
33: #include "tree.h"
34: #include "c-tree.h"
35: #include "expr.h"
36: #include "obstack.h"
37: #include "machopic.h"
38: /* Save the operands last given to a compare for use when we
39: generate a scc or bcc insn. */
40:
41: rtx hppa_compare_op0, hppa_compare_op1;
42: enum cmp_type hppa_branch_type;
43:
44: rtx hppa_save_pic_table_rtx;
45:
46: /* Set by the FUNCTION_PROFILER macro. */
47: int hp_profile_labelno;
48: extern int profile_label_no;
49:
50: /* Counts for the number of callee-saved general and floating point
51: registers which were saved by the current function's prologue. */
52: static int gr_saved, fr_saved;
53:
54: static rtx find_addr_reg ();
55:
56: /* Return non-zero only if OP is a register of mode MODE,
57: or CONST0_RTX. */
58: int
59: reg_or_0_operand (op, mode)
60: rtx op;
61: enum machine_mode mode;
62: {
63: return (op == CONST0_RTX (mode) || register_operand (op, mode));
64: }
65:
66: /* Return non-zero if OP is suitable for use in a call to a named
67: function.
68:
69: (???) For 2.5 try to eliminate either call_operand_address or
70: function_label_operand, they perform very similar functions. */
71: int
72: call_operand_address (op, mode)
73: rtx op;
74: enum machine_mode mode;
75: {
76: return (CONSTANT_P (op) && ! TARGET_LONG_CALLS);
77: }
78:
79: /* Return 1 if X contains a symbolic expression. We know these
80: expressions will have one of a few well defined forms, so
81: we need only check those forms. */
82: int
83: symbolic_expression_p (x)
84: register rtx x;
85: {
86:
87: /* Strip off any HIGH. */
88: if (GET_CODE (x) == HIGH)
89: x = XEXP (x, 0);
90:
91: return (symbolic_operand (x, VOIDmode));
92: }
93:
94: int
95: symbolic_operand (op, mode)
96: register rtx op;
97: enum machine_mode mode;
98: {
99: switch (GET_CODE (op))
100: {
101: case SYMBOL_REF:
102: case LABEL_REF:
103: return 1;
104: case CONST:
105: op = XEXP (op, 0);
106: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
107: || GET_CODE (XEXP (op, 0)) == LABEL_REF)
108: && GET_CODE (XEXP (op, 1)) == CONST_INT);
109: default:
110: return 0;
111: }
112: }
113:
114: /* Return truth value of statement that OP is a symbolic memory
115: operand of mode MODE. */
116:
117: int
118: symbolic_memory_operand (op, mode)
119: rtx op;
120: enum machine_mode mode;
121: {
122: if (GET_CODE (op) == SUBREG)
123: op = SUBREG_REG (op);
124: if (GET_CODE (op) != MEM)
125: return 0;
126: op = XEXP (op, 0);
127: return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
128: || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
129: }
130:
131: /* Return 1 if the operand is either a register or a memory operand that is
132: not symbolic. */
133:
134: int
135: reg_or_nonsymb_mem_operand (op, mode)
136: register rtx op;
137: enum machine_mode mode;
138: {
139: if (register_operand (op, mode))
140: return 1;
141:
142: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
143: return 1;
144:
145: return 0;
146: }
147:
148: /* Return 1 if the operand is either a register, zero, or a memory operand
149: that is not symbolic. */
150:
151: int
152: reg_or_0_or_nonsymb_mem_operand (op, mode)
153: register rtx op;
154: enum machine_mode mode;
155: {
156: if (register_operand (op, mode))
157: return 1;
158:
159: if (op == CONST0_RTX (mode))
160: return 1;
161:
162: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
163: return 1;
164:
165: return 0;
166: }
167:
168: /* Accept any constant that can be moved in one instructions into a
169: general register. */
170: int
171: cint_ok_for_move (intval)
172: int intval;
173: {
174: /* OK if ldo, ldil, or zdepi, can be used. */
175: return (VAL_14_BITS_P (intval) || (intval & RIGHT_BITS_MASK) == 0
176: || zdepi_cint_p (intval));
177: }
178:
179: /* Accept anything that can be moved in one instruction into a general
180: register. */
181: int
182: move_operand (op, mode)
183: rtx op;
184: enum machine_mode mode;
185: {
186: if (register_operand (op, mode))
187: return 1;
188:
189: if (GET_CODE (op) == CONST_INT)
190: return cint_ok_for_move (INTVAL (op));
191:
192: if (GET_MODE (op) != mode)
193: return 0;
194: if (GET_CODE (op) == SUBREG)
195: op = SUBREG_REG (op);
196: if (GET_CODE (op) != MEM)
197: return 0;
198:
199: op = XEXP (op, 0);
200: if (GET_CODE (op) == LO_SUM)
201: return (register_operand (XEXP (op, 0), Pmode)
202: && CONSTANT_P (XEXP (op, 1)));
203: return memory_address_p (mode, op);
204: }
205:
206: /* Accept REG and any CONST_INT that can be moved in one instruction into a
207: general register. */
208: int
209: reg_or_cint_move_operand (op, mode)
210: rtx op;
211: enum machine_mode mode;
212: {
213: if (register_operand (op, mode))
214: return 1;
215:
216: if (GET_CODE (op) == CONST_INT)
217: return cint_ok_for_move (INTVAL (op));
218:
219: return 0;
220: }
221:
222: int
223: pic_operand (op, mode)
224: rtx op;
225: enum machine_mode mode;
226: {
227: return flag_pic && GET_CODE (op) == LABEL_REF;
228: }
229:
230: int
231: fp_reg_operand (op, mode)
232: rtx op;
233: enum machine_mode mode;
234: {
235: return reg_renumber && FP_REG_P (op);
236: }
237:
238:
239: extern int current_function_uses_pic_offset_table;
240: extern rtx force_reg (), validize_mem ();
241:
242: /* The rtx for the global offset table which is a special form
243: that *is* a position independent symbolic constant. */
244: rtx pic_pc_rtx;
245:
246: /* Ensure that we are not using patterns that are not OK with PIC. */
247:
248: int
249: check_pic (i)
250: int i;
251: {
252: extern rtx recog_operand[];
253: switch (flag_pic)
254: {
255: case 1:
256: if (GET_CODE (recog_operand[i]) == SYMBOL_REF
257: || (GET_CODE (recog_operand[i]) == CONST
258: && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
259: abort ();
260: case 2:
261: default:
262: return 1;
263: }
264: }
265:
266: /* Return truth value of whether OP can be used as an operand in a
267: three operand arithmetic insn that accepts registers of mode MODE
268: or 14-bit signed integers. */
269: int
270: arith_operand (op, mode)
271: rtx op;
272: enum machine_mode mode;
273: {
274: return (register_operand (op, mode)
275: || (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));
276: }
277:
278: /* Return truth value of whether OP can be used as an operand in a
279: three operand arithmetic insn that accepts registers of mode MODE
280: or 11-bit signed integers. */
281: int
282: arith11_operand (op, mode)
283: rtx op;
284: enum machine_mode mode;
285: {
286: return (register_operand (op, mode)
287: || (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));
288: }
289:
290: /* A constant integer suitable for use in a PRE_MODIFY memory
291: reference. */
292: int
293: pre_cint_operand (op, mode)
294: rtx op;
295: enum machine_mode mode;
296: {
297: return (GET_CODE (op) == CONST_INT
298: && INTVAL (op) >= -0x2000 && INTVAL (op) < 0x10);
299: }
300:
301: /* A constant integer suitable for use in a POST_MODIFY memory
302: reference. */
303: int
304: post_cint_operand (op, mode)
305: rtx op;
306: enum machine_mode mode;
307: {
308: return (GET_CODE (op) == CONST_INT
309: && INTVAL (op) < 0x2000 && INTVAL (op) >= -0x10);
310: }
311:
312: int
313: arith_double_operand (op, mode)
314: rtx op;
315: enum machine_mode mode;
316: {
317: return (register_operand (op, mode)
318: || (GET_CODE (op) == CONST_DOUBLE
319: && GET_MODE (op) == mode
320: && VAL_14_BITS_P (CONST_DOUBLE_LOW (op))
321: && (CONST_DOUBLE_HIGH (op) >= 0
322: == ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
323: }
324:
325: /* Return truth value of whether OP is a integer which fits the
326: range constraining immediate operands in three-address insns. */
327:
328: int
329: int5_operand (op, mode)
330: rtx op;
331: enum machine_mode mode;
332: {
333: return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));
334: }
335:
336: int
337: uint5_operand (op, mode)
338: rtx op;
339: enum machine_mode mode;
340: {
341: return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));
342: }
343:
344:
345: int
346: int11_operand (op, mode)
347: rtx op;
348: enum machine_mode mode;
349: {
350: return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));
351: }
352:
353: int
354: arith5_operand (op, mode)
355: rtx op;
356: enum machine_mode mode;
357: {
358: return register_operand (op, mode) || int5_operand (op, mode);
359: }
360:
361: /* True iff zdepi can be used to generate this CONST_INT. */
362: int
363: zdepi_cint_p (x)
364: unsigned x;
365: {
366: unsigned lsb_mask, t;
367:
368: /* This might not be obvious, but it's at least fast.
369: This function is critcal; we don't have the time loops would take. */
370: lsb_mask = x & -x;
371: t = ((x >> 4) + lsb_mask) & ~(lsb_mask - 1);
372: /* Return true iff t is a power of two. */
373: return ((t & (t - 1)) == 0);
374: }
375:
376: /* True iff depi or extru can be used to compute (reg & mask). */
377: int
378: and_mask_p (mask)
379: unsigned mask;
380: {
381: mask = ~mask;
382: mask += mask & -mask;
383: return (mask & (mask - 1)) == 0;
384: }
385:
386: /* True iff depi or extru can be used to compute (reg & OP). */
387: int
388: and_operand (op, mode)
389: rtx op;
390: enum machine_mode mode;
391: {
392: return (register_operand (op, mode)
393: || (GET_CODE (op) == CONST_INT && and_mask_p (INTVAL (op))));
394: }
395:
396: /* True iff depi can be used to compute (reg | MASK). */
397: int
398: ior_mask_p (mask)
399: unsigned mask;
400: {
401: mask += mask & -mask;
402: return (mask & (mask - 1)) == 0;
403: }
404:
405: /* True iff depi can be used to compute (reg | OP). */
406: int
407: ior_operand (op, mode)
408: rtx op;
409: enum machine_mode mode;
410: {
411: return (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op)));
412: }
413:
414: int
415: lhs_lshift_operand (op, mode)
416: rtx op;
417: enum machine_mode mode;
418: {
419: return register_operand (op, mode) || lhs_lshift_cint_operand (op, mode);
420: }
421:
422: /* True iff OP is a CONST_INT of the forms 0...0xxxx or 0...01...1xxxx.
423: Such values can be the left hand side x in (x << r), using the zvdepi
424: instruction. */
425: int
426: lhs_lshift_cint_operand (op, mode)
427: rtx op;
428: enum machine_mode mode;
429: {
430: unsigned x;
431: if (GET_CODE (op) != CONST_INT)
432: return 0;
433: x = INTVAL (op) >> 4;
434: return (x & (x + 1)) == 0;
435: }
436:
437: int
438: arith32_operand (op, mode)
439: rtx op;
440: enum machine_mode mode;
441: {
442: return register_operand (op, mode) || GET_CODE (op) == CONST_INT;
443: }
444:
445: int
446: pc_or_label_operand (op, mode)
447: rtx op;
448: enum machine_mode mode;
449: {
450: return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
451: }
452:
453: int
454: code_label_operand (op, mode)
455: rtx op;
456: enum machine_mode mode;
457: {
458: return (GET_CODE (op) == CODE_LABEL);
459: }
460:
461: /* Legitimize PIC addresses. If the address is already
462: position-independent, we return ORIG. Newly generated
463: position-independent addresses go to REG. If we need more
464: than one register, we lose. */
465:
466: rtx
467: legitimize_pic_address (orig, mode, reg)
468: rtx orig, reg;
469: enum machine_mode mode;
470: {
471: rtx pic_ref = orig;
472:
473: #ifdef MACHO_PIC
474: return machopic_legitimize_pic_address (orig, mode, reg);
475: #endif
476:
477: if (GET_CODE (orig) == SYMBOL_REF)
478: {
479: if (reg == 0)
480: abort ();
481:
482: if (flag_pic == 2)
483: {
484: emit_insn (gen_rtx (SET, VOIDmode, reg,
485: gen_rtx (HIGH, Pmode, orig)));
486: emit_insn (gen_rtx (SET, VOIDmode, reg,
487: gen_rtx (LO_SUM, Pmode, reg, orig)));
488: orig = reg;
489: }
490: pic_ref = gen_rtx (MEM, Pmode,
491: gen_rtx (PLUS, Pmode,
492: pic_offset_table_rtx, orig));
493: current_function_uses_pic_offset_table = 1;
494: RTX_UNCHANGING_P (pic_ref) = 1;
495: emit_move_insn (reg, pic_ref);
496: return reg;
497: }
498: else if (GET_CODE (orig) == CONST)
499: {
500: rtx base;
501:
502: if (GET_CODE (XEXP (orig, 0)) == PLUS
503: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
504: return orig;
505:
506: if (reg == 0)
507: abort ();
508:
509: if (GET_CODE (XEXP (orig, 0)) == PLUS)
510: {
511: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
512: orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
513: base == reg ? 0 : reg);
514: }
515: else abort ();
516: if (GET_CODE (orig) == CONST_INT)
517: {
518: if (INT_14_BITS (orig))
519: return plus_constant_for_output (base, INTVAL (orig));
520: orig = force_reg (Pmode, orig);
521: }
522: pic_ref = gen_rtx (PLUS, Pmode, base, orig);
523: /* Likewise, should we set special REG_NOTEs here? */
524: }
525: return pic_ref;
526: }
527:
528: /* Set up PIC-specific rtl. This should not cause any insns
529: to be emitted. */
530:
531: void
532: initialize_pic ()
533: {
534: }
535:
536: /* Emit special PIC prologues and epilogues. */
537:
538: void
539: finalize_pic ()
540: {
541: rtx insn = get_insns ();
542:
543: while (GET_CODE (insn) == NOTE)
544: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
545: break;
546: else
547: insn = NEXT_INSN (insn);
548:
549:
550: #ifdef NeXT_ASM
551: if (current_function_uses_pic_offset_table)
552: {
553: rtx label = gen_label_rtx ();
554: rtx target = gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM);
555: XSTR (label, 4) = machopic_function_base_name ();
556: insn = emit_jump_insn_after (gen_branch_and_link (label, target), insn);
557: insn = emit_label_after (label, insn);
558: LABEL_PRESERVE_P (label) = 1;
559: insn = emit_insn_after (gen_andsi3 (target, target,
560: gen_rtx (CONST_INT, SImode, ~3UL)),
561: insn);
562: }
563: #endif
564:
565: if (hppa_save_pic_table_rtx)
566: {
567: emit_insn_after (gen_rtx (SET, VOIDmode,
568: hppa_save_pic_table_rtx,
569: gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)),
570: insn);
571: /* Need to emit this whether or not we obey regdecls,
572: since setjmp/longjmp can cause life info to screw up. */
573: hppa_save_pic_table_rtx = 0;
574: }
575:
576: emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
577: }
578:
579: /* Try machine-dependent ways of modifying an illegitimate address
580: to be legitimate. If we find one, return the new, valid address.
581: This macro is used in only one place: `memory_address' in explow.c.
582:
583: OLDX is the address as it was before break_out_memory_refs was called.
584: In some cases it is useful to look at this to decide what needs to be done.
585:
586: MODE and WIN are passed so that this macro can use
587: GO_IF_LEGITIMATE_ADDRESS.
588:
589: It is always safe for this macro to do nothing. It exists to recognize
590: opportunities to optimize the output.
591:
592: For the PA, transform:
593:
594: memory(X + <large int>)
595:
596: into:
597:
598: if (<large int> & mask) >= 16
599: Y = (<large int> & ~mask) + mask + 1 Round up.
600: else
601: Y = (<large int> & ~mask) Round down.
602: Z = X + Y
603: memory (Z + (<large int> - Y));
604:
605: This is for CSE to find several similar references, and only use one Z.
606:
607: X can either be a SYMBOL_REF or REG, but because combine can not
608: perform a 4->2 combination we do nothing for SYMBOL_REF + D where
609: D will not fit in 14 bits.
610:
611: MODE_FLOAT references allow displacements which fit in 5 bits, so use
612: 0x1f as the mask.
613:
614: MODE_INT references allow displacements which fit in 14 bits, so use
615: 0x3fff as the mask.
616:
617: This relies on the fact that most mode MODE_FLOAT references will use FP
618: registers and most mode MODE_INT references will use integer registers.
619: (In the rare case of an FP register used in an integer MODE, we depend
620: on secondary reloads to clean things up.)
621:
622:
623: It is also beneficial to handle (plus (mult (X) (Y)) (Z)) in a special
624: manner if Y is 2, 4, or 8. (allows more shadd insns and shifted indexed
625: adressing modes to be used).
626:
627: Put X and Z into registers. Then put the entire expression into
628: a register. */
629:
630: rtx
631: hppa_legitimize_address (x, oldx, mode)
632: rtx x, oldx;
633: enum machine_mode mode;
634: {
635:
636: rtx orig = x;
637:
638: /* Strip off CONST. */
639: if (GET_CODE (x) == CONST)
640: x = XEXP (x, 0);
641:
642: if (GET_CODE (x) == PLUS
643: && GET_CODE (XEXP (x, 1)) == CONST_INT
644: && (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
645: || GET_CODE (XEXP (x, 0)) == REG))
646: {
647: rtx int_part, ptr_reg;
648: int newoffset;
649: int offset = INTVAL (XEXP (x, 1));
650: int mask = GET_MODE_CLASS (mode) == MODE_FLOAT ? 0x1f : 0x3fff;
651:
652: /* Choose which way to round the offset. Round up if we
653: are >= halfway to the next boundary. */
654: if ((offset & mask) >= ((mask + 1) / 2))
655: newoffset = (offset & ~ mask) + mask + 1;
656: else
657: newoffset = (offset & ~ mask);
658:
659: /* If the newoffset will not fit in 14 bits (ldo), then
660: handling this would take 4 or 5 instructions (2 to load
661: the SYMBOL_REF + 1 or 2 to load the newoffset + 1 to
662: add the new offset and the SYMBOL_REF.) Combine can
663: not handle 4->2 or 5->2 combinations, so do not create
664: them. */
665: if (! VAL_14_BITS_P (newoffset)
666: && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
667: {
668: rtx const_part = gen_rtx (CONST, VOIDmode,
669: gen_rtx (PLUS, Pmode,
670: XEXP (x, 0),
671: GEN_INT (newoffset)));
672: rtx tmp_reg
673: = force_reg (Pmode,
674: gen_rtx (HIGH, Pmode, const_part));
675: ptr_reg
676: = force_reg (Pmode,
677: gen_rtx (LO_SUM, Pmode,
678: tmp_reg, const_part));
679: }
680: else
681: {
682: if (! VAL_14_BITS_P (newoffset))
683: int_part = force_reg (Pmode, GEN_INT (newoffset));
684: else
685: int_part = GEN_INT (newoffset);
686:
687: ptr_reg = force_reg (Pmode,
688: gen_rtx (PLUS, Pmode,
689: force_reg (Pmode, XEXP (x, 0)),
690: int_part));
691: }
692: return plus_constant (ptr_reg, offset - newoffset);
693: }
694:
695: /* Try to arrange things so that indexing modes can be used, but
696: only do so if indexing is safe.
697:
698: Indexing is safe when the second operand for the outer PLUS
699: is a REG, SUBREG, SYMBOL_REF or the like.
700:
701: For 2.5, indexing is also safe for (plus (symbol_ref) (const_int))
702: if the integer is > 0. */
703: if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT
704: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
705: && shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1)))
706: && (GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == 'o'
707: || GET_CODE (XEXP (x, 1)) == SUBREG)
708: && GET_CODE (XEXP (x, 1)) != CONST)
709: {
710: int val = INTVAL (XEXP (XEXP (x, 0), 1));
711: rtx reg1, reg2;
712: reg1 = force_reg (Pmode, force_operand (XEXP (x, 1), 0));
713: reg2 = force_reg (Pmode,
714: force_operand (XEXP (XEXP (x, 0), 0), 0));
715: return force_reg (Pmode,
716: gen_rtx (PLUS, Pmode,
717: gen_rtx (MULT, Pmode, reg2,
718: GEN_INT (val)),
719: reg1));
720: }
721:
722: /* Uh-oh. We might have an address for x[n-100000]. This needs
723: special handling. */
724:
725: if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT
726: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
727: && shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
728: {
729: /* Ugly. We modify things here so that the address offset specified
730: by the index expression is computed first, then added to x to form
731: the entire address.
732:
733: For 2.5, it might be profitable to set things up so that we
734: compute the raw (unscaled) index first, then use scaled indexing
735: to access memory, or better yet have the MI parts of the compiler
736: handle this. */
737:
738: rtx regx1, regy1, regy2, y;
739:
740: /* Strip off any CONST. */
741: y = XEXP (x, 1);
742: if (GET_CODE (y) == CONST)
743: y = XEXP (y, 0);
744:
745: if (GET_CODE (y) == PLUS || GET_CODE (y) == MINUS)
746: {
747: regx1 = force_reg (Pmode, force_operand (XEXP (x, 0), 0));
748: regy1 = force_reg (Pmode, force_operand (XEXP (y, 0), 0));
749: regy2 = force_reg (Pmode, force_operand (XEXP (y, 1), 0));
750: regx1 = force_reg (Pmode, gen_rtx (GET_CODE (y), Pmode, regx1, regy2));
751: return force_reg (Pmode, gen_rtx (PLUS, Pmode, regx1, regy1));
752: }
753: }
754:
755: if (flag_pic)
756: return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
757:
758: return orig;
759: }
760:
761: /* For the HPPA, REG and REG+CONST is cost 0
762: and addresses involving symbolic constants are cost 2.
763:
764: PIC addresses are very expensive.
765:
766: It is no coincidence that this has the same structure
767: as GO_IF_LEGITIMATE_ADDRESS. */
768: int
769: hppa_address_cost (X)
770: rtx X;
771: {
772: if (GET_CODE (X) == PLUS)
773: return 1;
774: else if (GET_CODE (X) == LO_SUM)
775: return 1;
776: else if (GET_CODE (X) == HIGH)
777: return 2;
778: return 4;
779: }
780:
781: /* Emit insns to move operands[1] into operands[0].
782:
783: Return 1 if we have written out everything that needs to be done to
784: do the move. Otherwise, return 0 and the caller will emit the move
785: normally. */
786:
787: int
788: emit_move_sequence (operands, mode, scratch_reg)
789: rtx *operands;
790: enum machine_mode mode;
791: rtx scratch_reg;
792: {
793: register rtx operand0 = operands[0];
794: register rtx operand1 = operands[1];
795:
796: /* Handle secondary reloads for loads/stores of FP registers from
797: REG+D addresses where D does not fit in 5 bits. */
798: if (fp_reg_operand (operand0, mode)
799: && GET_CODE (operand1) == MEM
800: /* Using DFmode forces only short displacements be be
801: recognized as valid in reg+d addressing modes. */
802: && ! memory_address_p (DFmode, XEXP (operand1, 0))
803: && scratch_reg)
804: {
805: emit_move_insn (scratch_reg, XEXP (operand1 , 0));
806: emit_insn (gen_rtx (SET, VOIDmode, operand0, gen_rtx (MEM, mode,
807: scratch_reg)));
808: return 1;
809: }
810: else if (fp_reg_operand (operand1, mode)
811: && GET_CODE (operand0) == MEM
812: /* Using DFmode forces only short displacements be be
813: recognized as valid in reg+d addressing modes. */
814: && ! memory_address_p (DFmode, XEXP (operand0, 0))
815: && scratch_reg)
816: {
817: emit_move_insn (scratch_reg, XEXP (operand0 , 0));
818: emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, mode, scratch_reg),
819: operand1));
820: return 1;
821: }
822: /* Handle secondary reloads for loads of FP registers from constant
823: expressions by forcing the constant into memory.
824:
825: use scratch_reg to hold the address of the memory location.
826:
827: ??? The proper fix is to change PREFERRED_RELOAD_CLASS to return
828: NO_REGS when presented with a const_int and an register class
829: containing only FP registers. Doing so unfortunately creates
830: more problems than it solves. Fix this for 2.5. */
831: else if (fp_reg_operand (operand0, mode)
832: && CONSTANT_P (operand1)
833: && scratch_reg)
834: {
835: rtx xoperands[2];
836:
837: /* Force the constant into memory and put the address of the
838: memory location into scratch_reg. */
839: xoperands[0] = scratch_reg;
840: xoperands[1] = XEXP (force_const_mem (mode, operand1), 0);
841: emit_move_sequence (xoperands, Pmode, 0);
842:
843: /* Now load the destination register. */
844: emit_insn (gen_rtx (SET, mode, operand0,
845: gen_rtx (MEM, mode, scratch_reg)));
846: return 1;
847: }
848: /* Handle secondary reloads for SAR. These occur when trying to load
849: the SAR from memory or from a FP register. */
850: else if (GET_CODE (operand0) == REG
851: && REGNO_REG_CLASS (REGNO (operand0)) == SHIFT_REGS
852: && (GET_CODE (operand1) == MEM
853: || (GET_CODE (operand1) == REG
854: && FP_REG_CLASS_P (REGNO_REG_CLASS (REGNO (operand1)))))
855: && scratch_reg)
856: {
857: emit_move_insn (scratch_reg, operand1);
858: emit_move_insn (operand0, scratch_reg);
859: return 1;
860: }
861: /* Handle most common case: storing into a register. */
862: else if (register_operand (operand0, mode))
863: {
864: if (register_operand (operand1, mode)
865: || (GET_CODE (operand1) == CONST_INT && INT_14_BITS (operand1))
866: || (operand1 == CONST0_RTX (mode))
867: || (GET_CODE (operand1) == HIGH
868: && !symbolic_operand (XEXP (operand1, 0)))
869: /* Only `general_operands' can come here, so MEM is ok. */
870: || GET_CODE (operand1) == MEM)
871: {
872: /* Run this case quickly. */
873: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
874: return 1;
875: }
876: }
877: else if (GET_CODE (operand0) == MEM)
878: {
879: if (register_operand (operand1, mode) || operand1 == CONST0_RTX (mode))
880: {
881: /* Run this case quickly. */
882: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
883: return 1;
884: }
885: if (! (reload_in_progress || reload_completed))
886: {
887: operands[0] = validize_mem (operand0);
888: operands[1] = operand1 = force_reg (mode, operand1);
889: }
890: }
891:
892: /* Simplify the source if we need to. */
893: if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
894: || (GET_CODE (operand1) == HIGH
895: && symbolic_operand (XEXP (operand1, 0), mode)))
896: {
897: int ishighonly = 0;
898:
899: if (GET_CODE (operand1) == HIGH)
900: {
901: ishighonly = 1;
902: operand1 = XEXP (operand1, 0);
903: }
904: if (symbolic_operand (operand1, mode))
905: {
906: if (flag_pic)
907: {
908: rtx temp;
909:
910: if (reload_in_progress || reload_completed)
911: temp = operand0;
912: else
913: temp = gen_reg_rtx (Pmode);
914:
915: operands[1] = legitimize_pic_address (operand1, mode, temp);
916: emit_insn (gen_rtx (SET, VOIDmode, operand0, operands[1]));
917: }
918: /* On the HPPA, references to data space are supposed to */
919: /* use dp, register 27, but showing it in the RTL inhibits various
920: cse and loop optimizations. */
921: else
922: {
923: rtx temp, set;
924:
925: if (reload_in_progress || reload_completed)
926: temp = scratch_reg ? scratch_reg : operand0;
927: else
928: temp = gen_reg_rtx (mode);
929:
930: if (ishighonly)
931: set = gen_rtx (SET, mode, operand0, temp);
932: else
933: set = gen_rtx (SET, VOIDmode,
934: operand0,
935: gen_rtx (LO_SUM, mode, temp, operand1));
936:
937: emit_insn (gen_rtx (SET, VOIDmode,
938: temp,
939: gen_rtx (HIGH, mode, operand1)));
940: if (function_label_operand (operand1, mode))
941: {
942: rtx temp;
943:
944: if (reload_in_progress || reload_completed)
945: temp = scratch_reg;
946: else
947: temp = gen_reg_rtx (mode);
948:
949: if (!temp)
950: abort ();
951: emit_insn (gen_rtx (PARALLEL, VOIDmode,
952: gen_rtvec (2,
953: set,
954: gen_rtx (CLOBBER, VOIDmode,
955: temp))));
956: }
957: else
958: emit_insn (set);
959: return 1;
960: }
961: return 1;
962: }
963: else if (GET_CODE (operand1) != CONST_INT
964: || ! cint_ok_for_move (INTVAL (operand1)))
965: {
966: rtx temp;
967:
968: if (reload_in_progress || reload_completed)
969: temp = operand0;
970: else
971: temp = gen_reg_rtx (mode);
972:
973: emit_insn (gen_rtx (SET, VOIDmode, temp,
974: gen_rtx (HIGH, mode, operand1)));
975: operands[1] = gen_rtx (LO_SUM, mode, temp, operand1);
976: }
977: }
978: /* Now have insn-emit do whatever it normally does. */
979: return 0;
980: }
981:
982: /* Does operand (which is a symbolic_operand) live in text space? If
983: so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true. */
984:
985: int
986: read_only_operand (operand)
987: rtx operand;
988: {
989: if (GET_CODE (operand) == CONST)
990: operand = XEXP (XEXP (operand, 0), 0);
991: if (GET_CODE (operand) == SYMBOL_REF)
992: return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
993: return 1;
994: }
995:
996:
997: /* Return the best assembler insn template
998: for moving operands[1] into operands[0] as a fullword. */
999: char *
1000: singlemove_string (operands)
1001: rtx *operands;
1002: {
1003: if (GET_CODE (operands[0]) == MEM)
1004: return "stw %r1,%0";
1005: else if (GET_CODE (operands[1]) == MEM)
1006: return "ldw %1,%0";
1007: else if (GET_CODE (operands[1]) == CONST_DOUBLE
1008: && GET_MODE (operands[1]) == SFmode)
1009: {
1010: int i;
1011: union real_extract u;
1012: union float_extract { float f; int i; } v;
1013:
1014: bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u);
1015: v.f = REAL_VALUE_TRUNCATE (SFmode, u.d);
1016: i = v.i;
1017:
1018: operands[1] = gen_rtx (CONST_INT, VOIDmode, i);
1019:
1020: /* See if we can handle this constant in a single instruction. */
1021: if (cint_ok_for_move (INTVAL (operands[1])))
1022: {
1023: int intval = INTVAL (operands[1]);
1024:
1025: if (intval == 0)
1026: return "copy 0,%0";
1027: else if (VAL_14_BITS_P (intval))
1028: return "ldi %1,%0";
1029: else if ((intval & RIGHT_BITS_MASK) == 0)
1030: return "ldil L%'%1,%0";
1031: else if (zdepi_cint_p (intval))
1032: return "zdepi %Z1,%0";
1033: }
1034: else
1035: return "ldil L%'%1,%0\n\tldo R%'%1(%0),%0";
1036: }
1037:
1038: else if (GET_CODE (operands[1]) == CONST_INT)
1039: {
1040: /* See if we can handle this in a single instruction. */
1041: if (cint_ok_for_move (INTVAL (operands[1])))
1042: {
1043: int intval = INTVAL (operands[1]);
1044:
1045: if (intval == 0)
1046: return "copy 0,%0";
1047: else if (VAL_14_BITS_P (intval))
1048: return "ldi %1,%0";
1049: else if ((intval & RIGHT_BITS_MASK) == 0)
1050: return "ldil L%'%1,%0";
1051: else if (zdepi_cint_p (intval))
1052: return "zdepi %Z1,%0";
1053: }
1054: else
1055: return "ldil L%'%1,%0\n\tldo R%'%1(%0),%0";
1056: }
1057: return "copy %1,%0";
1058: }
1059:
1060:
1061: /* Compute position (in OP[1]) and width (in OP[2])
1062: useful for copying IMM to a register using the zdepi
1063: instructions. Store the immediate value to insert in OP[0]. */
1064: void
1065: compute_zdepi_operands (imm, op)
1066: unsigned imm;
1067: unsigned *op;
1068: {
1069: int lsb, len;
1070:
1071: /* Find the least significant set bit in IMM. */
1072: for (lsb = 0; lsb < 32; lsb++)
1073: {
1074: if ((imm & 1) != 0)
1075: break;
1076: imm >>= 1;
1077: }
1078:
1079: /* Choose variants based on *sign* of the 5-bit field. */
1080: if ((imm & 0x10) == 0)
1081: len = (lsb <= 28) ? 4 : 32 - lsb;
1082: else
1083: {
1084: /* Find the width of the bitstring in IMM. */
1085: for (len = 5; len < 32; len++)
1086: {
1087: if ((imm & (1 << len)) == 0)
1088: break;
1089: }
1090:
1091: /* Sign extend IMM as a 5-bit value. */
1092: imm = (imm & 0xf) - 0x10;
1093: }
1094:
1095: op[0] = imm;
1096: op[1] = 31 - lsb;
1097: op[2] = len;
1098: }
1099:
1100: /* Output assembler code to perform a doubleword move insn
1101: with operands OPERANDS. */
1102:
1103: char *
1104: output_move_double (operands)
1105: rtx *operands;
1106: {
1107: enum { REGOP, OFFSOP, MEMOP, CNSTOP, RNDOP } optype0, optype1;
1108: rtx latehalf[2];
1109: rtx addreg0 = 0, addreg1 = 0;
1110:
1111: /* First classify both operands. */
1112:
1113: if (REG_P (operands[0]))
1114: optype0 = REGOP;
1115: else if (offsettable_memref_p (operands[0]))
1116: optype0 = OFFSOP;
1117: else if (GET_CODE (operands[0]) == MEM)
1118: optype0 = MEMOP;
1119: else
1120: optype0 = RNDOP;
1121:
1122: if (REG_P (operands[1]))
1123: optype1 = REGOP;
1124: else if (CONSTANT_P (operands[1]))
1125: optype1 = CNSTOP;
1126: else if (offsettable_memref_p (operands[1]))
1127: optype1 = OFFSOP;
1128: else if (GET_CODE (operands[1]) == MEM)
1129: optype1 = MEMOP;
1130: else
1131: optype1 = RNDOP;
1132:
1133: /* Check for the cases that the operand constraints are not
1134: supposed to allow to happen. Abort if we get one,
1135: because generating code for these cases is painful. */
1136:
1137: if (optype0 != REGOP && optype1 != REGOP)
1138: abort ();
1139:
1140: /* Handle auto decrementing and incrementing loads and stores
1141: specifically, since the structure of the function doesn't work
1142: for them without major modification. Do it better when we learn
1143: this port about the general inc/dec addressing of PA.
1144: (This was written by tege. Chide him if it doesn't work.) */
1145:
1146: if (optype0 == MEMOP)
1147: {
1148: /* We have to output the address syntax ourselves, since print_operand
1149: doesn't deal with the addresses we want to use. Fix this later. */
1150:
1151: rtx addr = XEXP (operands[0], 0);
1152: if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)
1153: {
1154: rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0);
1155:
1156: operands[0] = XEXP (addr, 0);
1157: if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
1158: abort ();
1159:
1160: if (!reg_overlap_mentioned_p (high_reg, addr))
1161: {
1162: /* No overlap between high target register and address
1163: register. (We do this in a non-obvious way to
1164: save a register file writeback) */
1165: if (GET_CODE (addr) == POST_INC)
1166: return "stws,ma %1,8(0,%0)\n\tstw %R1,-4(0,%0)";
1167: return "stws,ma %1,-8(0,%0)\n\tstw %R1,12(0,%0)";
1168: }
1169: else
1170: abort();
1171: }
1172: else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
1173: {
1174: rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0);
1175:
1176: operands[0] = XEXP (addr, 0);
1177: if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
1178: abort ();
1179:
1180: if (!reg_overlap_mentioned_p (high_reg, addr))
1181: {
1182: /* No overlap between high target register and address
1183: register. (We do this in a non-obvious way to
1184: save a register file writeback) */
1185: if (GET_CODE (addr) == PRE_INC)
1186: return "stws,mb %1,8(0,%0)\n\tstw %R1,4(0,%0)";
1187: return "stws,mb %1,-8(0,%0)\n\tstw %R1,4(0,%0)";
1188: }
1189: else
1190: abort();
1191: }
1192: }
1193: if (optype1 == MEMOP)
1194: {
1195: /* We have to output the address syntax ourselves, since print_operand
1196: doesn't deal with the addresses we want to use. Fix this later. */
1197:
1198: rtx addr = XEXP (operands[1], 0);
1199: if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)
1200: {
1201: rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0);
1202:
1203: operands[1] = XEXP (addr, 0);
1204: if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
1205: abort ();
1206:
1207: if (!reg_overlap_mentioned_p (high_reg, addr))
1208: {
1209: /* No overlap between high target register and address
1210: register. (We do this in a non-obvious way to
1211: save a register file writeback) */
1212: if (GET_CODE (addr) == POST_INC)
1213: return "ldws,ma 8(0,%1),%0\n\tldw -4(0,%1),%R0";
1214: return "ldws,ma -8(0,%1),%0\n\tldw 12(0,%1),%R0";
1215: }
1216: else
1217: {
1218: /* This is an undefined situation. We should load into the
1219: address register *and* update that register. Probably
1220: we don't need to handle this at all. */
1221: if (GET_CODE (addr) == POST_INC)
1222: return "ldw 4(0,%1),%R0\n\tldws,ma 8(0,%1),%0";
1223: return "ldw 4(0,%1),%R0\n\tldws,ma -8(0,%1),%0";
1224: }
1225: }
1226: else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
1227: {
1228: rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0);
1229:
1230: operands[1] = XEXP (addr, 0);
1231: if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
1232: abort ();
1233:
1234: if (!reg_overlap_mentioned_p (high_reg, addr))
1235: {
1236: /* No overlap between high target register and address
1237: register. (We do this in a non-obvious way to
1238: save a register file writeback) */
1239: if (GET_CODE (addr) == PRE_INC)
1240: return "ldws,mb 8(0,%1),%0\n\tldw 4(0,%1),%R0";
1241: return "ldws,mb -8(0,%1),%0\n\tldw 4(0,%1),%R0";
1242: }
1243: else
1244: {
1245: /* This is an undefined situation. We should load into the
1246: address register *and* update that register. Probably
1247: we don't need to handle this at all. */
1248: if (GET_CODE (addr) == PRE_INC)
1249: return "ldw 12(0,%1),%R0\n\tldws,mb 8(0,%1),%0";
1250: return "ldw -4(0,%1),%R0\n\tldws,mb -8(0,%1),%0";
1251: }
1252: }
1253: }
1254:
1255: /* If an operand is an unoffsettable memory ref, find a register
1256: we can increment temporarily to make it refer to the second word. */
1257:
1258: if (optype0 == MEMOP)
1259: addreg0 = find_addr_reg (XEXP (operands[0], 0));
1260:
1261: if (optype1 == MEMOP)
1262: addreg1 = find_addr_reg (XEXP (operands[1], 0));
1263:
1264: /* Ok, we can do one word at a time.
1265: Normally we do the low-numbered word first.
1266:
1267: In either case, set up in LATEHALF the operands to use
1268: for the high-numbered word and in some cases alter the
1269: operands in OPERANDS to be suitable for the low-numbered word. */
1270:
1271: if (optype0 == REGOP)
1272: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
1273: else if (optype0 == OFFSOP)
1274: latehalf[0] = adj_offsettable_operand (operands[0], 4);
1275: else
1276: latehalf[0] = operands[0];
1277:
1278: if (optype1 == REGOP)
1279: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
1280: else if (optype1 == OFFSOP)
1281: latehalf[1] = adj_offsettable_operand (operands[1], 4);
1282: else if (optype1 == CNSTOP)
1283: split_double (operands[1], &operands[1], &latehalf[1]);
1284: else
1285: latehalf[1] = operands[1];
1286:
1287: /* If the first move would clobber the source of the second one,
1288: do them in the other order.
1289:
1290: RMS says "This happens only for registers;
1291: such overlap can't happen in memory unless the user explicitly
1292: sets it up, and that is an undefined circumstance."
1293:
1294: but it happens on the HP-PA when loading parameter registers,
1295: so I am going to define that circumstance, and make it work
1296: as expected. */
1297:
1298: if (optype0 == REGOP && (optype1 == MEMOP || optype1 == OFFSOP)
1299: && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
1300: {
1301: /* XXX THIS PROBABLY DOESN'T WORK. */
1302: /* Do the late half first. */
1303: if (addreg1)
1304: output_asm_insn ("ldo 4(%0),%0", &addreg1);
1305: output_asm_insn (singlemove_string (latehalf), latehalf);
1306: if (addreg1)
1307: output_asm_insn ("ldo -4(%0),%0", &addreg1);
1308: /* Then clobber. */
1309: return singlemove_string (operands);
1310: }
1311:
1312: if (optype0 == REGOP && optype1 == REGOP
1313: && REGNO (operands[0]) == REGNO (operands[1]) + 1)
1314: {
1315: output_asm_insn (singlemove_string (latehalf), latehalf);
1316: return singlemove_string (operands);
1317: }
1318:
1319: /* Normal case: do the two words, low-numbered first. */
1320:
1321: output_asm_insn (singlemove_string (operands), operands);
1322:
1323: /* Make any unoffsettable addresses point at high-numbered word. */
1324: if (addreg0)
1325: output_asm_insn ("ldo 4(%0),%0", &addreg0);
1326: if (addreg1)
1327: output_asm_insn ("ldo 4(%0),%0", &addreg1);
1328:
1329: /* Do that word. */
1330: output_asm_insn (singlemove_string (latehalf), latehalf);
1331:
1332: /* Undo the adds we just did. */
1333: if (addreg0)
1334: output_asm_insn ("ldo -4(%0),%0", &addreg0);
1335: if (addreg1)
1336: output_asm_insn ("ldo -4(%0),%0", &addreg1);
1337:
1338: return "";
1339: }
1340:
1341: char *
1342: output_fp_move_double (operands)
1343: rtx *operands;
1344: {
1345: if (FP_REG_P (operands[0]))
1346: {
1347: if (FP_REG_P (operands[1])
1348: || operands[1] == CONST0_RTX (GET_MODE (operands[0])))
1349: output_asm_insn ("fcpy,dbl %r1,%0", operands);
1350: else
1351: output_asm_insn ("fldds%F1 %1,%0", operands);
1352: }
1353: else if (FP_REG_P (operands[1]))
1354: {
1355: output_asm_insn ("fstds%F0 %1,%0", operands);
1356: }
1357: else if (operands[1] == CONST0_RTX (GET_MODE (operands[0])))
1358: {
1359: if (GET_CODE (operands[0]) == REG)
1360: {
1361: rtx xoperands[2];
1362: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
1363: xoperands[0] = operands[0];
1364: output_asm_insn ("copy %%r0,%0\n\tcopy %%r0,%1", xoperands);
1365: }
1366: /* This is a pain. You have to be prepared to deal with an
1367: arbritary address here including pre/post increment/decrement.
1368:
1369: so avoid this in the MD. */
1370: else
1371: abort ();
1372: }
1373: else abort ();
1374: return "";
1375: }
1376:
1377: /* Return a REG that occurs in ADDR with coefficient 1.
1378: ADDR can be effectively incremented by incrementing REG. */
1379:
1380: static rtx
1381: find_addr_reg (addr)
1382: rtx addr;
1383: {
1384: while (GET_CODE (addr) == PLUS)
1385: {
1386: if (GET_CODE (XEXP (addr, 0)) == REG)
1387: addr = XEXP (addr, 0);
1388: else if (GET_CODE (XEXP (addr, 1)) == REG)
1389: addr = XEXP (addr, 1);
1390: else if (CONSTANT_P (XEXP (addr, 0)))
1391: addr = XEXP (addr, 1);
1392: else if (CONSTANT_P (XEXP (addr, 1)))
1393: addr = XEXP (addr, 0);
1394: else
1395: abort ();
1396: }
1397: if (GET_CODE (addr) == REG)
1398: return addr;
1399: abort ();
1400: }
1401:
1402: /* Emit code to perform a block move.
1403:
1404: Restriction: If the length argument is non-constant, alignment
1405: must be 4.
1406:
1407: OPERANDS[0] is the destination pointer as a REG, clobbered.
1408: OPERANDS[1] is the source pointer as a REG, clobbered.
1409: if SIZE_IS_CONSTANT
1410: OPERANDS[2] is a register for temporary storage.
1411: OPERANDS[4] is the size as a CONST_INT
1412: else
1413: OPERANDS[2] is a REG which will contain the size, clobbered.
1414: OPERANDS[3] is a register for temporary storage.
1415: OPERANDS[5] is the alignment safe to use, as a CONST_INT. */
1416:
1417: char *
1418: output_block_move (operands, size_is_constant)
1419: rtx *operands;
1420: int size_is_constant;
1421: {
1422: int align = INTVAL (operands[5]);
1423: unsigned long n_bytes;
1424:
1425: /* We can't move more than four bytes at a time because the PA
1426: has no longer integer move insns. (Could use fp mem ops?) */
1427: if (align > 4)
1428: align = 4;
1429:
1430: if (size_is_constant)
1431: {
1432: unsigned long offset;
1433: rtx temp;
1434:
1435: n_bytes = INTVAL (operands[4]);
1436: if (n_bytes == 0)
1437: return "";
1438:
1439: if (align >= 4)
1440: {
1441: /* Don't unroll too large blocks. */
1442: if (n_bytes > 64)
1443: goto copy_with_loop;
1444:
1445: /* Read and store using two registers, and hide latency
1446: by deferring the stores until three instructions after
1447: the corresponding load. The last load insn will read
1448: the entire word were the last bytes are, possibly past
1449: the end of the source block, but since loads are aligned,
1450: this is harmless. */
1451:
1452: output_asm_insn ("ldws,ma 4(0,%1),%2", operands);
1453:
1454: for (offset = 4; offset < n_bytes; offset += 4)
1455: {
1456: output_asm_insn ("ldws,ma 4(0,%1),%3", operands);
1457: output_asm_insn ("stws,ma %2,4(0,%0)", operands);
1458:
1459: temp = operands[2];
1460: operands[2] = operands[3];
1461: operands[3] = temp;
1462: }
1463: if (n_bytes % 4 == 0)
1464: /* Store the last word. */
1465: output_asm_insn ("stw %2,0(0,%0)", operands);
1466: else
1467: {
1468: /* Store the last, partial word. */
1469: operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4);
1470: output_asm_insn ("stbys,e %2,%4(0,%0)", operands);
1471: }
1472: return "";
1473: }
1474:
1475: if (align >= 2 && n_bytes >= 2)
1476: {
1477: output_asm_insn ("ldhs,ma 2(0,%1),%2", operands);
1478:
1479: for (offset = 2; offset + 2 <= n_bytes; offset += 2)
1480: {
1481: output_asm_insn ("ldhs,ma 2(0,%1),%3", operands);
1482: output_asm_insn ("sths,ma %2,2(0,%0)", operands);
1483:
1484: temp = operands[2];
1485: operands[2] = operands[3];
1486: operands[3] = temp;
1487: }
1488: if (n_bytes % 2 != 0)
1489: output_asm_insn ("ldb 0(0,%1),%3", operands);
1490:
1491: output_asm_insn ("sths,ma %2,2(0,%0)", operands);
1492:
1493: if (n_bytes % 2 != 0)
1494: output_asm_insn ("stb %3,0(0,%0)", operands);
1495:
1496: return "";
1497: }
1498:
1499: output_asm_insn ("ldbs,ma 1(0,%1),%2", operands);
1500:
1501: for (offset = 1; offset + 1 <= n_bytes; offset += 1)
1502: {
1503: output_asm_insn ("ldbs,ma 1(0,%1),%3", operands);
1504: output_asm_insn ("stbs,ma %2,1(0,%0)", operands);
1505:
1506: temp = operands[2];
1507: operands[2] = operands[3];
1508: operands[3] = temp;
1509: }
1510: output_asm_insn ("stb %2,0(0,%0)", operands);
1511:
1512: return "";
1513: }
1514:
1515: if (align != 4)
1516: abort();
1517:
1518: copy_with_loop:
1519:
1520: if (size_is_constant)
1521: {
1522: /* Size is compile-time determined, and also not
1523: very small (such small cases are handled above). */
1524: operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes - 4);
1525: output_asm_insn ("ldo %4(0),%2", operands);
1526: }
1527: else
1528: {
1529: /* Decrement counter by 4, and if it becomes negative, jump past the
1530: word copying loop. */
1531: output_asm_insn ("addib,<,n -4,%2,.+16", operands);
1532: }
1533:
1534: /* Copying loop. Note that the first load is in the annulled delay slot
1535: of addib. Is it OK on PA to have a load in a delay slot, i.e. is a
1536: possible page fault stopped in time? */
1537: output_asm_insn ("ldws,ma 4(0,%1),%3", operands);
1538: output_asm_insn ("addib,>= -4,%2,.-4", operands);
1539: output_asm_insn ("stws,ma %3,4(0,%0)", operands);
1540:
1541: /* The counter is negative, >= -4. The remaining number of bytes are
1542: determined by the two least significant bits. */
1543:
1544: if (size_is_constant)
1545: {
1546: if (n_bytes % 4 != 0)
1547: {
1548: /* Read the entire word of the source block tail. */
1549: output_asm_insn ("ldw 0(0,%1),%3", operands);
1550: operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4);
1551: output_asm_insn ("stbys,e %3,%4(0,%0)", operands);
1552: }
1553: }
1554: else
1555: {
1556: /* Add 4 to counter. If it becomes zero, we're done. */
1557: output_asm_insn ("addib,=,n 4,%2,.+16", operands);
1558:
1559: /* Read the entire word of the source block tail. (Also this
1560: load is in an annulled delay slot.) */
1561: output_asm_insn ("ldw 0(0,%1),%3", operands);
1562:
1563: /* Make %0 point at the first byte after the destination block. */
1564: output_asm_insn ("add %2,%0,%0", operands);
1565: /* Store the leftmost bytes, up to, but not including, the address
1566: in %0. */
1567: output_asm_insn ("stbys,e %3,0(0,%0)", operands);
1568: }
1569: return "";
1570: }
1571:
1572: /* Count the number of insns necessary to handle this block move.
1573:
1574: Basic structure is the same as emit_block_move, except that we
1575: count insns rather than emit them. */
1576:
1577: int
1578: compute_movstrsi_length (insn)
1579: rtx insn;
1580: {
1581: rtx pat = PATTERN (insn);
1582: int size_is_constant;
1583: int align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0));
1584: unsigned long n_bytes;
1585: int insn_count = 0;
1586:
1587: if (GET_CODE (XEXP (XVECEXP (pat, 0, 5), 0)) == CONST_INT)
1588: {
1589: size_is_constant = 1;
1590: n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0));
1591: }
1592: else
1593: {
1594: size_is_constant = 0;
1595: n_bytes = 0;
1596: }
1597:
1598: /* We can't move more than four bytes at a time because the PA
1599: has no longer integer move insns. (Could use fp mem ops?) */
1600: if (align > 4)
1601: align = 4;
1602:
1603: if (size_is_constant)
1604: {
1605: unsigned long offset;
1606:
1607: if (n_bytes == 0)
1608: return 0;
1609:
1610: if (align >= 4)
1611: {
1612: /* Don't unroll too large blocks. */
1613: if (n_bytes > 64)
1614: goto copy_with_loop;
1615:
1616: /* first load */
1617: insn_count = 1;
1618:
1619: /* Count the unrolled insns. */
1620: for (offset = 4; offset < n_bytes; offset += 4)
1621: insn_count += 2;
1622:
1623: /* Count last store or partial store. */
1624: insn_count += 1;
1625: return insn_count * 4;
1626: }
1627:
1628: if (align >= 2 && n_bytes >= 2)
1629: {
1630: /* initial load. */
1631: insn_count = 1;
1632:
1633: /* Unrolled loop. */
1634: for (offset = 2; offset + 2 <= n_bytes; offset += 2)
1635: insn_count += 2;
1636:
1637: /* ??? odd load/store */
1638: if (n_bytes % 2 != 0)
1639: insn_count += 2;
1640:
1641: /* ??? final store from loop. */
1642: insn_count += 1;
1643:
1644: return insn_count * 4;
1645: }
1646:
1647: /* First load. */
1648: insn_count = 1;
1649:
1650: /* The unrolled loop. */
1651: for (offset = 1; offset + 1 <= n_bytes; offset += 1)
1652: insn_count += 2;
1653:
1654: /* Final store. */
1655: insn_count += 1;
1656:
1657: return insn_count * 4;
1658: }
1659:
1660: if (align != 4)
1661: abort();
1662:
1663: copy_with_loop:
1664:
1665: /* setup for constant and non-constant case. */
1666: insn_count = 1;
1667:
1668: /* The copying loop. */
1669: insn_count += 3;
1670:
1671: /* The counter is negative, >= -4. The remaining number of bytes are
1672: determined by the two least significant bits. */
1673:
1674: if (size_is_constant)
1675: {
1676: if (n_bytes % 4 != 0)
1677: insn_count += 2;
1678: }
1679: else
1680: insn_count += 4;
1681: return insn_count * 4;
1682: }
1683:
1684:
1685: char *
1686: output_and (operands)
1687: rtx *operands;
1688: {
1689: if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
1690: {
1691: unsigned mask = INTVAL (operands[2]);
1692: int ls0, ls1, ms0, p, len;
1693:
1694: for (ls0 = 0; ls0 < 32; ls0++)
1695: if ((mask & (1 << ls0)) == 0)
1696: break;
1697:
1698: for (ls1 = ls0; ls1 < 32; ls1++)
1699: if ((mask & (1 << ls1)) != 0)
1700: break;
1701:
1702: for (ms0 = ls1; ms0 < 32; ms0++)
1703: if ((mask & (1 << ms0)) == 0)
1704: break;
1705:
1706: if (ms0 != 32)
1707: abort();
1708:
1709: if (ls1 == 32)
1710: {
1711: len = ls0;
1712:
1713: if (len == 0)
1714: abort ();
1715:
1716: operands[2] = gen_rtx (CONST_INT, VOIDmode, len);
1717: return "extru %1,31,%2,%0";
1718: }
1719: else
1720: {
1721: /* We could use this `depi' for the case above as well, but `depi'
1722: requires one more register file access than an `extru'. */
1723:
1724: p = 31 - ls0;
1725: len = ls1 - ls0;
1726:
1727: operands[2] = gen_rtx (CONST_INT, VOIDmode, p);
1728: operands[3] = gen_rtx (CONST_INT, VOIDmode, len);
1729: return "depi 0,%2,%3,%0";
1730: }
1731: }
1732: else
1733: return "and %1,%2,%0";
1734: }
1735:
1736: char *
1737: output_ior (operands)
1738: rtx *operands;
1739: {
1740: unsigned mask = INTVAL (operands[2]);
1741: int bs0, bs1, p, len;
1742:
1743: if (INTVAL (operands[2]) == 0)
1744: return "copy %1,%0";
1745:
1746: for (bs0 = 0; bs0 < 32; bs0++)
1747: if ((mask & (1 << bs0)) != 0)
1748: break;
1749:
1750: for (bs1 = bs0; bs1 < 32; bs1++)
1751: if ((mask & (1 << bs1)) == 0)
1752: break;
1753:
1754: if (bs1 != 32 && ((unsigned) 1 << bs1) <= mask)
1755: abort();
1756:
1757: p = 31 - bs0;
1758: len = bs1 - bs0;
1759:
1760: operands[2] = gen_rtx (CONST_INT, VOIDmode, p);
1761: operands[3] = gen_rtx (CONST_INT, VOIDmode, len);
1762: return "depi -1,%2,%3,%0";
1763: }
1764:
1765: /* Output an ascii string. */
1766: void
1767: output_ascii (file, p, size)
1768: FILE *file;
1769: unsigned char *p;
1770: int size;
1771: {
1772: int i;
1773: int chars_output;
1774: unsigned char partial_output[16]; /* Max space 4 chars can occupy. */
1775:
1776: /* The HP assembler can only take strings of 256 characters at one
1777: time. This is a limitation on input line length, *not* the
1778: length of the string. Sigh. Even worse, it seems that the
1779: restriction is in number of input characters (see \xnn &
1780: \whatever). So we have to do this very carefully. */
1781:
1782: fprintf (file, "\t.%s \"", STRING_SECTION_NAME);
1783:
1784: chars_output = 0;
1785: for (i = 0; i < size; i += 4)
1786: {
1787: int co = 0;
1788: int io = 0;
1789: for (io = 0, co = 0; io < MIN (4, size - i); io++)
1790: {
1791: register unsigned int c = p[i + io];
1792:
1793: if (c == '\"' || c == '\\')
1794: partial_output[co++] = '\\';
1795:
1796: if (c >= ' ' && c < 0177)
1797: partial_output[co++] = c;
1798:
1799: else if (TARGET_GAS)
1800: {
1801: /* output octal numbers for gas */
1802: partial_output[co++] = '\\';
1803: partial_output[co++] = (c / 64) % 8 - 0 + '0';
1804: partial_output[co++] = (c / 8) % 8 - 0 + '0';
1805: partial_output[co++] = c % 8 - 0 + '0';
1806: }
1807: else
1808: {
1809: unsigned int hexd;
1810: partial_output[co++] = '\\';
1811: partial_output[co++] = 'x';
1812: hexd = c / 16 - 0 + '0';
1813: if (hexd > '9')
1814: hexd -= '9' - 'a' + 1;
1815: partial_output[co++] = hexd;
1816: hexd = c % 16 - 0 + '0';
1817: if (hexd > '9')
1818: hexd -= '9' - 'a' + 1;
1819: partial_output[co++] = hexd;
1820: }
1821: }
1822: if (chars_output + co > 243)
1823: {
1824: fprintf (file, "\"\n\t.%s \"", STRING_SECTION_NAME);
1825: chars_output = 0;
1826: }
1827: fwrite (partial_output, 1, co, file);
1828: chars_output += co;
1829: co = 0;
1830: }
1831: fprintf (file, "\"\n");
1832: }
1833:
1834: /* You may have trouble believing this, but this is the HP-PA stack
1835: layout. Wow.
1836:
1837: Offset Contents
1838:
1839: Variable arguments (optional; any number may be allocated)
1840:
1841: SP-(4*(N+9)) arg word N
1842: : :
1843: SP-56 arg word 5
1844: SP-52 arg word 4
1845:
1846: Fixed arguments (must be allocated; may remain unused)
1847:
1848: SP-48 arg word 3
1849: SP-44 arg word 2
1850: SP-40 arg word 1
1851: SP-36 arg word 0
1852:
1853: Frame Marker
1854:
1855: SP-32 External Data Pointer (DP)
1856: SP-28 External sr4
1857: SP-24 External/stub RP (RP')
1858: SP-20 Current RP
1859: SP-16 Static Link
1860: SP-12 Clean up
1861: SP-8 Calling Stub RP (RP'')
1862: SP-4 Previous SP
1863:
1864: Top of Frame
1865:
1866: SP-0 Stack Pointer (points to next available address)
1867:
1868: */
1869:
1870: /* This function saves registers as follows. Registers marked with ' are
1871: this function's registers (as opposed to the previous function's).
1872: If a frame_pointer isn't needed, r4 is saved as a general register;
1873: the space for the frame pointer is still allocated, though, to keep
1874: things simple.
1875:
1876:
1877: Top of Frame
1878:
1879: SP (FP') Previous FP
1880: SP + 4 Alignment filler (sigh)
1881: SP + 8 Space for locals reserved here.
1882: .
1883: .
1884: .
1885: SP + n All call saved register used.
1886: .
1887: .
1888: .
1889: SP + o All call saved fp registers used.
1890: .
1891: .
1892: .
1893: SP + p (SP') points to next available address.
1894:
1895: */
1896:
1897: /* Emit RTL to store REG at the memory location specified by BASE+DISP.
1898: Handle case where DISP > 8k by using the add_high_const pattern.
1899:
1900: Note in DISP > 8k case, we will leave the high part of the address
1901: in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
1902: static void
1903: store_reg (reg, disp, base)
1904: int reg, disp, base;
1905: {
1906: if (VAL_14_BITS_P (disp))
1907: {
1908: emit_move_insn (gen_rtx (MEM, SImode,
1909: gen_rtx (PLUS, SImode,
1910: gen_rtx (REG, SImode, base),
1911: GEN_INT (disp))),
1912: gen_rtx (REG, SImode, reg));
1913: }
1914: else
1915: {
1916: emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1),
1917: gen_rtx (REG, SImode, base),
1918: GEN_INT (disp)));
1919: emit_move_insn (gen_rtx (MEM, SImode,
1920: gen_rtx (LO_SUM, SImode,
1921: gen_rtx (REG, SImode, 1),
1922: GEN_INT (disp))),
1923: gen_rtx (REG, SImode, reg));
1924: }
1925: }
1926:
1927: /* Emit RTL to load REG from the memory location specified by BASE+DISP.
1928: Handle case where DISP > 8k by using the add_high_const pattern.
1929:
1930: Note in DISP > 8k case, we will leave the high part of the address
1931: in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
1932: static void
1933: load_reg (reg, disp, base)
1934: int reg, disp, base;
1935: {
1936: if (VAL_14_BITS_P (disp))
1937: {
1938: emit_move_insn (gen_rtx (REG, SImode, reg),
1939: gen_rtx (MEM, SImode,
1940: gen_rtx (PLUS, SImode,
1941: gen_rtx (REG, SImode, base),
1942: GEN_INT (disp))));
1943:
1944: }
1945: else
1946: {
1947: emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1),
1948: gen_rtx (REG, SImode, base),
1949: GEN_INT (disp)));
1950: emit_move_insn (gen_rtx (REG, SImode, reg),
1951: gen_rtx (MEM, SImode,
1952: gen_rtx (LO_SUM, SImode,
1953: gen_rtx (REG, SImode, 1),
1954: GEN_INT (disp))));
1955: }
1956: }
1957:
1958: /* Emit RTL to set REG to the value specified by BASE+DISP.
1959: Handle case where DISP > 8k by using the add_high_const pattern.
1960:
1961: Note in DISP > 8k case, we will leave the high part of the address
1962: in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
1963: static void
1964: set_reg_plus_d(reg, base, disp)
1965: int reg, base, disp;
1966: {
1967: if (VAL_14_BITS_P (disp))
1968: {
1969: emit_move_insn (gen_rtx (REG, SImode, reg),
1970: gen_rtx (PLUS, SImode,
1971: gen_rtx (REG, SImode, base),
1972: GEN_INT (disp)));
1973:
1974: }
1975: else
1976: {
1977: emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1),
1978: gen_rtx (REG, SImode, base),
1979: GEN_INT (disp)));
1980: emit_move_insn (gen_rtx (REG, SImode, reg),
1981: gen_rtx (LO_SUM, SImode,
1982: gen_rtx (REG, SImode, 1),
1983: GEN_INT (disp)));
1984: }
1985: }
1986:
1987: /* Global variables set by FUNCTION_PROLOGUE. */
1988: /* Size of frame. Need to know this to emit return insns from
1989: leaf procedures. */
1990: static int actual_fsize;
1991: static int local_fsize, save_fregs;
1992:
1993: int
1994: compute_frame_size (size, fregs_live)
1995: int size;
1996: int *fregs_live;
1997: {
1998: extern int current_function_outgoing_args_size;
1999: int i, fsize;
2000:
2001: /* 8 is space for frame pointer + filler. If any frame is allocated
2002: we need to add this in because of STARTING_FRAME_OFFSET. */
2003: fsize = size + (size || frame_pointer_needed ? 8 : 0);
2004:
2005: /* fp is stored in a special place. */
2006: if (frame_pointer_needed)
2007: {
2008: for (i = 18; i >= 5; i--)
2009: if (regs_ever_live[i])
2010: fsize += 4;
2011:
2012: if (regs_ever_live[3])
2013: fsize += 4;
2014: }
2015: else
2016: {
2017: for (i = 18; i >= 3; i--)
2018: if (regs_ever_live[i])
2019: fsize += 4;
2020: }
2021: fsize = (fsize + 7) & ~7;
2022:
2023: if (!TARGET_SNAKE)
2024: {
2025: for (i = 43; i >= 40; i--)
2026: if (regs_ever_live[i])
2027: {
2028: fsize += 8;
2029: if (fregs_live)
2030: *fregs_live = 1;
2031: }
2032: }
2033: else
2034: {
2035: for (i = 78; i >= 60; i -= 2)
2036: if (regs_ever_live[i] || regs_ever_live[i + 1])
2037: {
2038: fsize += 8;
2039: if (fregs_live)
2040: *fregs_live = 1;
2041: }
2042: }
2043: fsize += current_function_outgoing_args_size;
2044: if (! leaf_function_p () || fsize)
2045: fsize += 32;
2046: return (fsize + 63) & ~63;
2047: }
2048:
2049: rtx hp_profile_label_rtx;
2050: static char hp_profile_label_name[8];
2051: void
2052: output_function_prologue (file, size)
2053: FILE *file;
2054: int size;
2055: {
2056:
2057: /* hppa_expand_prologue does the dirty work now. We just need
2058: to output the assembler directives which denote the start
2059: of a function. */
2060: fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=%d", actual_fsize);
2061: if (regs_ever_live[2] || profile_flag)
2062: fprintf (file, ",CALLS,SAVE_RP");
2063: else
2064: fprintf (file, ",NO_CALLS");
2065:
2066: if (frame_pointer_needed)
2067: fprintf (file, ",SAVE_SP");
2068:
2069: /* Pass on information about the number of callee register saves
2070: performed in the prologue.
2071:
2072: The compiler is supposed to pass the highest register number
2073: saved, the assembler then has to adjust that number before
2074: entering it into the unwind descriptor (to account for any
2075: caller saved registers with lower register numbers than the
2076: first callee saved register). */
2077: if (gr_saved)
2078: fprintf (file, ",ENTRY_GR=%d", gr_saved + 2);
2079:
2080: if (fr_saved)
2081: fprintf (file, ",ENTRY_FR=%d", fr_saved + 11);
2082:
2083: fprintf (file, "\n\t.ENTRY\n");
2084:
2085: /* Horrid hack. emit_function_prologue will modify this RTL in
2086: place to get the expected results. */
2087: if (profile_flag)
2088: sprintf(hp_profile_label_name, "LP$%04d", hp_profile_labelno);
2089: }
2090:
2091: void
2092: hppa_expand_prologue()
2093: {
2094:
2095: extern char call_used_regs[];
2096: int size = get_frame_size ();
2097: int merge_sp_adjust_with_store = 0;
2098: int i, offset;
2099: rtx tmpreg, size_rtx;
2100:
2101:
2102: gr_saved = 0;
2103: fr_saved = 0;
2104: save_fregs = 0;
2105: local_fsize = size + (size || frame_pointer_needed ? 8 : 0);
2106: actual_fsize = compute_frame_size (size, &save_fregs);
2107:
2108: /* Compute a few things we will use often. */
2109: tmpreg = gen_rtx (REG, SImode, 1);
2110: size_rtx = GEN_INT (actual_fsize);
2111:
2112: /* Save RP first. The calling conventions manual states RP will
2113: always be stored into the caller's frame at sp-20. */
2114: if (regs_ever_live[2] || profile_flag)
2115: store_reg (2, -20, STACK_POINTER_REGNUM);
2116:
2117: /* Allocate the local frame and set up the frame pointer if needed. */
2118: if (actual_fsize)
2119: if (frame_pointer_needed)
2120: {
2121: /* Copy the old frame pointer temporarily into %r1. Set up the
2122: new stack pointer, then store away the saved old frame pointer
2123: into the stack at sp+actual_fsize and at the same time update
2124: the stack pointer by actual_fsize bytes. Two versions, first
2125: handles small (<8k) frames. The second handles large (>8k)
2126: frames. */
2127: emit_move_insn (tmpreg, frame_pointer_rtx);
2128: emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
2129: if (VAL_14_BITS_P (actual_fsize))
2130: emit_insn (gen_post_stwm (stack_pointer_rtx,
2131: stack_pointer_rtx,
2132: size_rtx, tmpreg));
2133: else
2134: {
2135: store_reg (1, 0, FRAME_POINTER_REGNUM);
2136: set_reg_plus_d (STACK_POINTER_REGNUM,
2137: STACK_POINTER_REGNUM,
2138: actual_fsize);
2139: }
2140: }
2141: /* no frame pointer needed. */
2142: else
2143: {
2144: /* In some cases we can perform the first callee register save
2145: and allocating the stack frame at the same time. If so, just
2146: make a note of it and defer allocating the frame until saving
2147: the callee registers. */
2148: if (VAL_14_BITS_P (-actual_fsize)
2149: && local_fsize == 0
2150: && ! profile_flag
2151: && ! flag_pic)
2152: merge_sp_adjust_with_store = 1;
2153: /* Can not optimize. Adjust the stack frame by actual_fsize bytes. */
2154: else if (actual_fsize != 0)
2155: set_reg_plus_d (STACK_POINTER_REGNUM,
2156: STACK_POINTER_REGNUM,
2157: actual_fsize);
2158: }
2159: /* The hppa calling conventions say that that %r19, the pic offset
2160: register, is saved at sp - 32 (in this function's frame) when
2161: generating PIC code. */
2162: if (flag_pic)
2163: {
2164: #ifndef NeXT_ASM
2165: store_reg (PIC_OFFSET_TABLE_REGNUM, -32, STACK_POINTER_REGNUM);
2166: #endif
2167: }
2168:
2169:
2170: /* Profiling code.
2171:
2172: Instead of taking one argument, the counter label, as most normal
2173: mcounts do, _mcount appears to behave differently on the HPPA. It
2174: takes the return address of the caller, the address of this routine,
2175: and the address of the label. Also, it isn't magic, so
2176: argument registre hsave to be preserved. */
2177: if (profile_flag)
2178: {
2179: int pc_offset, i, arg_offset, basereg, offsetadj;
2180:
2181: pc_offset = 4 + (frame_pointer_needed
2182: ? (VAL_14_BITS_P (actual_fsize) ? 12 : 20)
2183: : (VAL_14_BITS_P (actual_fsize) ? 4 : 8));
2184:
2185: /* When the function has a frame pointer, use it as the base
2186: register for saving/restore registers. Else use the stack
2187: pointer. Adjust the offset according to the frame size if
2188: this function does not have a frame pointer. */
2189:
2190: basereg = frame_pointer_needed ? FRAME_POINTER_REGNUM
2191: : STACK_POINTER_REGNUM;
2192: offsetadj = frame_pointer_needed ? 0 : actual_fsize;
2193:
2194: /* Horrid hack. emit_function_prologue will modify this RTL in
2195: place to get the expected results. sprintf here is just to
2196: put something in the name. */
2197: sprintf(hp_profile_label_name, "LP%d", profile_label_no);
2198: hp_profile_label_rtx = gen_rtx (SYMBOL_REF, SImode,
2199: hp_profile_label_name);
2200: if (current_function_returns_struct)
2201: store_reg (STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg);
2202:
2203: for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
2204: if (regs_ever_live [i])
2205: {
2206: store_reg (i, arg_offset, basereg);
2207: /* Deal with arg_offset not fitting in 14 bits. */
2208: pc_offset += VAL_14_BITS_P (arg_offset) ? 4 : 8;
2209: }
2210:
2211: emit_move_insn (gen_rtx (REG, SImode, 26), gen_rtx (REG, SImode, 2));
2212: #ifndef NeXT_ASM
2213: emit_move_insn (tmpreg, gen_rtx (HIGH, SImode, hp_profile_label_rtx));
2214: emit_move_insn (gen_rtx (REG, SImode, 24),
2215: gen_rtx (LO_SUM, SImode, tmpreg, hp_profile_label_rtx));
2216: #endif
2217: /* %r25 is set from within the output pattern. */
2218: emit_insn (gen_call_profiler (GEN_INT (- pc_offset - 20)));
2219:
2220: /* Restore argument registers. */
2221: for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
2222: if (regs_ever_live [i])
2223: load_reg (i, arg_offset, basereg);
2224:
2225: if (current_function_returns_struct)
2226: load_reg (STRUCT_VALUE_REGNUM, -12 - offsetadj, basereg);
2227:
2228: }
2229:
2230: /* Normal register save.
2231:
2232: Do not save the frame pointer in the frame_pointer_needed case. It
2233: was done earlier. */
2234: if (frame_pointer_needed)
2235: {
2236: for (i = 18, offset = local_fsize; i >= 3; i--)
2237: if (regs_ever_live[i] && ! call_used_regs[i]
2238: && i != FRAME_POINTER_REGNUM)
2239: {
2240: store_reg (i, offset, FRAME_POINTER_REGNUM);
2241: offset += 4;
2242: gr_saved++;
2243: }
2244: /* Account for %r4 which is saved in a special place. */
2245: gr_saved++;
2246: }
2247: /* No frame pointer needed. */
2248: else
2249: {
2250: for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
2251: if (regs_ever_live[i] && ! call_used_regs[i])
2252: {
2253: /* If merge_sp_adjust_with_store is nonzero, then we can
2254: optimize the first GR save. */
2255: if (merge_sp_adjust_with_store)
2256: {
2257: merge_sp_adjust_with_store = 0;
2258: emit_insn (gen_post_stwm (stack_pointer_rtx,
2259: stack_pointer_rtx,
2260: GEN_INT (-offset),
2261: gen_rtx (REG, SImode, i)));
2262: }
2263: else
2264: store_reg (i, offset, STACK_POINTER_REGNUM);
2265: offset += 4;
2266: gr_saved++;
2267: }
2268:
2269: /* If we wanted to merge the SP adjustment with a GR save, but we never
2270: did any GR saves, then just emit the adjustment here. */
2271: if (merge_sp_adjust_with_store)
2272: set_reg_plus_d (STACK_POINTER_REGNUM,
2273: STACK_POINTER_REGNUM,
2274: actual_fsize);
2275: }
2276:
2277:
2278: /* Align pointer properly (doubleword boundary). */
2279: offset = (offset + 7) & ~7;
2280:
2281: /* Floating point register store. */
2282: if (save_fregs)
2283: {
2284:
2285: /* First get the frame or stack pointer to the start of the FP register
2286: save area. */
2287: if (frame_pointer_needed)
2288: set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
2289: else
2290: set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
2291:
2292: /* Now actually save the FP registers. */
2293: if (! TARGET_SNAKE)
2294: {
2295: for (i = 43; i >= 40; i--)
2296: if (regs_ever_live[i])
2297: {
2298: emit_move_insn (gen_rtx (MEM, DFmode,
2299: gen_rtx (POST_INC, DFmode, tmpreg)),
2300: gen_rtx (REG, DFmode, i));
2301: fr_saved++;
2302: }
2303: }
2304: else
2305: {
2306: for (i = 78; i >= 60; i -= 2)
2307: if (regs_ever_live[i] || regs_ever_live[i + 1])
2308: {
2309: emit_move_insn (gen_rtx (MEM, DFmode,
2310: gen_rtx (POST_INC, DFmode, tmpreg)),
2311: gen_rtx (REG, DFmode, i));
2312: fr_saved++;
2313: }
2314: }
2315: }
2316: }
2317:
2318:
2319: void
2320: output_function_epilogue (file, size)
2321: FILE *file;
2322: int size;
2323: {
2324:
2325: rtx insn = get_last_insn ();
2326:
2327: /* hppa_expand_epilogue does the dirty work now. We just need
2328: to output the assembler directives which denote the end
2329: of a function.
2330:
2331: To make debuggers happy, emit a nop if the epilogue was completely
2332: eliminated due to a volatile call as the last insn in the
2333: current function. That way the return address (in %r2) will
2334: always point to a valid instruction in the current function. */
2335:
2336: /* Get the last real insn. */
2337: if (GET_CODE (insn) == NOTE)
2338: insn = prev_real_insn (insn);
2339:
2340: /* If it is a sequence, then look inside. */
2341: if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
2342: insn = XVECEXP (PATTERN (insn), 0, 0);
2343:
2344: /* If insn is a CALL_INSN, then it must be a call to a volatile
2345: function (otherwise there would be epilogue insns). */
2346: if (insn && GET_CODE (insn) == CALL_INSN)
2347: fprintf (file, "\tnop\n");
2348:
2349: fprintf (file, "\t.EXIT\n\t.PROCEND\n");
2350: }
2351:
2352: void
2353: hppa_expand_epilogue ()
2354: {
2355: rtx tmpreg;
2356: int offset,i;
2357: int merge_sp_adjust_with_load = 0;
2358:
2359: /* We will use this often. */
2360: tmpreg = gen_rtx (REG, SImode, 1);
2361:
2362: /* Try to restore RP early to avoid load/use interlocks when
2363: RP gets used in the return (bv) instruction. This appears to still
2364: be necessary even when we schedule the prologue and epilogue. */
2365: if (frame_pointer_needed
2366: && (regs_ever_live [2] || profile_flag))
2367: load_reg (2, -20, FRAME_POINTER_REGNUM);
2368:
2369: /* No frame pointer, and stack is smaller than 8k. */
2370: else if (! frame_pointer_needed
2371: && VAL_14_BITS_P (actual_fsize + 20)
2372: && (regs_ever_live[2] || profile_flag))
2373: load_reg (2, - (actual_fsize + 20), STACK_POINTER_REGNUM);
2374:
2375: /* General register restores. */
2376: if (frame_pointer_needed)
2377: {
2378: for (i = 18, offset = local_fsize; i >= 3; i--)
2379: if (regs_ever_live[i] && ! call_used_regs[i]
2380: && i != FRAME_POINTER_REGNUM)
2381: {
2382: load_reg (i, offset, FRAME_POINTER_REGNUM);
2383: offset += 4;
2384: }
2385: }
2386: else
2387: {
2388: for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
2389: if (regs_ever_live[i] && ! call_used_regs[i])
2390: {
2391: /* Only for the first load.
2392: merge_sp_adjust_with_load holds the register load
2393: with which we will merge the sp adjustment. */
2394: if (VAL_14_BITS_P (actual_fsize + 20)
2395: && local_fsize == 0
2396: && ! merge_sp_adjust_with_load)
2397: merge_sp_adjust_with_load = i;
2398: else
2399: load_reg (i, offset, STACK_POINTER_REGNUM);
2400: offset += 4;
2401: }
2402: }
2403:
2404: /* Align pointer properly (doubleword boundary). */
2405: offset = (offset + 7) & ~7;
2406:
2407: /* FP register restores. */
2408: if (save_fregs)
2409: {
2410: /* Adjust the register to index off of. */
2411: if (frame_pointer_needed)
2412: set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
2413: else
2414: set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
2415:
2416: /* Actually do the restores now. */
2417: if (! TARGET_SNAKE)
2418: {
2419: for (i = 43; i >= 40; i--)
2420: if (regs_ever_live[i])
2421: emit_move_insn (gen_rtx (REG, DFmode, i),
2422: gen_rtx (MEM, DFmode,
2423: gen_rtx (POST_INC, DFmode, tmpreg)));
2424:
2425: }
2426: else
2427: {
2428: for (i = 78; i >= 60; i -= 2)
2429: if (regs_ever_live[i] || regs_ever_live[i + 1])
2430: emit_move_insn (gen_rtx (REG, DFmode, i),
2431: gen_rtx (MEM, DFmode,
2432: gen_rtx (POST_INC, DFmode, tmpreg)));
2433: }
2434: }
2435:
2436: /* No frame pointer, but we have a stack greater than 8k. We restore
2437: %r2 very late in this case. (All other cases are restored as early
2438: as possible.) */
2439: if (! frame_pointer_needed
2440: && ! VAL_14_BITS_P (actual_fsize + 20)
2441: && (regs_ever_live[2] || profile_flag))
2442: {
2443: set_reg_plus_d (STACK_POINTER_REGNUM,
2444: STACK_POINTER_REGNUM,
2445: - actual_fsize);
2446: #ifdef NeXT_ASM
2447: /* The calculation previously used is incorrect with the NeXT
2448: * assembler. We substitute a load_reg from the stack, which
2449: * unfortunately will prevent an instruction from being moved into
2450: * the delay slot of the return.
2451: * We could use the strategy of doing the load_reg from r1 to get rid
2452: * of the extra instruction, but the calculation would be significantly
2453: * more difficult (and subject to change).
2454: */
2455: load_reg (2, -20, STACK_POINTER_REGNUM);
2456: #else
2457: /* Uses value left over in %r1 by set_reg_plus_d. */
2458: load_reg (2, - (actual_fsize + 20 + ((- actual_fsize) & ~0x7ff)), 1);
2459: #endif
2460: }
2461:
2462: /* Reset stack pointer (and possibly frame pointer). The stack */
2463: /* pointer is initially set to fp + 64 to avoid a race condition.
2464: ??? What race condition?!? */
2465: else if (frame_pointer_needed)
2466: {
2467: /* Emit a blockage insn here to keep these insns from being moved
2468: to the beginning of the prologue or into the main instruction
2469: stream, doing so avoids some very obscure problems. */
2470: emit_insn (gen_blockage ());
2471: set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64);
2472: emit_insn (gen_pre_ldwm (stack_pointer_rtx, stack_pointer_rtx,
2473: GEN_INT (-64), frame_pointer_rtx));
2474: }
2475: /* If we were deferring a callee register restore, do it now. */
2476: else if (! frame_pointer_needed && merge_sp_adjust_with_load)
2477: emit_insn (gen_pre_ldwm (stack_pointer_rtx,
2478: stack_pointer_rtx,
2479: GEN_INT (- actual_fsize),
2480: gen_rtx (REG, SImode,
2481: merge_sp_adjust_with_load)));
2482: else if (actual_fsize != 0)
2483: set_reg_plus_d (STACK_POINTER_REGNUM,
2484: STACK_POINTER_REGNUM,
2485: - actual_fsize);
2486: }
2487:
2488: /* This is only valid once reload has completed because it depends on
2489: knowing exactly how much (if any) frame there is and...
2490:
2491: It's only valid if there is no frame marker to de-allocate and...
2492:
2493: It's only valid if %r2 hasn't been saved into the caller's frame
2494: (we're not profiling and %r2 isn't live anywhere). */
2495: int
2496: hppa_can_use_return_insn_p ()
2497: {
2498: return (reload_completed
2499: && (compute_frame_size (get_frame_size (), 0) ? 0 : 1)
2500: && ! profile_flag
2501: && ! regs_ever_live[2]
2502: && ! frame_pointer_needed);
2503: }
2504:
2505: void
2506: emit_bcond_fp (code, operand0)
2507: enum rtx_code code;
2508: rtx operand0;
2509: {
2510: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
2511: gen_rtx (IF_THEN_ELSE, VOIDmode,
2512: gen_rtx (code, VOIDmode,
2513: gen_rtx (REG, CCFPmode, 0),
2514: const0_rtx),
2515: gen_rtx (LABEL_REF, VOIDmode, operand0),
2516: pc_rtx)));
2517:
2518: }
2519:
2520: rtx
2521: gen_cmp_fp (code, operand0, operand1)
2522: enum rtx_code code;
2523: rtx operand0, operand1;
2524: {
2525: return gen_rtx (SET, VOIDmode, gen_rtx (REG, CCFPmode, 0),
2526: gen_rtx (code, CCFPmode, operand0, operand1));
2527: }
2528:
2529: /* Adjust the cost of a scheduling dependency. Return the new cost of
2530: a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
2531:
2532: int
2533: pa_adjust_cost (insn, link, dep_insn, cost)
2534: rtx insn;
2535: rtx link;
2536: rtx dep_insn;
2537: int cost;
2538: {
2539: if (! recog_memoized (insn))
2540: return 0;
2541:
2542: if (REG_NOTE_KIND (link) == 0)
2543: {
2544: /* Data dependency; DEP_INSN writes a register that INSN reads some
2545: cycles later. */
2546:
2547: if (get_attr_type (insn) == TYPE_FPSTORE)
2548: {
2549: rtx pat = PATTERN (insn);
2550: rtx dep_pat = PATTERN (dep_insn);
2551: if (GET_CODE (pat) == PARALLEL)
2552: {
2553: /* This happens for the fstXs,mb patterns. */
2554: pat = XVECEXP (pat, 0, 0);
2555: }
2556: if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
2557: /* If this happens, we have to extend this to schedule
2558: optimally. Return 0 for now. */
2559: return 0;
2560:
2561: if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
2562: {
2563: if (! recog_memoized (dep_insn))
2564: return 0;
2565: /* DEP_INSN is writing its result to the register
2566: being stored in the fpstore INSN. */
2567: switch (get_attr_type (dep_insn))
2568: {
2569: case TYPE_FPLOAD:
2570: /* This cost 3 cycles, not 2 as the md says. */
2571: return cost + 1;
2572:
2573: case TYPE_FPALU:
2574: case TYPE_FPMUL:
2575: case TYPE_FPDIVSGL:
2576: case TYPE_FPDIVDBL:
2577: case TYPE_FPSQRTSGL:
2578: case TYPE_FPSQRTDBL:
2579: /* In these important cases, we save one cycle compared to
2580: when flop instruction feed each other. */
2581: return cost - 1;
2582:
2583: default:
2584: return cost;
2585: }
2586: }
2587: }
2588:
2589: /* For other data dependencies, the default cost specified in the
2590: md is correct. */
2591: return cost;
2592: }
2593: else if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
2594: {
2595: /* Anti dependency; DEP_INSN reads a register that INSN writes some
2596: cycles later. */
2597:
2598: if (get_attr_type (insn) == TYPE_FPLOAD)
2599: {
2600: rtx pat = PATTERN (insn);
2601: rtx dep_pat = PATTERN (dep_insn);
2602: if (GET_CODE (pat) == PARALLEL)
2603: {
2604: /* This happens for the fldXs,mb patterns. */
2605: pat = XVECEXP (pat, 0, 0);
2606: }
2607: if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
2608: /* If this happens, we have to extend this to schedule
2609: optimally. Return 0 for now. */
2610: return 0;
2611:
2612: if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
2613: {
2614: if (! recog_memoized (dep_insn))
2615: return 0;
2616: switch (get_attr_type (dep_insn))
2617: {
2618: case TYPE_FPALU:
2619: case TYPE_FPMUL:
2620: case TYPE_FPDIVSGL:
2621: case TYPE_FPDIVDBL:
2622: case TYPE_FPSQRTSGL:
2623: case TYPE_FPSQRTDBL:
2624: /* A fpload can't be issued until one cycle before a
2625: preceeding arithmetic operation has finished, if
2626: the target of the fpload is any of the sources
2627: (or destination) of the arithmetic operation. */
2628: return cost - 1;
2629:
2630: default:
2631: return 0;
2632: }
2633: }
2634: }
2635:
2636: /* For other anti dependencies, the cost is 0. */
2637: return 0;
2638: }
2639:
2640: /* For output dependencies, the cost is often one too high. */
2641: return cost - 1;
2642: }
2643:
2644: /* Return any length adjustment needed by INSN which already has its length
2645: computed as LENGTH. Return zero if no adjustment is necessary.
2646:
2647: For the PA: function calls, millicode calls, and backwards short
2648: conditional branches with unfilled delay slots need an adjustment by +1
2649: (to account for the NOP which will be inserted into the instruction stream).
2650:
2651: Also compute the length of an inline block move here as it is too
2652: complicated to express as a length attribute in pa.md. */
2653: int
2654: pa_adjust_insn_length (insn, length)
2655: rtx insn;
2656: int length;
2657: {
2658: rtx pat = PATTERN (insn);
2659:
2660: /* Call insns which are *not* indirect and have unfilled delay slots. */
2661: if (GET_CODE (insn) == CALL_INSN)
2662: {
2663:
2664: if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL
2665: && GET_CODE (XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0)) == SYMBOL_REF)
2666: return 4;
2667: else if (GET_CODE (XVECEXP (pat, 0, 0)) == SET
2668: && GET_CODE (XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0))
2669: == SYMBOL_REF)
2670: return 4;
2671: else
2672: return 0;
2673: }
2674: /* Millicode insn with an unfilled delay slot. */
2675: else if (GET_CODE (insn) == INSN
2676: && GET_CODE (pat) != SEQUENCE
2677: && GET_CODE (pat) != USE
2678: && GET_CODE (pat) != CLOBBER
2679: && get_attr_type (insn) == TYPE_MILLI)
2680: return 4;
2681: /* Block move pattern. */
2682: else if (GET_CODE (insn) == INSN
2683: && GET_CODE (pat) == PARALLEL
2684: && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM
2685: && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 1)) == MEM
2686: && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode
2687: && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 1)) == BLKmode)
2688: return compute_movstrsi_length (insn) - 4;
2689: /* Conditional branch with an unfilled delay slot. */
2690: else if (GET_CODE (insn) == JUMP_INSN && ! simplejump_p (insn))
2691: {
2692: /* Adjust a short backwards conditional with an unfilled delay slot. */
2693: if (GET_CODE (pat) == SET
2694: && length == 4
2695: && ! forward_branch_p (insn))
2696: return 4;
2697: /* Adjust dbra insn with short backwards conditional branch with
2698: unfilled delay slot -- only for case where counter is in a
2699: general register register. */
2700: else if (GET_CODE (pat) == PARALLEL
2701: && GET_CODE (XVECEXP (pat, 0, 1)) == SET
2702: && GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == REG
2703: && ! FP_REG_P (XEXP (XVECEXP (pat, 0, 1), 0))
2704: && length == 4
2705: && ! forward_branch_p (insn))
2706: return 4;
2707: else
2708: return 0;
2709: }
2710: else
2711: return 0;
2712: }
2713:
2714: /* Print operand X (an rtx) in assembler syntax to file FILE.
2715: CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
2716: For `%' followed by punctuation, CODE is the punctuation and X is null. */
2717:
2718: void
2719: print_operand (file, x, code)
2720: FILE *file;
2721: rtx x;
2722: int code;
2723: {
2724: switch (code)
2725: {
2726: case '\'':
2727: fputc (PA_QUOTE, file);
2728: return;
2729: break;
2730:
2731: case '#':
2732: /* Output a 'nop' if there's nothing for the delay slot. */
2733: if (dbr_sequence_length () == 0)
2734: fputs ("\n\tnop", file);
2735: return;
2736: case '*':
2737: /* Output an nullification completer if there's nothing for the */
2738: /* delay slot or nullification is requested. */
2739: if (dbr_sequence_length () == 0 ||
2740: (final_sequence &&
2741: INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))))
2742: fputs (",n", file);
2743: return;
2744: case 'R':
2745: /* Print out the second register name of a register pair.
2746: I.e., R (6) => 7. */
2747: fputs (reg_names[REGNO (x)+1], file);
2748: return;
2749: case 'r':
2750: /* A register or zero. */
2751: if (x == const0_rtx
2752: || (x == CONST0_RTX (DFmode))
2753: || (x == CONST0_RTX (SFmode)))
2754: {
2755: fputs ("0", file);
2756: return;
2757: }
2758: else
2759: break;
2760: case 'C': /* Plain (C)ondition */
2761: case 'X':
2762: switch (GET_CODE (x))
2763: {
2764: case EQ:
2765: fprintf (file, "="); break;
2766: case NE:
2767: fprintf (file, "<>"); break;
2768: case GT:
2769: fprintf (file, ">"); break;
2770: case GE:
2771: fprintf (file, ">="); break;
2772: case GEU:
2773: fprintf (file, ">>="); break;
2774: case GTU:
2775: fprintf (file, ">>"); break;
2776: case LT:
2777: fprintf (file, "<"); break;
2778: case LE:
2779: fprintf (file, "<="); break;
2780: case LEU:
2781: fprintf (file, "<<="); break;
2782: case LTU:
2783: fprintf (file, "<<"); break;
2784: default:
2785: printf ("Can't grok '%c' operator:\n", code);
2786: debug_rtx (x);
2787: abort ();
2788: }
2789: return;
2790: case 'N': /* Condition, (N)egated */
2791: switch (GET_CODE (x))
2792: {
2793: case EQ:
2794: fprintf (file, "<>"); break;
2795: case NE:
2796: fprintf (file, "="); break;
2797: case GT:
2798: fprintf (file, "<="); break;
2799: case GE:
2800: fprintf (file, "<"); break;
2801: case GEU:
2802: fprintf (file, "<<"); break;
2803: case GTU:
2804: fprintf (file, "<<="); break;
2805: case LT:
2806: fprintf (file, ">="); break;
2807: case LE:
2808: fprintf (file, ">"); break;
2809: case LEU:
2810: fprintf (file, ">>"); break;
2811: case LTU:
2812: fprintf (file, ">>="); break;
2813: default:
2814: printf ("Can't grok '%c' operator:\n", code);
2815: debug_rtx (x);
2816: abort ();
2817: }
2818: return;
2819: /* For floating point comparisons. Need special conditions to deal
2820: with NaNs properly. */
2821: case 'Y':
2822: switch (GET_CODE (x))
2823: {
2824: case EQ:
2825: fprintf (file, "!="); break;
2826: case NE:
2827: fprintf (file, "="); break;
2828: case GT:
2829: fprintf (file, "!>"); break;
2830: case GE:
2831: fprintf (file, "!>="); break;
2832: case LT:
2833: fprintf (file, "!<"); break;
2834: case LE:
2835: fprintf (file, "!<="); break;
2836: default:
2837: printf ("Can't grok '%c' operator:\n", code);
2838: debug_rtx (x);
2839: abort ();
2840: }
2841: return;
2842: case 'S': /* Condition, operands are (S)wapped. */
2843: switch (GET_CODE (x))
2844: {
2845: case EQ:
2846: fprintf (file, "="); break;
2847: case NE:
2848: fprintf (file, "<>"); break;
2849: case GT:
2850: fprintf (file, "<"); break;
2851: case GE:
2852: fprintf (file, "<="); break;
2853: case GEU:
2854: fprintf (file, "<<="); break;
2855: case GTU:
2856: fprintf (file, "<<"); break;
2857: case LT:
2858: fprintf (file, ">"); break;
2859: case LE:
2860: fprintf (file, ">="); break;
2861: case LEU:
2862: fprintf (file, ">>="); break;
2863: case LTU:
2864: fprintf (file, ">>"); break;
2865: default:
2866: printf ("Can't grok '%c' operator:\n", code);
2867: debug_rtx (x);
2868: abort ();
2869: }
2870: return;
2871: case 'B': /* Condition, (B)oth swapped and negate. */
2872: switch (GET_CODE (x))
2873: {
2874: case EQ:
2875: fprintf (file, "<>"); break;
2876: case NE:
2877: fprintf (file, "="); break;
2878: case GT:
2879: fprintf (file, ">="); break;
2880: case GE:
2881: fprintf (file, ">"); break;
2882: case GEU:
2883: fprintf (file, ">>"); break;
2884: case GTU:
2885: fprintf (file, ">>="); break;
2886: case LT:
2887: fprintf (file, "<="); break;
2888: case LE:
2889: fprintf (file, "<"); break;
2890: case LEU:
2891: fprintf (file, "<<"); break;
2892: case LTU:
2893: fprintf (file, "<<="); break;
2894: default:
2895: printf ("Can't grok '%c' operator:\n", code);
2896: debug_rtx (x);
2897: abort ();
2898: }
2899: return;
2900: case 'k':
2901: if (GET_CODE (x) == CONST_INT)
2902: {
2903: fprintf (file, "%d", ~INTVAL (x));
2904: return;
2905: }
2906: abort();
2907: case 'L':
2908: if (GET_CODE (x) == CONST_INT)
2909: {
2910: fprintf (file, "%d", 32 - (INTVAL (x) & 31));
2911: return;
2912: }
2913: abort();
2914: case 'O':
2915: if (GET_CODE (x) == CONST_INT && exact_log2 (INTVAL (x)) >= 0)
2916: {
2917: fprintf (file, "%d", exact_log2 (INTVAL (x)));
2918: return;
2919: }
2920: abort();
2921: case 'P':
2922: if (GET_CODE (x) == CONST_INT)
2923: {
2924: fprintf (file, "%d", 31 - (INTVAL (x) & 31));
2925: return;
2926: }
2927: abort();
2928: case 'I':
2929: if (GET_CODE (x) == CONST_INT)
2930: fputs ("i", file);
2931: return;
2932: case 'M':
2933: switch (GET_CODE (XEXP (x, 0)))
2934: {
2935: case PRE_DEC:
2936: case PRE_INC:
2937: fprintf (file, "s,mb");
2938: break;
2939: case POST_DEC:
2940: case POST_INC:
2941: fprintf (file, "s,ma");
2942: break;
2943: default:
2944: break;
2945: }
2946: return;
2947: case 'F':
2948: switch (GET_CODE (XEXP (x, 0)))
2949: {
2950: case PRE_DEC:
2951: case PRE_INC:
2952: fprintf (file, ",mb");
2953: break;
2954: case POST_DEC:
2955: case POST_INC:
2956: fprintf (file, ",ma");
2957: break;
2958: default:
2959: break;
2960: }
2961: return;
2962: case 'G':
2963: output_global_address (file, x);
2964: return;
2965: case 0: /* Don't do anything special */
2966: break;
2967: case 'Z':
2968: {
2969: unsigned op[3];
2970: compute_zdepi_operands (INTVAL (x), op);
2971: fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
2972: return;
2973: }
2974: default:
2975: abort ();
2976: }
2977: if (GET_CODE (x) == REG)
2978: fprintf (file, "%s", reg_names [REGNO (x)]);
2979: else if (GET_CODE (x) == MEM)
2980: {
2981: int size = GET_MODE_SIZE (GET_MODE (x));
2982: rtx base = XEXP (XEXP (x, 0), 0);
2983: switch (GET_CODE (XEXP (x, 0)))
2984: {
2985: case PRE_DEC:
2986: case POST_DEC:
2987: fprintf (file, "-%d(0,%s)", size, reg_names [REGNO (base)]);
2988: break;
2989: case PRE_INC:
2990: case POST_INC:
2991: fprintf (file, "%d(0,%s)", size, reg_names [REGNO (base)]);
2992: break;
2993: default:
2994: output_address (XEXP (x, 0));
2995: break;
2996: }
2997: }
2998: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
2999: {
3000: union { double d; int i[2]; } u;
3001: union { float f; int i; } u1;
3002: u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
3003: u1.f = u.d;
3004: if (code == 'f')
3005: fprintf (file, "0r%.9g", u1.f);
3006: else
3007: fprintf (file, "0x%x", u1.i);
3008: }
3009: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
3010: {
3011: union { double d; int i[2]; } u;
3012: u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
3013: fprintf (file, "0r%.20g", u.d);
3014: }
3015: else
3016: output_addr_const (file, x);
3017: }
3018:
3019: /* output a SYMBOL_REF or a CONST expression involving a SYMBOL_REF. */
3020:
3021: void
3022: output_global_address (file, x)
3023: FILE *file;
3024: rtx x;
3025: {
3026:
3027: /* Imagine (high (const (plus ...))). */
3028: if (GET_CODE (x) == HIGH)
3029: x = XEXP (x, 0);
3030:
3031: if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x))
3032: assemble_name (file, XSTR (x, 0));
3033: else if (GET_CODE (x) == SYMBOL_REF)
3034: {
3035: assemble_name (file, XSTR (x, 0));
3036: #ifndef NeXT_ASM
3037: fprintf (file, "-$global$");
3038: #endif
3039: }
3040: else if (GET_CODE (x) == CONST)
3041: {
3042: char *sep = "";
3043: int offset = 0; /* assembler wants -$global$ at end */
3044: rtx base;
3045:
3046: if (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
3047: {
3048: base = XEXP (XEXP (x, 0), 0);
3049: output_addr_const (file, base);
3050: }
3051: else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == CONST_INT)
3052: offset = INTVAL (XEXP (XEXP (x, 0), 0));
3053: else abort ();
3054:
3055: #ifdef NeXT_ASM
3056: if (GET_CODE (XEXP (x, 0)) == MINUS)
3057: fprintf (file, "-");
3058: #endif
3059:
3060: if (GET_CODE (XEXP (XEXP (x, 0), 1)) == SYMBOL_REF)
3061: {
3062: base = XEXP (XEXP (x, 0), 1);
3063: output_addr_const (file, base);
3064: }
3065: else if (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
3066: offset = INTVAL (XEXP (XEXP (x, 0),1));
3067: else abort ();
3068:
3069: if (GET_CODE (XEXP (x, 0)) == PLUS)
3070: {
3071: if (offset < 0)
3072: {
3073: offset = -offset;
3074: sep = "-";
3075: }
3076: else
3077: sep = "+";
3078: }
3079: else if (GET_CODE (XEXP (x, 0)) == MINUS
3080: && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
3081: sep = "-";
3082: else abort ();
3083:
3084: #ifndef NeXT_ASM
3085: if (!read_only_operand (base))
3086: fprintf (file, "-$global$");
3087: #endif
3088: if (offset)
3089: {
3090: fprintf (file,"%s%d", sep, offset);
3091: }
3092: }
3093: else
3094: output_addr_const (file, x);
3095: }
3096:
3097: /* HP's millicode routines mean something special to the assembler.
3098: Keep track of which ones we have used. */
3099:
3100: enum millicodes { remI, remU, divI, divU, mulI, mulU, end1000 };
3101: static char imported[(int)end1000];
3102: static char *milli_names[] = {"remI", "remU", "divI", "divU", "mulI", "mulU"};
3103: static char import_string[] = ".IMPORT $$....,MILLICODE";
3104: #define MILLI_START 10
3105:
3106: static void
3107: import_milli (code)
3108: enum millicodes code;
3109: {
3110: #ifndef NeXT_ASM
3111: char str[sizeof (import_string)];
3112:
3113: if (!imported[(int)code])
3114: {
3115: imported[(int)code] = 1;
3116: strcpy (str, import_string);
3117: strncpy (str + MILLI_START, milli_names[(int)code], 4);
3118: output_asm_insn (str, 0);
3119: }
3120: #endif
3121: }
3122:
3123: /* The register constraints have put the operands and return value in
3124: the proper registers. */
3125:
3126: char *
3127: output_mul_insn (unsignedp, insn)
3128: int unsignedp;
3129: rtx insn;
3130: {
3131:
3132: if (unsignedp)
3133: {
3134: import_milli (mulU);
3135: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulU"),
3136: gen_rtx (REG, SImode, 31));
3137: }
3138: else
3139: {
3140: import_milli (mulI);
3141: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulI"),
3142: gen_rtx (REG, SImode, 31));
3143: }
3144: }
3145:
3146: /* If operands isn't NULL, then it's a CONST_INT with which we can do
3147: something */
3148:
3149:
3150: /* Emit the rtl for doing a division by a constant. */
3151:
3152: /* Do magic division millicodes exist for this value? */
3153:
3154: static int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
3155: 1, 1};
3156:
3157: /* We'll use an array to keep track of the magic millicodes and
3158: whether or not we've used them already. [n][0] is signed, [n][1] is
3159: unsigned. */
3160:
3161: static int div_milli[16][2];
3162:
3163: int
3164: div_operand (op, mode)
3165: rtx op;
3166: enum machine_mode mode;
3167: {
3168: return (mode == SImode
3169: && ((GET_CODE (op) == REG && REGNO (op) == 25)
3170: || (GET_CODE (op) == CONST_INT && INTVAL (op) > 0
3171: && INTVAL (op) < 16 && magic_milli[INTVAL (op)])));
3172: }
3173:
3174: int
3175: emit_hpdiv_const (operands, unsignedp)
3176: rtx *operands;
3177: int unsignedp;
3178: {
3179: if (GET_CODE (operands[2]) == CONST_INT
3180: && INTVAL (operands[2]) > 0
3181: && INTVAL (operands[2]) < 16
3182: && magic_milli[INTVAL (operands[2])])
3183: {
3184: emit_move_insn ( gen_rtx (REG, SImode, 26), operands[1]);
3185: emit
3186: (gen_rtx
3187: (PARALLEL, VOIDmode,
3188: gen_rtvec (6, gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 29),
3189: gen_rtx (unsignedp ? UDIV : DIV, SImode,
3190: gen_rtx (REG, SImode, 26),
3191: operands[2])),
3192: gen_rtx (CLOBBER, VOIDmode, operands[3]),
3193: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 26)),
3194: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 25)),
3195: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 19)),
3196: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 31)))));
3197: emit_move_insn (operands[0], gen_rtx (REG, SImode, 29));
3198: return 1;
3199: }
3200: return 0;
3201: }
3202:
3203: char *
3204: output_div_insn (operands, unsignedp, insn)
3205: rtx *operands;
3206: int unsignedp;
3207: rtx insn;
3208: {
3209: int divisor;
3210:
3211: /* If the divisor is a constant, try to use one of the special
3212: opcodes .*/
3213: if (GET_CODE (operands[0]) == CONST_INT)
3214: {
3215: static char buf[100];
3216: divisor = INTVAL (operands[0]);
3217: if (!div_milli[divisor][unsignedp])
3218: {
3219: div_milli[divisor][unsignedp] = 1;
3220: #ifndef NeXT_ASM
3221: if (unsignedp)
3222: output_asm_insn (".IMPORT $$divU_%0,MILLICODE", operands);
3223: else
3224: output_asm_insn (".IMPORT $$divI_%0,MILLICODE", operands);
3225: #endif
3226: }
3227: if (unsignedp)
3228: {
3229: sprintf (buf, "$$divU_%d", INTVAL (operands[0]));
3230: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf),
3231: gen_rtx (REG, SImode, 31));
3232: }
3233: else
3234: {
3235: sprintf (buf, "$$divI_%d", INTVAL (operands[0]));
3236: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf),
3237: gen_rtx (REG, SImode, 31));
3238: }
3239: }
3240: /* Divisor isn't a special constant. */
3241: else
3242: {
3243: if (unsignedp)
3244: {
3245: import_milli (divU);
3246: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divU"),
3247: gen_rtx (REG, SImode, 31));
3248: }
3249: else
3250: {
3251: import_milli (divI);
3252: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divI"),
3253: gen_rtx (REG, SImode, 31));
3254: }
3255: }
3256: }
3257:
3258: /* Output a $$rem millicode to do mod. */
3259:
3260: char *
3261: output_mod_insn (unsignedp, insn)
3262: int unsignedp;
3263: rtx insn;
3264: {
3265: if (unsignedp)
3266: {
3267: import_milli (remU);
3268: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remU"),
3269: gen_rtx (REG, SImode, 31));
3270: }
3271: else
3272: {
3273: import_milli (remI);
3274: return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remI"),
3275: gen_rtx (REG, SImode, 31));
3276: }
3277: }
3278:
3279: void
3280: output_arg_descriptor (insn)
3281: rtx insn;
3282: {
3283: char *arg_regs[4];
3284: enum machine_mode arg_mode;
3285: rtx prev_insn;
3286: int i, output_flag = 0;
3287: int regno;
3288:
3289: for (i = 0; i < 4; i++)
3290: arg_regs[i] = 0;
3291:
3292: for (prev_insn = PREV_INSN (insn); GET_CODE (prev_insn) == INSN;
3293: prev_insn = PREV_INSN (prev_insn))
3294: {
3295: /* Terminate search for arguments if a non-USE insn is encountered
3296: or a USE insn which does not specify an argument, STATIC_CHAIN,
3297: or STRUCT_VALUE register. */
3298: if (!(GET_CODE (PATTERN (prev_insn)) == USE
3299: && GET_CODE (XEXP (PATTERN (prev_insn), 0)) == REG
3300: && (FUNCTION_ARG_REGNO_P (REGNO (XEXP (PATTERN (prev_insn), 0)))
3301: || REGNO (XEXP (PATTERN (prev_insn), 0)) == STATIC_CHAIN_REGNUM
3302: || REGNO (XEXP (PATTERN (prev_insn), 0))
3303: == STRUCT_VALUE_REGNUM)))
3304: break;
3305:
3306: /* If this is a USE for the STATIC_CHAIN or STRUCT_VALUE register,
3307: then skip it and continue the loop since those are not encoded
3308: in the argument relocation bits. */
3309: if (REGNO (XEXP (PATTERN (prev_insn), 0)) == STATIC_CHAIN_REGNUM
3310: || REGNO (XEXP (PATTERN (prev_insn), 0)) == STRUCT_VALUE_REGNUM)
3311: continue;
3312:
3313: arg_mode = GET_MODE (XEXP (PATTERN (prev_insn), 0));
3314: regno = REGNO (XEXP (PATTERN (prev_insn), 0));
3315: if (regno >= 23 && regno <= 26)
3316: {
3317: arg_regs[26 - regno] = "GR";
3318: if (arg_mode == DImode)
3319: arg_regs[25 - regno] = "GR";
3320: }
3321: else if (!TARGET_SNAKE) /* fp args */
3322: {
3323: if (arg_mode == SFmode)
3324: arg_regs[regno - 32] = "FR";
3325: else
3326: {
3327: #ifndef HP_FP_ARG_DESCRIPTOR_REVERSED
3328: arg_regs[regno - 33] = "FR";
3329: arg_regs[regno - 32] = "FU";
3330: #else
3331: arg_regs[regno - 33] = "FU";
3332: arg_regs[regno - 32] = "FR";
3333: #endif
3334: }
3335: }
3336: else
3337: {
3338: if (arg_mode == SFmode)
3339: arg_regs[(regno - 44) / 2] = "FR";
3340: else
3341: {
3342: #ifndef HP_FP_ARG_DESCRIPTOR_REVERSED
3343: arg_regs[(regno - 46) / 2] = "FR";
3344: arg_regs[(regno - 46) / 2 + 1] = "FU";
3345: #else
3346: arg_regs[(regno - 46) / 2] = "FU";
3347: arg_regs[(regno - 46) / 2 + 1] = "FR";
3348: #endif
3349: }
3350: }
3351: }
3352: #ifndef NeXT_ASM
3353: fputs ("\t.CALL ", asm_out_file);
3354: for (i = 0; i < 4; i++)
3355: {
3356: if (arg_regs[i])
3357: {
3358: if (output_flag++)
3359: fputc (',', asm_out_file);
3360: fprintf (asm_out_file, "ARGW%d=%s", i, arg_regs[i]);
3361: }
3362: }
3363: fputc ('\n', asm_out_file);
3364: #endif
3365: }
3366:
3367: /* Memory loads/stores to/from the shift need to go through
3368: the general registers. */
3369:
3370: enum reg_class
3371: secondary_reload_class (class, mode, in)
3372: enum reg_class class;
3373: enum machine_mode mode;
3374: rtx in;
3375: {
3376: int regno = true_regnum (in);
3377:
3378: if (function_label_operand (in, mode)
3379: || ((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
3380: && GET_MODE_CLASS (mode) == MODE_INT
3381: && FP_REG_CLASS_P (class))
3382: || (class == SHIFT_REGS && (regno <= 0 || regno >= 32)))
3383: return GENERAL_REGS;
3384:
3385: if (GET_CODE (in) == HIGH)
3386: in = XEXP (in, 0);
3387:
3388: if (class != R1_REGS && symbolic_operand (in, VOIDmode))
3389: return R1_REGS;
3390:
3391: return NO_REGS;
3392: }
3393:
3394: enum direction
3395: function_arg_padding (mode, type)
3396: enum machine_mode mode;
3397: tree type;
3398: {
3399: int size;
3400:
3401: if (mode == BLKmode)
3402: {
3403: if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
3404: size = int_size_in_bytes (type) * BITS_PER_UNIT;
3405: else
3406: return upward; /* Don't know if this is right, but */
3407: /* same as old definition. */
3408: }
3409: else
3410: size = GET_MODE_BITSIZE (mode);
3411: if (size < PARM_BOUNDARY)
3412: return downward;
3413: else if (size % PARM_BOUNDARY)
3414: return upward;
3415: else
3416: return none;
3417: }
3418:
3419:
3420: /* Do what is necessary for `va_start'. The argument is ignored;
3421: We look at the current function to determine if stdargs or varargs
3422: is used and fill in an initial va_list. A pointer to this constructor
3423: is returned. */
3424:
3425: struct rtx_def *
3426: hppa_builtin_saveregs (arglist)
3427: tree arglist;
3428: {
3429: rtx offset;
3430: tree fntype = TREE_TYPE (current_function_decl);
3431: int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
3432: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
3433: != void_type_node)))
3434: ? UNITS_PER_WORD : 0);
3435:
3436: if (argadj)
3437: offset = plus_constant (current_function_arg_offset_rtx, argadj);
3438: else
3439: offset = current_function_arg_offset_rtx;
3440:
3441: /* Store general registers on the stack. */
3442: move_block_from_reg (23,
3443: gen_rtx (MEM, BLKmode,
3444: plus_constant
3445: (current_function_internal_arg_pointer, -16)),
3446: 4, 4 * UNITS_PER_WORD);
3447: return copy_to_reg (expand_binop (Pmode, add_optab,
3448: current_function_internal_arg_pointer,
3449: offset, 0, 0, OPTAB_LIB_WIDEN));
3450: }
3451:
3452: /* This routine handles all the normal conditional branch sequences we
3453: might need to generate. It handles compare immediate vs compare
3454: register, nullification of delay slots, varying length branches,
3455: negated branches, and all combinations of the above. It returns the
3456: output appropriate to emit the branch corresponding to all given
3457: parameters. */
3458:
3459: char *
3460: output_cbranch (operands, nullify, length, negated, insn)
3461: rtx *operands;
3462: int nullify, length, negated;
3463: rtx insn;
3464: {
3465: static char buf[100];
3466: int useskip = 0;
3467:
3468: /* A conditional branch to the following instruction (eg the delay slot) is
3469: asking for a disaster. This can happen when not optimizing.
3470:
3471: In such cases it is safe to emit nothing. */
3472:
3473: if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
3474: return "";
3475:
3476: /* If this is a long branch with its delay slot unfilled, set `nullify'
3477: as it can nullify the delay slot and save a nop. */
3478: if (length == 8 && dbr_sequence_length () == 0)
3479: nullify = 1;
3480:
3481: /* If this is a short forward conditional branch which did not get
3482: its delay slot filled, the delay slot can still be nullified. */
3483: if (! nullify && length == 4 && dbr_sequence_length () == 0)
3484: nullify = forward_branch_p (insn);
3485:
3486: /* A forward branch over a single nullified insn can be done with a
3487: comclr instruction. This avoids a single cycle penalty due to
3488: mis-predicted branch if we fall through (branch not taken). */
3489: if (length == 4
3490: && next_real_insn (insn) != 0
3491: && get_attr_length (next_real_insn (insn)) == 4
3492: && JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
3493: && nullify)
3494: useskip = 1;
3495:
3496: switch (length)
3497: {
3498: /* All short conditional branches except backwards with an unfilled
3499: delay slot. */
3500: case 4:
3501: if (useskip)
3502: strcpy (buf, "com%I2clr,");
3503: else
3504: strcpy (buf, "com%I2b,");
3505: if (negated)
3506: strcat (buf, "%B3");
3507: else
3508: strcat (buf, "%S3");
3509: if (useskip)
3510: strcat (buf, " %2,%1,%%r0");
3511: else if (nullify)
3512: strcat (buf, ",n %2,%1,%0");
3513: else
3514: strcat (buf, " %2,%1,%0");
3515: break;
3516:
3517: /* All long conditionals. Note an short backward branch with an
3518: unfilled delay slot is treated just like a long backward branch
3519: with an unfilled delay slot. */
3520: case 8:
3521: /* Handle weird backwards branch with a filled delay slot
3522: with is nullified. */
3523: if (dbr_sequence_length () != 0
3524: && ! forward_branch_p (insn)
3525: && nullify)
3526: {
3527: strcpy (buf, "com%I2b,");
3528: if (negated)
3529: strcat (buf, "%S3");
3530: else
3531: strcat (buf, "%B3");
3532: strcat (buf, ",n %2,%1,.+12\n\tbl %0,%%r0");
3533: }
3534: else
3535: {
3536: strcpy (buf, "com%I2clr,");
3537: if (negated)
3538: strcat (buf, "%S3");
3539: else
3540: strcat (buf, "%B3");
3541: if (nullify)
3542: strcat (buf, " %2,%1,%%r0\n\tbl,n %0,%%r0");
3543: else
3544: strcat (buf, " %2,%1,%%r0\n\tbl %0,%%r0");
3545: }
3546: break;
3547:
3548: default:
3549: abort();
3550: }
3551: return buf;
3552: }
3553:
3554: /* This routine handles all the branch-on-bit conditional branch sequences we
3555: might need to generate. It handles nullification of delay slots,
3556: varying length branches, negated branches and all combinations of the
3557: above. it returns the appropriate output template to emit the branch. */
3558:
3559: char *
3560: output_bb (operands, nullify, length, negated, insn, which)
3561: rtx *operands;
3562: int nullify, length, negated;
3563: rtx insn;
3564: int which;
3565: {
3566: static char buf[100];
3567: int useskip = 0;
3568:
3569: /* A conditional branch to the following instruction (eg the delay slot) is
3570: asking for a disaster. I do not think this can happen as this pattern
3571: is only used when optimizing; jump optimization should eliminate the
3572: jump. But be prepared just in case. */
3573:
3574: if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
3575: return "";
3576:
3577: /* If this is a long branch with its delay slot unfilled, set `nullify'
3578: as it can nullify the delay slot and save a nop. */
3579: if (length == 8 && dbr_sequence_length () == 0)
3580: nullify = 1;
3581:
3582: /* If this is a short forward conditional branch which did not get
3583: its delay slot filled, the delay slot can still be nullified. */
3584: if (! nullify && length == 4 && dbr_sequence_length () == 0)
3585: nullify = forward_branch_p (insn);
3586:
3587: /* A forward branch over a single nullified insn can be done with a
3588: extrs instruction. This avoids a single cycle penalty due to
3589: mis-predicted branch if we fall through (branch not taken). */
3590:
3591: if (length == 4
3592: && next_real_insn (insn) != 0
3593: && get_attr_length (next_real_insn (insn)) == 4
3594: && JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
3595: && nullify)
3596: useskip = 1;
3597:
3598: switch (length)
3599: {
3600:
3601: /* All short conditional branches except backwards with an unfilled
3602: delay slot. */
3603: case 4:
3604: if (useskip)
3605: strcpy (buf, "extrs,");
3606: else
3607: strcpy (buf, "bb,");
3608: if ((which == 0 && negated)
3609: || (which == 1 && ! negated))
3610: strcat (buf, ">=");
3611: else
3612: strcat (buf, "<");
3613: if (useskip)
3614: strcat (buf, " %0,%1,1,0");
3615: else if (nullify && negated)
3616: strcat (buf, ",n %0,%1,%3");
3617: else if (nullify && ! negated)
3618: strcat (buf, ",n %0,%1,%2");
3619: else if (! nullify && negated)
3620: strcat (buf, "%0,%1,%3");
3621: else if (! nullify && ! negated)
3622: strcat (buf, " %0,%1,%2");
3623: break;
3624:
3625: /* All long conditionals. Note an short backward branch with an
3626: unfilled delay slot is treated just like a long backward branch
3627: with an unfilled delay slot. */
3628: case 8:
3629: /* Handle weird backwards branch with a filled delay slot
3630: with is nullified. */
3631: if (dbr_sequence_length () != 0
3632: && ! forward_branch_p (insn)
3633: && nullify)
3634: {
3635: strcpy (buf, "bb,");
3636: if ((which == 0 && negated)
3637: || (which == 1 && ! negated))
3638: strcat (buf, "<");
3639: else
3640: strcat (buf, ">=");
3641: if (negated)
3642: strcat (buf, " %0,%1,.+12\n\tbl %3,%%r0");
3643: else
3644: strcat (buf, " %0,%1,.+12\n\tbl %2,%%r0");
3645: }
3646: else
3647: {
3648: strcpy (buf, "extrs,");
3649: if ((which == 0 && negated)
3650: || (which == 1 && ! negated))
3651: strcat (buf, "<");
3652: else
3653: strcat (buf, ">=");
3654: if (nullify && negated)
3655: strcat (buf, " %0,%1,1,0\n\tbl,n %3,%%r0");
3656: else if (nullify && ! negated)
3657: strcat (buf, " %0,%1,1,0\n\tbl,n %2,%%r0");
3658: else if (negated)
3659: strcat (buf, " %0,%1,1,0\n\tbl %3,%%r0");
3660: else
3661: strcat (buf, " %0,%1,1,0\n\tbl %2,%%r0");
3662: }
3663: break;
3664:
3665: default:
3666: abort();
3667: }
3668: return buf;
3669: }
3670:
3671: /* Return the output template for emitting a dbra type insn.
3672:
3673: Note it may perform some output operations on its own before
3674: returning the final output string. */
3675: char *
3676: output_dbra (operands, insn, which_alternative)
3677: rtx *operands;
3678: rtx insn;
3679: int which_alternative;
3680: {
3681:
3682: /* A conditional branch to the following instruction (eg the delay slot) is
3683: asking for a disaster. Be prepared! */
3684:
3685: if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
3686: {
3687: if (which_alternative == 0)
3688: return "ldo %1(%0),%0";
3689: else if (which_alternative == 1)
3690: {
3691: output_asm_insn ("fstws %0,-16(0,%%r30)",operands);
3692: output_asm_insn ("ldw -16(0,%%r30),%4",operands);
3693: output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(0,%%r30)", operands);
3694: return "fldws -16(0,%%r30),%0";
3695: }
3696: else
3697: {
3698: output_asm_insn ("ldw %0,%4", operands);
3699: return "ldo %1(%4),%4\n\tstw %4,%0";
3700: }
3701: }
3702:
3703: if (which_alternative == 0)
3704: {
3705: int nullify = INSN_ANNULLED_BRANCH_P (insn);
3706: int length = get_attr_length (insn);
3707:
3708: /* If this is a long branch with its delay slot unfilled, set `nullify'
3709: as it can nullify the delay slot and save a nop. */
3710: if (length == 8 && dbr_sequence_length () == 0)
3711: nullify = 1;
3712:
3713: /* If this is a short forward conditional branch which did not get
3714: its delay slot filled, the delay slot can still be nullified. */
3715: if (! nullify && length == 4 && dbr_sequence_length () == 0)
3716: nullify = forward_branch_p (insn);
3717:
3718: /* Handle short versions first. */
3719: if (length == 4 && nullify)
3720: return "addib,%C2,n %1,%0,%3";
3721: else if (length == 4 && ! nullify)
3722: return "addib,%C2 %1,%0,%3";
3723: else if (length == 8)
3724: {
3725: /* Handle weird backwards branch with a fulled delay slot
3726: which is nullified. */
3727: if (dbr_sequence_length () != 0
3728: && ! forward_branch_p (insn)
3729: && nullify)
3730: return "addib,%N2,n %1,%0,.+12\n\tbl %3,0";
3731:
3732: /* Handle normal cases. */
3733: if (nullify)
3734: return "addi,%N2 %1,%0,%0\n\tbl,n %3,0";
3735: else
3736: return "addi,%N2 %1,%0,%0\n\tbl %3,0";
3737: }
3738: else
3739: abort();
3740: }
3741: /* Deal with gross reload from FP register case. */
3742: else if (which_alternative == 1)
3743: {
3744: /* Move loop counter from FP register to MEM then into a GR,
3745: increment the GR, store the GR into MEM, and finally reload
3746: the FP register from MEM from within the branch's delay slot. */
3747: output_asm_insn ("fstws %0,-16(0,%%r30)\n\tldw -16(0,%%r30),%4",operands);
3748: output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(0,%%r30)", operands);
3749: if (get_attr_length (insn) == 24)
3750: return "comb,%S2 0,%4,%3\n\tfldws -16(0,%%r30),%0";
3751: else
3752: return "comclr,%B2 0,%4,0\n\tbl %3,0\n\tfldws -16(0,%%r30),%0";
3753: }
3754: /* Deal with gross reload from memory case. */
3755: else
3756: {
3757: /* Reload loop counter from memory, the store back to memory
3758: happens in the branch's delay slot. */
3759: output_asm_insn ("ldw %0,%4", operands);
3760: if (get_attr_length (insn) == 12)
3761: return "addib,%C2 %1,%4,%3\n\tstw %4,%0";
3762: else
3763: return "addi,%N2 %1,%4,%4\n\tbl %3,0\n\tstw %4,%0";
3764: }
3765: }
3766:
3767: /* Return the output template for emitting a dbra type insn.
3768:
3769: Note it may perform some output operations on its own before
3770: returning the final output string. */
3771: char *
3772: output_movb (operands, insn, which_alternative, reverse_comparison)
3773: rtx *operands;
3774: rtx insn;
3775: int which_alternative;
3776: int reverse_comparison;
3777: {
3778:
3779: /* A conditional branch to the following instruction (eg the delay slot) is
3780: asking for a disaster. Be prepared! */
3781:
3782: if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
3783: {
3784: if (which_alternative == 0)
3785: return "copy %1,%0";
3786: else if (which_alternative == 1)
3787: {
3788: output_asm_insn ("stw %1,-16(0,%%r30)",operands);
3789: return "fldws -16(0,%%r30),%0";
3790: }
3791: else
3792: return "stw %1,%0";
3793: }
3794:
3795: /* Support the second variant. */
3796: if (reverse_comparison)
3797: PUT_CODE (operands[2], reverse_condition (GET_CODE (operands[2])));
3798:
3799: if (which_alternative == 0)
3800: {
3801: int nullify = INSN_ANNULLED_BRANCH_P (insn);
3802: int length = get_attr_length (insn);
3803:
3804: /* If this is a long branch with its delay slot unfilled, set `nullify'
3805: as it can nullify the delay slot and save a nop. */
3806: if (length == 8 && dbr_sequence_length () == 0)
3807: nullify = 1;
3808:
3809: /* If this is a short forward conditional branch which did not get
3810: its delay slot filled, the delay slot can still be nullified. */
3811: if (! nullify && length == 4 && dbr_sequence_length () == 0)
3812: nullify = forward_branch_p (insn);
3813:
3814: /* Handle short versions first. */
3815: if (length == 4 && nullify)
3816: return "movb,%C2,n %1,%0,%3";
3817: else if (length == 4 && ! nullify)
3818: return "movb,%C2 %1,%0,%3";
3819: else if (length == 8)
3820: {
3821: /* Handle weird backwards branch with a fulled delay slot
3822: which is nullified. */
3823: if (dbr_sequence_length () != 0
3824: && ! forward_branch_p (insn)
3825: && nullify)
3826: return "movb,%N2,n %1,%0,.+12\n\ttbl %3,0";
3827:
3828: /* Handle normal cases. */
3829: if (nullify)
3830: return "or,%N2 %1,%%r0,%0\n\tbl,n %3,0";
3831: else
3832: return "or,%N2 %1,%%r0,%0\n\tbl %3,0";
3833: }
3834: else
3835: abort();
3836: }
3837: /* Deal with gross reload from FP register case. */
3838: else if (which_alternative == 1)
3839: {
3840: /* Move loop counter from FP register to MEM then into a GR,
3841: increment the GR, store the GR into MEM, and finally reload
3842: the FP register from MEM from within the branch's delay slot. */
3843: output_asm_insn ("stw %1,-16(0,%%r30)",operands);
3844: if (get_attr_length (insn) == 12)
3845: return "comb,%S2 0,%1,%3\n\tfldws -16(0,%%r30),%0";
3846: else
3847: return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tfldws -16(0,%%r30),%0";
3848: }
3849: /* Deal with gross reload from memory case. */
3850: else
3851: {
3852: /* Reload loop counter from memory, the store back to memory
3853: happens in the branch's delay slot. */
3854: if (get_attr_length (insn) == 8)
3855: return "comb,%S2 0,%1,%3\n\tstw %1,%0";
3856: else
3857: return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tstw %1,%0";
3858: }
3859: }
3860:
3861:
3862: /* Output a local call insn not emitting insns for the delay slot.
3863: If -mstub-calls is enabled, we emit the pseudo insn "jbsr", to
3864: a locally generated stub, and make that stub do the actual call.
3865:
3866: CALL_DEST is the routine we are calling.
3867:
3868: RETURN_POINTER is the register which will hold the return address.
3869: %r2 for most calls, %r31 for millicode calls. */
3870: #ifdef NeXT_ASM
3871: void add_compiler_stub PROTO((tree, tree, int));
3872: void output_compiler_stub PROTO ((void));
3873: int no_previous_def PROTO((tree));
3874: tree get_prev_label PROTO((tree));
3875:
3876: #endif
3877:
3878: void
3879: output_call_insn (insn, call_dest, return_pointer)
3880: rtx insn;
3881: rtx call_dest;
3882: rtx return_pointer;
3883:
3884: {
3885: rtx xoperands[2];
3886:
3887: xoperands[0] = call_dest;
3888: xoperands[1] = return_pointer;
3889:
3890: #ifdef NeXT_ASM
3891: if(GET_CODE (call_dest) == SYMBOL_REF)
3892: {
3893: rtx prev_insn, label_rtx;
3894: int line_number;
3895: static char buf[256];
3896: static char temp_buf[256];
3897: char *label_buf;
3898: tree labelname;
3899: tree funname = get_identifier (XSTR (call_dest, 0));
3900:
3901: if (!flag_pic && !strncmp (IDENTIFIER_POINTER (funname), "$$", 2))
3902: {
3903: {
3904: strcpy (temp_buf, "ldil L%'");
3905: strcat (temp_buf, IDENTIFIER_POINTER (funname));
3906: strcat (temp_buf, ",%%r31\n\tble R%'");
3907: strcat (temp_buf, IDENTIFIER_POINTER (funname));
3908: strcat (temp_buf, "(4,%%r31)");
3909: output_asm_insn (temp_buf, 0);
3910: }
3911: return;
3912: }
3913: else if (!strncmp (IDENTIFIER_POINTER (funname), "$$", 2))
3914: {
3915: strcpy (temp_buf, "*");
3916: strcat (temp_buf, XSTR (call_dest, 0));
3917: funname = get_identifier (temp_buf);
3918: }
3919: if (no_previous_def (funname))
3920: {
3921: label_rtx = gen_label_rtx ();
3922:
3923: ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L", CODE_LABEL_NUMBER(label_rtx));
3924:
3925: if (temp_buf[0] == '*')
3926: label_buf = temp_buf + 1;
3927: else
3928: label_buf = temp_buf;
3929:
3930: while (insn && GET_CODE (insn) != NOTE)
3931: insn = PREV_INSN (insn);
3932:
3933: if (insn)
3934: line_number = NOTE_LINE_NUMBER (insn);
3935:
3936: labelname =get_identifier (label_buf);
3937: add_compiler_stub(labelname, funname, line_number);
3938: }
3939: else
3940: {
3941: labelname = get_prev_label (funname);
3942: }
3943:
3944: strcpy(buf, "jbsr %0,%r1,");
3945: strcat(buf, IDENTIFIER_POINTER (labelname));
3946:
3947: output_asm_insn (buf, xoperands);
3948: }
3949: else
3950: #endif
3951: output_asm_insn ("bl %0,%r1", xoperands);
3952: }
3953:
3954: /* INSN is either a function call or a millicode call. It may have an
3955: unconditional jump in its delay slot.
3956:
3957: CALL_DEST is the routine we are calling.
3958:
3959: RETURN_POINTER is the register which will hold the return address.
3960: %r2 for most calls, %r31 for millicode calls. */
3961: char *
3962: output_call (insn, call_dest, return_pointer)
3963: rtx insn;
3964: rtx call_dest;
3965: rtx return_pointer;
3966:
3967: {
3968: int distance;
3969: rtx xoperands[4];
3970: rtx seq_insn;
3971:
3972: /* Handle common case -- empty delay slot or no jump in the delay slot. */
3973: if (dbr_sequence_length () == 0
3974: || (dbr_sequence_length () != 0
3975: && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN))
3976: {
3977: output_call_insn (insn, call_dest, return_pointer);
3978: if (dbr_sequence_length () == 0)
3979: output_asm_insn ("nop", xoperands);
3980: return "";
3981: }
3982:
3983: /* This call has an unconditional jump in its delay slot. */
3984:
3985: /* Use the containing sequence insn's address. */
3986: seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
3987:
3988: distance = insn_addresses[INSN_UID (JUMP_LABEL (NEXT_INSN (insn)))]
3989: - insn_addresses[INSN_UID (seq_insn)] - 8;
3990:
3991: /* If the branch was too far away, emit a normal call followed
3992: by a nop, followed by the unconditional branch.
3993:
3994: If the branch is close, then adjust %r2 from within the
3995: call's delay slot. */
3996:
3997: xoperands[0] = call_dest;
3998: xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
3999: xoperands[2] = return_pointer;
4000: if (! VAL_14_BITS_P (distance))
4001: {
4002: output_call_insn (insn, call_dest, return_pointer);
4003: output_asm_insn ("nop\n\tbl,n %1,%%r0", xoperands);
4004: }
4005: else
4006: {
4007: xoperands[3] = gen_label_rtx ();
4008: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
4009: CODE_LABEL_NUMBER (xoperands[3]));
4010: output_call_insn (insn, call_dest, return_pointer);
4011: output_asm_insn ("ldo %1-%3-8(%r2),%r2", xoperands);
4012: }
4013:
4014: /* Delete the jump. */
4015: PUT_CODE (NEXT_INSN (insn), NOTE);
4016: NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
4017: NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
4018: return "";
4019: }
4020:
4021: extern struct obstack *saveable_obstack;
4022:
4023: /* In HPUX 8.0's shared library scheme, special relocations are needed
4024: for function labels if they might be passed to a function
4025: in a shared library (because shared libraries don't live in code
4026: space), and special magic is needed to construct their address. */
4027:
4028: void
4029: hppa_encode_label (sym)
4030: rtx sym;
4031: {
4032: char *str = XSTR (sym, 0);
4033: int len = strlen (str);
4034: char *newstr = obstack_alloc (saveable_obstack, len + 2) ;
4035:
4036: if (str[0] == '*')
4037: *newstr++ = *str++;
4038: strcpy (newstr + 1, str);
4039: *newstr = '@';
4040: XSTR (sym,0) = newstr;
4041: }
4042:
4043: int
4044: function_label_operand (op, mode)
4045: rtx op;
4046: enum machine_mode mode;
4047: {
4048: return GET_CODE (op) == SYMBOL_REF && FUNCTION_NAME_P (XSTR (op, 0));
4049: }
4050:
4051: /* Returns 1 if the 6 operands specified in OPERANDS are suitable for
4052: use in fmpyadd instructions. */
4053: int
4054: fmpyaddoperands(operands)
4055: rtx *operands;
4056: {
4057: enum machine_mode mode = GET_MODE (operands[0]);
4058:
4059: /* All modes must be the same. */
4060: if (! (mode == GET_MODE (operands[1])
4061: && mode == GET_MODE (operands[2])
4062: && mode == GET_MODE (operands[3])
4063: && mode == GET_MODE (operands[4])
4064: && mode == GET_MODE (operands[5])))
4065: return 0;
4066:
4067: /* Both DFmode and SFmode should work. But using SFmode makes the
4068: assembler complain. Just turn it off for now. */
4069: if (mode != DFmode)
4070: return 0;
4071:
4072: /* Only 2 real operands to the addition. One of the input operands must
4073: be the same as the output operand. */
4074: if (! rtx_equal_p (operands[3], operands[4])
4075: && ! rtx_equal_p (operands[3], operands[5]))
4076: return 0;
4077:
4078: /* Inout operand of add can not conflict with any operands from multiply. */
4079: if (rtx_equal_p (operands[3], operands[0])
4080: || rtx_equal_p (operands[3], operands[1])
4081: || rtx_equal_p (operands[3], operands[2]))
4082: return 0;
4083:
4084: /* multiply can not feed into addition operands. */
4085: if (rtx_equal_p (operands[4], operands[0])
4086: || rtx_equal_p (operands[5], operands[0]))
4087: return 0;
4088:
4089: /* Passed. Operands are suitable for fmpyadd. */
4090: return 1;
4091: }
4092:
4093: /* Returns 1 if the 6 operands specified in OPERANDS are suitable for
4094: use in fmpysub instructions. */
4095: int
4096: fmpysuboperands(operands)
4097: rtx *operands;
4098: {
4099: enum machine_mode mode = GET_MODE (operands[0]);
4100:
4101: /* All modes must be the same. */
4102: if (! (mode == GET_MODE (operands[1])
4103: && mode == GET_MODE (operands[2])
4104: && mode == GET_MODE (operands[3])
4105: && mode == GET_MODE (operands[4])
4106: && mode == GET_MODE (operands[5])))
4107: return 0;
4108:
4109: /* Both DFmode and SFmode should work. But using SFmode makes the
4110: assembler complain. Just turn it off for now. */
4111: if (mode != DFmode)
4112: return 0;
4113:
4114: /* Only 2 real operands to the subtraction. Subtraction is not a commutative
4115: operation, so operands[4] must be the same as operand[3]. */
4116: if (! rtx_equal_p (operands[3], operands[4]))
4117: return 0;
4118:
4119: /* multiply can not feed into subtraction. */
4120: if (rtx_equal_p (operands[5], operands[0]))
4121: return 0;
4122:
4123: /* Inout operand of sub can not conflict with any operands from multiply. */
4124: if (rtx_equal_p (operands[3], operands[0])
4125: || rtx_equal_p (operands[3], operands[1])
4126: || rtx_equal_p (operands[3], operands[2]))
4127: return 0;
4128:
4129: /* Passed. Operands are suitable for fmpysub. */
4130: return 1;
4131: }
4132:
4133: int
4134: plus_xor_ior_operator (op, mode)
4135: rtx op;
4136: enum machine_mode mode;
4137: {
4138: return (GET_CODE (op) == PLUS || GET_CODE (op) == XOR
4139: || GET_CODE (op) == IOR);
4140: }
4141:
4142: /* Return 1 if the given constant is 2, 4, or 8. These are the valid
4143: constants for shadd instructions. */
4144: int
4145: shadd_constant_p (val)
4146: int val;
4147: {
4148: if (val == 2 || val == 4 || val == 8)
4149: return 1;
4150: else
4151: return 0;
4152: }
4153:
4154: /* Return 1 if OP is a CONST_INT with the value 2, 4, or 8. These are
4155: the valid constant for shadd instructions. */
4156: int
4157: shadd_operand (op, mode)
4158: rtx op;
4159: enum machine_mode mode;
4160: {
4161: return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op)));
4162: }
4163:
4164: /* Return 1 if INSN branches forward. Should be using insn_addresses
4165: to avoid walking through all the insns... */
4166: int
4167: forward_branch_p (insn)
4168: rtx insn;
4169: {
4170: rtx label = JUMP_LABEL (insn);
4171:
4172: while (insn)
4173: {
4174: if (insn == label)
4175: break;
4176: else
4177: insn = NEXT_INSN (insn);
4178: }
4179:
4180: return (insn == label);
4181: }
4182:
4183: /* Return 1 if OP is an equality comparison, else return 0. */
4184: int
4185: eq_neq_comparison_operator (op, mode)
4186: rtx op;
4187: enum machine_mode mode;
4188: {
4189: return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
4190: }
4191:
4192: /* Return 1 if OP is an operator suitable for use in a movb instruction. */
4193: int
4194: movb_comparison_operator (op, mode)
4195: rtx op;
4196: enum machine_mode mode;
4197: {
4198: return (GET_CODE (op) == EQ || GET_CODE (op) == NE
4199: || GET_CODE (op) == LT || GET_CODE (op) == GE);
4200: }
4201:
4202: /* Return 1 if INSN is in the delay slot of a call instruction. */
4203: int
4204: jump_in_call_delay (insn)
4205: rtx insn;
4206: {
4207:
4208: if (GET_CODE (insn) != JUMP_INSN)
4209: return 0;
4210:
4211: if (PREV_INSN (insn)
4212: && PREV_INSN (PREV_INSN (insn))
4213: && GET_CODE (next_active_insn (PREV_INSN (PREV_INSN (insn)))) == INSN)
4214: {
4215: rtx test_insn = next_active_insn (PREV_INSN (PREV_INSN (insn)));
4216:
4217: return (GET_CODE (PATTERN (test_insn)) == SEQUENCE
4218: && XVECEXP (PATTERN (test_insn), 0, 1) == insn);
4219:
4220: }
4221: else
4222: return 0;
4223: }
4224:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.