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