|
|
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 out-sparc.c
4:
5: This file is part of GNU CC.
6:
7: GNU CC is free software; you can redistribute it and/or modify
8: it under the terms of the GNU General Public License as published by
9: the Free Software Foundation; either version 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:
36: /* Save the operands last given to a compare for use when we
37: generate a scc or bcc insn. */
38:
39: rtx hppa_compare_op0, hppa_compare_op1;
40: enum cmp_type hppa_branch_type;
41:
42: /* Global variables set by FUNCTION_PROLOGUE. */
43: /* Size of frame. Need to know this to emit return insns from
44: leaf procedures. */
45: int apparent_fsize;
46: int actual_fsize;
47:
48: /* Name of where we pretend to think the frame pointer points.
49: Normally, this is "4", but if we are in a leaf procedure,
50: this is "something(30)". Will this work? */
51: char *frame_base_name;
52:
53: static rtx find_addr_reg ();
54:
55: /* Return non-zero only if OP is a register of mode MODE,
56: or const0_rtx. */
57: int
58: reg_or_0_operand (op, mode)
59: rtx op;
60: enum machine_mode mode;
61: {
62: return (op == const0_rtx || register_operand (op, mode));
63: }
64:
65: int
66: call_operand_address (op, mode)
67: rtx op;
68: enum machine_mode mode;
69: {
70: return (REG_P (op) || CONSTANT_P (op));
71: }
72:
73: int
74: symbolic_operand (op, mode)
75: register rtx op;
76: enum machine_mode mode;
77: {
78: switch (GET_CODE (op))
79: {
80: case SYMBOL_REF:
81: case LABEL_REF:
82: return 1;
83: case CONST:
84: op = XEXP (op, 0);
85: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
86: || GET_CODE (XEXP (op, 0)) == LABEL_REF)
87: && GET_CODE (XEXP (op, 1)) == CONST_INT);
88: default:
89: return 0;
90: }
91: }
92:
93: /* Return truth value of statement that OP is a symbolic memory
94: operand of mode MODE. */
95:
96: int
97: symbolic_memory_operand (op, mode)
98: rtx op;
99: enum machine_mode mode;
100: {
101: if (GET_CODE (op) == SUBREG)
102: op = SUBREG_REG (op);
103: if (GET_CODE (op) != MEM)
104: return 0;
105: op = XEXP (op, 0);
106: return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
107: || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
108: }
109:
110: /* Return 1 if the operand is either a register or a memory operand that is
111: not symbolic. */
112:
113: int
114: reg_or_nonsymb_mem_operand (op, mode)
115: register rtx op;
116: enum machine_mode mode;
117: {
118: if (register_operand (op, mode))
119: return 1;
120:
121: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
122: return 1;
123:
124: return 0;
125: }
126:
127: int
128: move_operand (op, mode)
129: rtx op;
130: enum machine_mode mode;
131: {
132: if (register_operand (op, mode))
133: return 1;
134:
135: if (op == CONST0_RTX (mode))
136: return 1;
137:
138: if (GET_MODE (op) != mode)
139: return 0;
140: if (GET_CODE (op) == SUBREG)
141: op = SUBREG_REG (op);
142: if (GET_CODE (op) != MEM)
143: return 0;
144:
145: op = XEXP (op, 0);
146: if (GET_CODE (op) == LO_SUM)
147: return (register_operand (XEXP (op, 0), Pmode)
148: && CONSTANT_P (XEXP (op, 1)));
149: return memory_address_p (mode, op);
150: }
151:
152: int
153: pic_operand (op, mode)
154: rtx op;
155: enum machine_mode mode;
156: {
157: return flag_pic && GET_CODE (op) == LABEL_REF;
158: }
159:
160: int
161: short_memory_operand (op, mode)
162: rtx op;
163: enum machine_mode mode;
164: {
165: if (GET_CODE (op) == MEM)
166: {
167: if (GET_CODE (XEXP (op, 0)) == REG)
168: return 1;
169: else if (GET_CODE (XEXP (op, 0)) == PLUS)
170: {
171: rtx op1 = XEXP (XEXP (op, 0), 0);
172: rtx op2 = XEXP (XEXP (op, 0), 1);
173:
174: if (GET_CODE (op1) == REG)
175: return (GET_CODE (op2) == CONST_INT && INT_5_BITS (op2));
176: else if (GET_CODE (op2) == REG)
177: return (GET_CODE (op1) == CONST_INT && INT_5_BITS (op1));
178: }
179: }
180: return 0;
181: }
182:
183: int
184: register_or_short_operand (op, mode)
185: rtx op;
186: enum machine_mode mode;
187: {
188: if (register_operand (op, mode))
189: return 1;
190: if (GET_CODE (op) == SUBREG)
191: op = SUBREG_REG (op);
192: return short_memory_operand (op, mode);
193: }
194:
195: int
196: fp_reg_operand (op, mode)
197: rtx op;
198: enum machine_mode mode;
199: {
200: return reg_renumber && FP_REG_P (op);
201: }
202:
203: extern int current_function_uses_pic_offset_table;
204: extern rtx force_reg (), validize_mem ();
205:
206: /* The rtx for the global offset table which is a special form
207: that *is* a position independent symbolic constant. */
208: rtx pic_pc_rtx;
209:
210: /* Ensure that we are not using patterns that are not OK with PIC. */
211:
212: int
213: check_pic (i)
214: int i;
215: {
216: extern rtx recog_operand[];
217: switch (flag_pic)
218: {
219: case 1:
220: if (GET_CODE (recog_operand[i]) == SYMBOL_REF
221: || (GET_CODE (recog_operand[i]) == CONST
222: && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
223: abort ();
224: case 2:
225: default:
226: return 1;
227: }
228: }
229:
230: /* Return truth value of whether OP is EQ or NE. */
231:
232: int
233: eq_or_neq (op, mode)
234: rtx op;
235: enum machine_mode mode;
236: {
237: return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
238: }
239:
240: /* Return truth value of whether OP can be used as an operands in a three
241: address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */
242:
243: int
244: arith_operand (op, mode)
245: rtx op;
246: enum machine_mode mode;
247: {
248: return (register_operand (op, mode)
249: || (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));
250: }
251:
252: int
253: arith_double_operand (op, mode)
254: rtx op;
255: enum machine_mode mode;
256: {
257: return (register_operand (op, mode)
258: || (GET_CODE (op) == CONST_DOUBLE
259: && GET_MODE (op) == mode
260: && VAL_14_BITS_P (CONST_DOUBLE_LOW (op))
261: && (CONST_DOUBLE_HIGH (op) >= 0
262: == ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
263: }
264:
265: /* Return truth value of whether OP is a integer which fits the
266: range constraining immediate operands in three-address insns. */
267:
268: int
269: int5_operand (op, mode)
270: rtx op;
271: enum machine_mode mode;
272: {
273: return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));
274: }
275:
276: int
277: uint5_operand (op, mode)
278: rtx op;
279: enum machine_mode mode;
280: {
281: return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));
282: }
283:
284:
285: int
286: int11_operand (op, mode)
287: rtx op;
288: enum machine_mode mode;
289: {
290: return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));
291: }
292:
293: int
294: arith5_operand (op, mode)
295: rtx op;
296: enum machine_mode mode;
297: {
298: return register_operand (op, mode) || int5_operand (op, mode);
299: }
300:
301: /* Return truth value of statement that OP is a call-clobbered register. */
302: int
303: clobbered_register (op, mode)
304: rtx op;
305: enum machine_mode mode;
306: {
307: return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
308: }
309:
310: /* Legitimize PIC addresses. If the address is already
311: position-independent, we return ORIG. Newly generated
312: position-independent addresses go to REG. If we need more
313: than one register, we lose. */
314:
315: rtx
316: legitimize_pic_address (orig, mode, reg)
317: rtx orig, reg;
318: enum machine_mode mode;
319: {
320: rtx pic_ref = orig;
321:
322: if (GET_CODE (orig) == SYMBOL_REF)
323: {
324: if (reg == 0)
325: abort ();
326:
327: if (flag_pic == 2)
328: {
329: emit_insn (gen_rtx (SET, VOIDmode, reg,
330: gen_rtx (HIGH, Pmode, orig)));
331: emit_insn (gen_rtx (SET, VOIDmode, reg,
332: gen_rtx (LO_SUM, Pmode, reg, orig)));
333: orig = reg;
334: }
335: pic_ref = gen_rtx (MEM, Pmode,
336: gen_rtx (PLUS, Pmode,
337: pic_offset_table_rtx, orig));
338: current_function_uses_pic_offset_table = 1;
339: RTX_UNCHANGING_P (pic_ref) = 1;
340: emit_move_insn (reg, pic_ref);
341: return reg;
342: }
343: else if (GET_CODE (orig) == CONST)
344: {
345: rtx base, offset;
346:
347: if (GET_CODE (XEXP (orig, 0)) == PLUS
348: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
349: return orig;
350:
351: if (reg == 0)
352: abort ();
353:
354: if (GET_CODE (XEXP (orig, 0)) == PLUS)
355: {
356: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
357: orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
358: base == reg ? 0 : reg);
359: }
360: else abort ();
361: if (GET_CODE (orig) == CONST_INT)
362: {
363: if (SMALL_INT (orig))
364: return plus_constant_for_output (base, INTVAL (orig));
365: orig = force_reg (Pmode, orig);
366: }
367: pic_ref = gen_rtx (PLUS, Pmode, base, orig);
368: /* Likewise, should we set special REG_NOTEs here? */
369: }
370: return pic_ref;
371: }
372:
373: /* Set up PIC-specific rtl. This should not cause any insns
374: to be emitted. */
375:
376: void
377: initialize_pic ()
378: {
379: }
380:
381: /* Emit special PIC prologues and epilogues. */
382:
383: void
384: finalize_pic ()
385: {
386: /* The table we use to reference PIC data. */
387: rtx global_offset_table;
388: /* Labels to get the PC in the prologue of this function. */
389: rtx l1, l2;
390: rtx seq;
391: int orig_flag_pic = flag_pic;
392:
393: if (current_function_uses_pic_offset_table == 0)
394: return;
395:
396: if (! flag_pic)
397: abort ();
398:
399: flag_pic = 0;
400: l1 = gen_label_rtx ();
401: l2 = gen_label_rtx ();
402:
403: start_sequence ();
404:
405: emit_label (l1);
406: /* Note that we pun calls and jumps here! */
407: emit_jump_insn (gen_rtx (PARALLEL, VOIDmode,
408: gen_rtvec (2,
409: gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)),
410: gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2)))));
411: emit_label (l2);
412:
413: /* Initialize every time through, since we can't easily
414: know this to be permanent. */
415: global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "*__GLOBAL_OFFSET_TABLE_");
416: pic_pc_rtx = gen_rtx (CONST, Pmode,
417: gen_rtx (MINUS, Pmode,
418: global_offset_table,
419: gen_rtx (CONST, Pmode,
420: gen_rtx (MINUS, Pmode,
421: gen_rtx (LABEL_REF, VOIDmode, l1),
422: pc_rtx))));
423:
424: emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
425: gen_rtx (HIGH, Pmode, pic_pc_rtx)));
426: emit_insn (gen_rtx (SET, VOIDmode,
427: pic_offset_table_rtx,
428: gen_rtx (LO_SUM, Pmode,
429: pic_offset_table_rtx, pic_pc_rtx)));
430: emit_insn (gen_rtx (SET, VOIDmode,
431: pic_offset_table_rtx,
432: gen_rtx (PLUS, SImode,
433: pic_offset_table_rtx, gen_rtx (REG, SImode, 15))));
434: /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */
435: LABEL_PRESERVE_P (l1) = 1;
436: LABEL_PRESERVE_P (l2) = 1;
437: flag_pic = orig_flag_pic;
438:
439: seq = gen_sequence ();
440: end_sequence ();
441: emit_insn_after (seq, get_insns ());
442:
443: /* Need to emit this whether or not we obey regdecls,
444: since setjmp/longjmp can cause life info to screw up. */
445: emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
446: }
447:
448: /* For the HPPA, REG and REG+CONST is cost 0
449: and addresses involving symbolic constants are cost 2.
450:
451: PIC addresses are very expensive.
452:
453: It is no coincidence that this has the same structure
454: as GO_IF_LEGITIMATE_ADDRESS. */
455: int
456: hppa_address_cost (X)
457: rtx X;
458: {
459: if (GET_CODE (X) == PLUS)
460: return 1;
461: else if (GET_CODE (X) == LO_SUM)
462: return 1;
463: else if (GET_CODE (X) == HIGH)
464: return 2;
465: return 4;
466: }
467:
468: /* Emit insns to move operands[1] into operands[0].
469:
470: Return 1 if we have written out everything that needs to be done to
471: do the move. Otherwise, return 0 and the caller will emit the move
472: normally. */
473:
474: int
475: emit_move_sequence (operands, mode)
476: rtx *operands;
477: enum machine_mode mode;
478: {
479: register rtx operand0 = operands[0];
480: register rtx operand1 = operands[1];
481:
482: /* Handle most common case first: storing into a register. */
483: if (register_operand (operand0, mode))
484: {
485: if (register_operand (operand1, mode)
486: || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
487: || (GET_CODE (operand1) == HIGH
488: && !symbolic_operand (XEXP (operand1, 0)))
489: /* Only `general_operands' can come here, so MEM is ok. */
490: || GET_CODE (operand1) == MEM)
491: {
492: /* Run this case quickly. */
493: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
494: return 1;
495: }
496: }
497: else if (GET_CODE (operand0) == MEM)
498: {
499: if (register_operand (operand1, mode) || operand1 == const0_rtx)
500: {
501: /* Run this case quickly. */
502: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
503: return 1;
504: }
505: if (! reload_in_progress)
506: {
507: operands[0] = validize_mem (operand0);
508: operands[1] = operand1 = force_reg (mode, operand1);
509: }
510: }
511:
512: /* Simplify the source if we need to. */
513: #if 0
514: if (GET_CODE (operand1) == HIGH
515: && symbolic_operand (XEXP (operand1, 0), mode)
516: && !read_only_operand (XEXP (operand1, 0)))
517: {
518: rtx temp = reload_in_progress ? operand0 : gen_reg_rtx(mode);
519:
520: emit_insn (gen_rtx (SET, VOIDmode, temp, operand1));
521: emit_insn (gen_rtx (SET, VOIDmode,
522: operand0,
523: gen_rtx (PLUS, mode,
524: temp, gen_rtx (REG, mode, 27))));
525: return 1;
526: }
527: #endif
528: if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
529: {
530: if (symbolic_operand (operand1, mode))
531: {
532: if (flag_pic)
533: {
534: rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (Pmode);
535: operands[1] = legitimize_pic_address (operand1, mode, temp);
536: }
537: /* On the HPPA, references to data space are supposed to */
538: /* use dp, register 27. */
539: else if (read_only_operand (operand1))
540: {
541: emit_insn (gen_rtx (SET, VOIDmode,
542: operand0,
543: gen_rtx (HIGH, mode, operand1)));
544: emit_insn (gen_rtx (SET, VOIDmode,
545: operand0,
546: gen_rtx (LO_SUM, mode, operand0, operand1)));
547: return 1;
548: }
549: else
550: {
551: /* If reload_in_progress, we can't use addil and r1; we */
552: /* have to use the more expensive ldil sequence. */
553: if (reload_in_progress)
554: {
555: emit_insn (gen_rtx (SET, VOIDmode,
556: operand0,
557: gen_rtx (HIGH, mode, operand1)));
558: emit_insn (gen_rtx (SET, VOIDmode,
559: operand0,
560: gen_rtx (PLUS, mode,
561: operand0,
562: gen_rtx (REG, mode, 27))));
563: emit_insn (gen_rtx (SET, VOIDmode,
564: operand0,
565: gen_rtx (LO_SUM, mode,
566: operand0, operand1)));
567: }
568: else
569: {
570: rtx temp1 = gen_reg_rtx (mode), temp2 = gen_reg_rtx (mode);
571:
572: emit_insn (gen_rtx (SET, VOIDmode,
573: temp1, gen_rtx (HIGH, mode, operand1)));
574: emit_insn (gen_rtx (SET, VOIDmode,
575: temp2,
576: gen_rtx (PLUS, mode,
577: gen_rtx (REG, mode, 27),
578: temp1)));
579: emit_insn (gen_rtx (SET, VOIDmode,
580: operand0,
581: gen_rtx (LO_SUM, mode,
582: temp2, operand1)));
583: }
584: return 1;
585: }
586: }
587: else if (GET_CODE (operand1) == CONST_INT
588: ? (! SMALL_INT (operand1)
589: && (INTVAL (operand1) & 0x7ff) != 0) : 1)
590: {
591: rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (mode);
592: emit_insn (gen_rtx (SET, VOIDmode, temp,
593: gen_rtx (HIGH, mode, operand1)));
594: operands[1] = gen_rtx (LO_SUM, mode, temp, operand1);
595: }
596: }
597: /* Now have insn-emit do whatever it normally does. */
598: return 0;
599: }
600:
601: /* Does operand (which is a symbolic_operand) live in text space? If
602: so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true.*/
603:
604: int
605: read_only_operand (operand)
606: rtx operand;
607: {
608: if (GET_CODE (operand) == CONST)
609: operand = XEXP (XEXP (operand, 0), 0);
610: if (GET_CODE (operand) == SYMBOL_REF)
611: return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
612: return 1;
613: }
614:
615:
616: /* Return the best assembler insn template
617: for moving operands[1] into operands[0] as a fullword. */
618:
619: static char *
620: singlemove_string (operands)
621: rtx *operands;
622: {
623: if (GET_CODE (operands[0]) == MEM)
624: return "stw %r1,%0";
625: if (GET_CODE (operands[1]) == MEM)
626: return "ldw %1,%0";
627: if (GET_CODE (operands[1]) == CONST_INT)
628: if (INT_14_BITS (operands[1]))
629: return (INTVAL (operands[1]) == 0 ? "copy 0,%0" : "ldi %1,%0");
630: else
631: return "ldil L'%1,%0\n\tldo R'%1(%0),%0";
632: return "copy %1,%0";
633: }
634:
635:
636: /* Output assembler code to perform a doubleword move insn
637: with operands OPERANDS. */
638:
639: char *
640: output_move_double (operands)
641: rtx *operands;
642: {
643: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
644: rtx latehalf[2];
645: rtx addreg0 = 0, addreg1 = 0;
646:
647: /* First classify both operands. */
648:
649: if (REG_P (operands[0]))
650: optype0 = REGOP;
651: else if (offsettable_memref_p (operands[0]))
652: optype0 = OFFSOP;
653: else if (GET_CODE (operands[0]) == MEM)
654: optype0 = MEMOP;
655: else
656: optype0 = RNDOP;
657:
658: if (REG_P (operands[1]))
659: optype1 = REGOP;
660: else if (CONSTANT_P (operands[1])
661: || GET_CODE (operands[1]) == CONST_DOUBLE)
662: optype1 = CNSTOP;
663: else if (offsettable_memref_p (operands[1]))
664: optype1 = OFFSOP;
665: else if (GET_CODE (operands[1]) == MEM)
666: optype1 = MEMOP;
667: else
668: optype1 = RNDOP;
669:
670: /* Check for the cases that the operand constraints are not
671: supposed to allow to happen. Abort if we get one,
672: because generating code for these cases is painful. */
673:
674: if (optype0 == RNDOP || optype1 == RNDOP)
675: abort ();
676:
677: /* If an operand is an unoffsettable memory ref, find a register
678: we can increment temporarily to make it refer to the second word. */
679:
680: if (optype0 == MEMOP)
681: addreg0 = find_addr_reg (operands[0]);
682:
683: if (optype1 == MEMOP)
684: addreg1 = find_addr_reg (operands[1]);
685:
686: /* Ok, we can do one word at a time.
687: Normally we do the low-numbered word first,
688: but if either operand is autodecrementing then we
689: do the high-numbered word first.
690:
691: In either case, set up in LATEHALF the operands to use
692: for the high-numbered word and in some cases alter the
693: operands in OPERANDS to be suitable for the low-numbered word. */
694:
695: if (optype0 == REGOP)
696: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
697: else if (optype0 == OFFSOP)
698: latehalf[0] = adj_offsettable_operand (operands[0], 4);
699: else
700: latehalf[0] = operands[0];
701:
702: if (optype1 == REGOP)
703: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
704: else if (optype1 == OFFSOP)
705: latehalf[1] = adj_offsettable_operand (operands[1], 4);
706: else if (optype1 == CNSTOP)
707: {
708: if (CONSTANT_P (operands[1]))
709: latehalf[1] = const0_rtx;
710: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
711: {
712: latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
713: XINT (operands[1], 1));
714: operands[1] = gen_rtx (CONST_INT, VOIDmode,
715: XINT (operands[1], 0));
716: }
717: }
718: else
719: latehalf[1] = operands[1];
720:
721: /* If the first move would clobber the source of the second one,
722: do them in the other order.
723:
724: RMS says "This happens only for registers;
725: such overlap can't happen in memory unless the user explicitly
726: sets it up, and that is an undefined circumstance."
727:
728: but it happens on the sparc when loading parameter registers,
729: so I am going to define that circumstance, and make it work
730: as expected. */
731:
732: if (optype0 == REGOP && (optype1 == MEMOP || optype1 == OFFSOP)
733: && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
734: {
735: /* XXX THIS PROBABLY DOESN'T WORK. */
736: /* Do the late half first. */
737: if (addreg1)
738: output_asm_insn ("addi 4,%0", &addreg1);
739: output_asm_insn (singlemove_string (latehalf), latehalf);
740: if (addreg1)
741: output_asm_insn ("addi -4,%0", &addreg1);
742: /* Then clobber. */
743: return singlemove_string (operands);
744: }
745:
746: /* Normal case: do the two words, low-numbered first. */
747:
748: output_asm_insn (singlemove_string (operands), operands);
749:
750: /* Make any unoffsettable addresses point at high-numbered word. */
751: if (addreg0)
752: output_asm_insn ("addi 4,%0", &addreg0);
753: if (addreg1)
754: output_asm_insn ("addi 4,%0", &addreg1);
755:
756: /* Do that word. */
757: output_asm_insn (singlemove_string (latehalf), latehalf);
758:
759: /* Undo the adds we just did. */
760: if (addreg0)
761: output_asm_insn ("addi -4,%0", &addreg0);
762: if (addreg1)
763: output_asm_insn ("addi -4,%0", &addreg1);
764:
765: return "";
766: }
767:
768: char *
769: output_fp_move_double (operands)
770: rtx *operands;
771: {
772: if (FP_REG_P (operands[0]))
773: {
774: if (FP_REG_P (operands[1]))
775: output_asm_insn ("fcpy,dbl %1,%0", operands);
776: else if (GET_CODE (operands[1]) == REG)
777: {
778: rtx xoperands[3];
779: xoperands[0] = operands[0];
780: xoperands[1] = operands[1];
781: xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
782: output_asm_insn
783: ("stw %1,-16(0,30)\n\tstw %2,-12(0,30)\n\tfldds -16(0,30),%0",
784: xoperands);
785: }
786: else
787: output_asm_insn ("fldds%F1 %1,%0", operands);
788: }
789: else if (FP_REG_P (operands[1]))
790: {
791: if (GET_CODE (operands[0]) == REG)
792: {
793: rtx xoperands[3];
794: xoperands[2] = operands[1];
795: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
796: xoperands[0] = operands[0];
797: output_asm_insn
798: ("fstds %2,-16(0,30)\n\tldw -12(0,30),%1\n\tldw -16(0,30),%0",
799: xoperands);
800: }
801: else
802: output_asm_insn ("fstds%F0 %1,%0", operands);
803: }
804: else abort ();
805: return "";
806: }
807:
808: /* Return a REG that occurs in ADDR with coefficient 1.
809: ADDR can be effectively incremented by incrementing REG. */
810:
811: static rtx
812: find_addr_reg (addr)
813: rtx addr;
814: {
815: while (GET_CODE (addr) == PLUS)
816: {
817: if (GET_CODE (XEXP (addr, 0)) == REG)
818: addr = XEXP (addr, 0);
819: else if (GET_CODE (XEXP (addr, 1)) == REG)
820: addr = XEXP (addr, 1);
821: else if (CONSTANT_P (XEXP (addr, 0)))
822: addr = XEXP (addr, 1);
823: else if (CONSTANT_P (XEXP (addr, 1)))
824: addr = XEXP (addr, 0);
825: else
826: abort ();
827: }
828: if (GET_CODE (addr) == REG)
829: return addr;
830: abort ();
831: }
832:
833: /* Load the address specified by OPERANDS[3] into the register
834: specified by OPERANDS[0].
835:
836: OPERANDS[3] may be the result of a sum, hence it could either be:
837:
838: (1) CONST
839: (2) REG
840: (2) REG + CONST_INT
841: (3) REG + REG + CONST_INT
842: (4) REG + REG (special case of 3).
843:
844: Note that (3) is not a legitimate address.
845: All cases are handled here. */
846:
847: void
848: output_load_address (operands)
849: rtx *operands;
850: {
851: rtx base, offset;
852:
853: if (CONSTANT_P (operands[3]))
854: {
855: output_asm_insn ("ldi %3,%0", operands);
856: return;
857: }
858:
859: if (REG_P (operands[3]))
860: {
861: if (REGNO (operands[0]) != REGNO (operands[3]))
862: output_asm_insn ("copy %3,%0", operands);
863: return;
864: }
865:
866: if (GET_CODE (operands[3]) != PLUS)
867: abort ();
868:
869: base = XEXP (operands[3], 0);
870: offset = XEXP (operands[3], 1);
871:
872: if (GET_CODE (base) == CONST_INT)
873: {
874: rtx tmp = base;
875: base = offset;
876: offset = tmp;
877: }
878:
879: if (GET_CODE (offset) != CONST_INT)
880: {
881: /* Operand is (PLUS (REG) (REG)). */
882: base = operands[3];
883: offset = const0_rtx;
884: }
885:
886: if (REG_P (base))
887: {
888: operands[6] = base;
889: operands[7] = offset;
890: if (INT_14_BITS (offset))
891: output_asm_insn ("ldo %7(%6),%0", operands);
892: else
893: output_asm_insn ("addil L'%7,%6\n\tldo R'%7(1),%0", operands);
894: }
895: else if (GET_CODE (base) == PLUS)
896: {
897: operands[6] = XEXP (base, 0);
898: operands[7] = XEXP (base, 1);
899: operands[8] = offset;
900:
901: if (offset == const0_rtx)
902: output_asm_insn ("add %6,%7,%0", operands);
903: else if (INT_14_BITS (offset))
904: output_asm_insn ("add %6,%7,%0\n\taddi %8,%0", operands);
905: else
906: output_asm_insn ("addil L'%8,%6\n\tldo R'%8(1),%0\n\tadd %0,%7,%0", operands);
907: }
908: else
909: abort ();
910: }
911:
912: /* Output code to place a size count SIZE in register REG.
913: ALIGN is the size of the unit of transfer.
914:
915: Because block moves are pipelined, we don't include the
916: first element in the transfer of SIZE to REG. */
917:
918: static void
919: output_size_for_block_move (size, reg, align)
920: rtx size, reg;
921: rtx align;
922: {
923: rtx xoperands[3];
924:
925: xoperands[0] = reg;
926: xoperands[1] = size;
927: xoperands[2] = align;
928: if (GET_CODE (size) == REG)
929: output_asm_insn ("ldo -%2(%1),%0", xoperands);
930: else
931: {
932: xoperands[1]
933: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
934: if (INT_14_BITS (xoperands[1]))
935: output_asm_insn ("ldi %1,%0", xoperands);
936: else
937: output_asm_insn ("addil L'%1,0\n\tldo R'%1(1),%0", xoperands);
938: }
939: }
940:
941: /* Emit code to perform a block move.
942:
943: OPERANDS[0] is the destination.
944: OPERANDS[1] is the source.
945: OPERANDS[2] is the size.
946: OPERANDS[3] is the alignment safe to use.
947: OPERANDS[4] is a register we can safely clobber as a temp. */
948:
949: char *
950: output_block_move (operands)
951: rtx *operands;
952: {
953: /* A vector for our computed operands. Note that load_output_address
954: makes use of (and can clobber) up to the 8th element of this vector. */
955: rtx xoperands[10];
956: rtx zoperands[10];
957: static int movstrsi_label = 0;
958: int i, j;
959: rtx temp1 = operands[4];
960: rtx alignrtx = operands[3];
961: int align = INTVAL (alignrtx);
962:
963: xoperands[0] = operands[0];
964: xoperands[1] = operands[1];
965: xoperands[2] = temp1;
966:
967: /* We can't move more than four bytes at a time
968: because we have only one register to move them through. */
969: if (align > 4)
970: {
971: align = 4;
972: alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
973: }
974:
975: /* Since we clobber untold things, nix the condition codes. */
976:
977: /* Recognize special cases of block moves. These occur
978: when GNU C++ is forced to treat something as BLKmode
979: to keep it in memory, when its mode could be represented
980: with something smaller.
981:
982: We cannot do this for global variables, since we don't know
983: what pages they don't cross. Sigh. */
984: if (GET_CODE (operands[2]) == CONST_INT
985: && INTVAL (operands[2]) <= 8
986: && ! CONSTANT_ADDRESS_P (operands[0])
987: && ! CONSTANT_ADDRESS_P (operands[1]))
988: {
989: int size = INTVAL (operands[2]);
990:
991: if (align == 1)
992: {
993: if (memory_address_p (QImode, plus_constant (xoperands[0], size))
994: && memory_address_p (QImode, plus_constant (xoperands[1], size)))
995: {
996: /* We will store different integers into xoperands[2]. */
997:
998: for (i = 0; i <= size-1; i++)
999: {
1000: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, i);
1001: output_asm_insn ("ldbs %2(%1),1\n\tstbs,ma 1,1(0,%0)",
1002: xoperands);
1003: }
1004: return "";
1005: }
1006: }
1007: else if (align == 2)
1008: {
1009: if (memory_address_p (HImode, plus_constant (xoperands[0], size))
1010: && memory_address_p (HImode, plus_constant (xoperands[1], size)))
1011: {
1012: for (i = 0 ; i <= (size>>1)-1; i++)
1013: {
1014: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, i << 1);
1015: output_asm_insn ("ldhs %2(%1),1\n\tsths,ma 1,2(0,%0)",
1016: xoperands);
1017: }
1018: return "";
1019: }
1020: }
1021: else
1022: {
1023: if (memory_address_p (SImode, plus_constant (xoperands[0], size))
1024: && memory_address_p (SImode, plus_constant (xoperands[1], size)))
1025: {
1026: for (i = 0; i <= (size>>2)-1; i++)
1027: {
1028: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, i << 2);
1029: output_asm_insn ("ldws %2(%1),1\n\tstws,ma 1,4(0,%0)",
1030: xoperands);
1031: }
1032: return "";
1033: }
1034: }
1035: }
1036:
1037: /* This is the size of the transfer.
1038: Either use the register which already contains the size,
1039: or use a free register (used by no operands).
1040: Also emit code to decrement the size value by ALIGN. */
1041: output_size_for_block_move (operands[2], temp1, alignrtx);
1042:
1043: zoperands[0] = operands[0];
1044: zoperands[3] = gen_rtx (PLUS, SImode, operands[0], temp1);
1045: output_load_address (zoperands);
1046:
1047: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1048: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
1049:
1050: if (align == 1)
1051: output_asm_insn ("\nLm%3\n\tldbx %2(%1),1\n\taddib,>= %4,%2,Lm%3\n\tstbs,ma 1,%4(0,%0)", xoperands);
1052: else if (align == 2)
1053: output_asm_insn ("\nLm%3\n\tldhx %2(%1),1\n\taddib,>= %4,%2,Lm%3\n\tsths,ma 1,%4(0,%0)", xoperands);
1054: else
1055: output_asm_insn ("\nLm%3\n\tldwx %2(%1),1\n\taddib,>= %4,%2,Lm%3\n\tstws,ma 1,%4(0,%0)", xoperands);
1056: return "";
1057: }
1058:
1059:
1060: /* Output an ascii string. */
1061: output_ascii (file, p, size)
1062: FILE *file;
1063: unsigned char *p;
1064: int size;
1065: {
1066: int i;
1067: int chars_output;
1068: unsigned char partial_output[16]; /* Max space 4 chars can occupy. */
1069:
1070: /* The HP assember can only take strings of 256 characters at one
1071: time. This is a limitation on input line length, *not* the
1072: length of the string. Sigh. Even worse, it seems that the
1073: restricition is in number of input characters (see \xnn &
1074: \whatever). So we have to do this very carefully. */
1075:
1076: fprintf (file, "\t.STRING \"");
1077:
1078: chars_output = 0;
1079: for (i = 0; i < size; i += 4)
1080: {
1081: int co = 0;
1082: int io = 0;
1083: for (io = 0, co = 0; io < MIN (4, size - i); io++)
1084: {
1085: register unsigned int c = p[i + io];
1086:
1087: if (c == '\"' || c == '\\')
1088: partial_output[co++] = '\\';
1089: if (c >= ' ' && c < 0177)
1090: partial_output[co++] = c;
1091: else
1092: {
1093: unsigned int hexd;
1094: partial_output[co++] = '\\';
1095: partial_output[co++] = 'x';
1096: hexd = c / 16 - 0 + '0';
1097: if (hexd > '9')
1098: hexd -= '9' - 'a' + 1;
1099: partial_output[co++] = hexd;
1100: hexd = c % 16 - 0 + '0';
1101: if (hexd > '9')
1102: hexd -= '9' - 'a' + 1;
1103: partial_output[co++] = hexd;
1104: }
1105: }
1106: if (chars_output + co > 243)
1107: {
1108: fprintf (file, "\"\n\t.STRING \"");
1109: chars_output = 0;
1110: }
1111: fwrite (partial_output, 1, co, file);
1112: chars_output += co;
1113: co = 0;
1114: }
1115: fprintf (file, "\"\n");
1116: }
1117:
1118: /* You may have trouble believing this, but this is the HP825 stack
1119: layout. Wow.
1120:
1121: Offset Contents
1122:
1123: Variable arguments (optional; any number may be allocated)
1124:
1125: SP-(4*(N+9)) arg word N
1126: : :
1127: SP-56 arg word 5
1128: SP-52 arg word 4
1129:
1130: Fixed arguments (must be allocated; may remain unused)
1131:
1132: SP-48 arg word 3
1133: SP-44 arg word 2
1134: SP-40 arg word 1
1135: SP-36 arg word 0
1136:
1137: Frame Marker
1138:
1139: SP-32 External Data Pointer (DP)
1140: SP-28 External sr4
1141: SP-24 External/stub RP (RP')
1142: SP-20 Current RP
1143: SP-16 Static Link
1144: SP-12 Clean up
1145: SP-8 Calling Stub RP (RP'')
1146: SP-4 Previous SP
1147:
1148: Top of Frame
1149:
1150: SP-0 Stack Pointer (points to next available address)
1151:
1152: */
1153:
1154: /* This function saves registers as follows. Registers marked with ' are
1155: this function's registers (as opposed to the previous function's).
1156: If a frame_pointer isn't needed, r4 is saved as a general register;
1157: the space for the frame pointer is still allocated, though, to keep
1158: things simple.
1159:
1160:
1161: Top of Frame
1162:
1163: SP (FP') Previous FP
1164: SP + 4 Alignment filler (sigh)
1165: SP + 8 Space for locals reserved here.
1166: .
1167: .
1168: .
1169: SP + n All call saved register used.
1170: .
1171: .
1172: .
1173: SP + o All call saved fp registers used.
1174: .
1175: .
1176: .
1177: SP + p (SP') points to next avaliable address.
1178:
1179: */
1180:
1181: /* Helper functions */
1182: void
1183: print_stw (file, r, disp, base)
1184: FILE *file;
1185: int r, disp, base;
1186: {
1187: if (VAL_14_BITS_P (disp))
1188: fprintf (file, "\tstw %d,%d(0,%d)\n", r, disp, base);
1189: else
1190: fprintf (file, "\taddil L'%d,%d\n\tstw %d,R'%d(0,1)\n", disp, base,
1191: r, disp);
1192: }
1193:
1194: void
1195: print_ldw (file, r, disp, base)
1196: FILE *file;
1197: int r, disp, base;
1198: {
1199: if (VAL_14_BITS_P (disp))
1200: fprintf (file, "\tldw %d(0,%d),%d\n", disp, base, r);
1201: else
1202: fprintf (file, "\taddil L'%d,%d\n\tldw R'%d(0,1),%d\n", disp, base,
1203: disp, r);
1204: }
1205:
1206: /* Set by the FUNCTION_PROFILER macro. */
1207: int hp_profile_labelno;
1208: extern int profile_flag;
1209:
1210: int local_fsize, save_fregs, actual_fsize;
1211:
1212: int
1213: compute_frame_size (size, leaf_function)
1214: int size;
1215: int leaf_function;
1216: {
1217: extern int current_function_outgoing_args_size;
1218: int i;
1219:
1220: /* 8 is space for frame pointer + filler */
1221: local_fsize = actual_fsize = size + 8;
1222:
1223: /* fp is stored in a special place. */
1224: for (i = 18; i >= 5; i--)
1225: if (regs_ever_live[i])
1226: actual_fsize += 4;
1227:
1228: if (regs_ever_live[3])
1229: actual_fsize += 4;
1230: actual_fsize = (actual_fsize + 7) & ~7;
1231:
1232: if (!TARGET_SNAKE)
1233: {
1234: for (i = 47; i >= 44; i--)
1235: if (regs_ever_live[i])
1236: {
1237: actual_fsize += 8; save_fregs++;
1238: }
1239: }
1240: else
1241: {
1242: for (i = 90; i >= 72; i -= 2)
1243: if (regs_ever_live[i] || regs_ever_live[i + 1])
1244: {
1245: actual_fsize += 8; save_fregs++;
1246: }
1247: }
1248: return actual_fsize + current_function_outgoing_args_size;
1249: }
1250:
1251: void
1252: output_function_prologue (file, size, leaf_function)
1253: FILE *file;
1254: int size;
1255: int leaf_function;
1256: {
1257: extern char call_used_regs[];
1258: extern int frame_pointer_needed;
1259: int i, offset;
1260:
1261: actual_fsize = compute_frame_size (size, leaf_function) + 32;
1262: /* Let's not try to bullshit more than we need to here. */
1263: /* This might be right a lot of the time */
1264: fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=%d", actual_fsize);
1265: if (regs_ever_live[2])
1266: fprintf (file, ",CALLS,SAVE_RP\n");
1267: else
1268: fprintf (file, ",NO_CALLS\n");
1269: fprintf (file, "\t.ENTRY\n");
1270:
1271: /* Instead of taking one argument, the counter label, as most normal
1272: mcounts do, _mcount appears to behave differently on the HPPA. It
1273: takes the return address of the caller, the address of this
1274: routine, and the address of the label. Also, it isn't magic, so
1275: caller saves have to be preserved. We get around this by calling
1276: our own gcc_mcount, which takes arguments on the stack and saves
1277: argument registers. */
1278:
1279: if (profile_flag)
1280: {
1281: fprintf (file,"\tstw 2,-20(30)\n\tldo 48(30),30\n\
1282: \taddil L'LP$%04d-$global$,27\n\tldo R'LP$%04d-$global$(1),1\n\
1283: \tbl __gcc_mcount,2\n\tstw 1,-16(30)\n\tldo -48(30),30\n\tldw -20(30),2\n",
1284: hp_profile_labelno, hp_profile_labelno);
1285: }
1286: /* Some registers have places to go in the current stack
1287: structure. */
1288:
1289: #if 0
1290: /* However, according to the hp docs, there's no need to save the
1291: sp. */
1292: fprintf (file, "\tstw 30,-4(30)\n");
1293: #endif
1294:
1295: if (regs_ever_live[2])
1296: fprintf (file, "\tstw 2,-20(0,30)\n");
1297:
1298: /* Reserve space for local variables. */
1299: if (frame_pointer_needed)
1300: {
1301: if (VAL_14_BITS_P (actual_fsize))
1302: fprintf (file, "\tcopy 4,1\n\tcopy 30,4\n\tstwm 1,%d(0,30)\n",
1303: actual_fsize);
1304: else
1305: {
1306: fprintf (file, "\tcopy 4,1\n\tcopy 30,4\n\tstw 1,0(0,4)\n");
1307: fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),30\n",
1308: actual_fsize, actual_fsize);
1309: }
1310: }
1311: else
1312: /* Used to be abort (); */
1313: {
1314: if (VAL_14_BITS_P (actual_fsize))
1315: fprintf (file, "\tldo %d(30),30\n", actual_fsize);
1316: else
1317: fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),30\n",
1318: actual_fsize, actual_fsize);
1319: }
1320:
1321: /* Normal register save. */
1322: if (frame_pointer_needed)
1323: {
1324: for (i = 18, offset = local_fsize; i >= 5; i--)
1325: if (regs_ever_live[i] && ! call_used_regs[i])
1326: {
1327: print_stw (file, i, offset, 4); offset += 4;
1328: }
1329: if (regs_ever_live[3] && ! call_used_regs[3])
1330: {
1331: print_stw (file, 3, offset, 4); offset += 4;
1332: }
1333: }
1334: else
1335: {
1336: for (i = 18, offset = local_fsize - actual_fsize; i >= 5; i--)
1337: if (regs_ever_live[i] && ! call_used_regs[i])
1338: {
1339: print_stw (file, i, offset, 30); offset += 4;
1340: }
1341: if (regs_ever_live[3] && ! call_used_regs[3])
1342: {
1343: print_stw (file, 3, offset, 30); offset += 4;
1344: }
1345: }
1346:
1347: /* Align pointer properly (doubleword boundary). */
1348: offset = (offset + 7) & ~7;
1349:
1350: /* Floating point register store. */
1351: if (save_fregs)
1352: if (frame_pointer_needed)
1353: if (VAL_14_BITS_P (offset))
1354: fprintf (file, "\tldo %d(4),1\n", offset);
1355: else
1356: fprintf (file, "\taddil L'%d,4\n\tldo R'%d(1),1\n", offset, offset);
1357: else
1358: if (VAL_14_BITS_P (offset))
1359: fprintf (file, "\tldo %d(30),1\n", offset);
1360: else
1361: fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),1\n", offset, offset);
1362: if (!TARGET_SNAKE)
1363: {
1364: for (i = 47; i >= 44; i--)
1365: {
1366: if (regs_ever_live[i])
1367: fprintf (file, "\tfstds,ma %s,8(0,1)\n", reg_names[i]);
1368: }
1369: }
1370: else
1371: {
1372: for (i = 90; i >= 72; i -= 2)
1373: if (regs_ever_live[i] || regs_ever_live[i + 1])
1374: {
1375: fprintf (file, "\tfstds,ma %s,8(0,1)\n", reg_names[i]);
1376: }
1377: }
1378: }
1379:
1380: void
1381: output_function_epilogue (file, size, leaf_function)
1382: FILE *file;
1383: int size;
1384: int leaf_function;
1385: {
1386: extern char call_used_regs[];
1387: extern int frame_pointer_needed;
1388: int i, offset;
1389:
1390: if (frame_pointer_needed)
1391: {
1392: for (i = 18, offset = local_fsize; i >= 5; i--)
1393: if (regs_ever_live[i] && ! call_used_regs[i])
1394: {
1395: print_ldw (file, i, offset, 4); offset += 4;
1396: }
1397: if (regs_ever_live[3] && ! call_used_regs[3])
1398: {
1399: print_ldw (file, 3, offset, 4); offset += 4;
1400: }
1401: }
1402: else
1403: {
1404: for (i = 18, offset = local_fsize - actual_fsize; i >= 5; i--)
1405: if (regs_ever_live[i] && ! call_used_regs[i])
1406: {
1407: print_ldw (file, i, offset, 30); offset += 4;
1408: }
1409: if (regs_ever_live[3] && ! call_used_regs[3])
1410: {
1411: print_ldw (file, 3, offset, 30); offset += 4;
1412: }
1413: }
1414:
1415: /* Align pointer properly (doubleword boundary). */
1416: offset = (offset + 7) & ~7;
1417:
1418: /* Floating point register restore. */
1419: if (save_fregs)
1420: if (frame_pointer_needed)
1421: if (VAL_14_BITS_P (offset))
1422: fprintf (file, "\tldo %d(4),1\n", offset);
1423: else
1424: fprintf (file, "\taddil L'%d,4\n\tldo R'%d(1),1\n", offset, offset);
1425: else
1426: if (VAL_14_BITS_P (offset))
1427: fprintf (file, "\tldo %d(30),1\n", offset);
1428: else
1429: fprintf (file, "\taddil L'%d,30\n\tldo R'%d(1),1\n", offset, offset);
1430: if (!TARGET_SNAKE)
1431: {
1432: for (i = 47; i >= 44; i--)
1433: {
1434: if (regs_ever_live[i])
1435: fprintf (file, "\tfldds,ma 8(0,1),%s\n", reg_names[i]);
1436: }
1437: }
1438: else
1439: {
1440: for (i = 90; i >= 72; i -= 2)
1441: if (regs_ever_live[i] || regs_ever_live[i + 1])
1442: {
1443: fprintf (file, "\tfldds,ma 8(0,1),%s\n", reg_names[i]);
1444: }
1445: }
1446: /* Reset stack pointer (and possibly frame pointer). The stack */
1447: /* pointer is initially set to fp + 8 to avoid a race condition. */
1448: if (frame_pointer_needed)
1449: {
1450: fprintf (file, "\tldo 8(4),30\n");
1451: if (regs_ever_live[2])
1452: fprintf (file, "\tldw -28(0,30),2\n");
1453: fprintf (file, "\tbv 0(2)\n\tldwm -8(30),4\n");
1454: }
1455: else if (actual_fsize)
1456: {
1457: if (regs_ever_live[2] && VAL_14_BITS_P (actual_fsize + 20))
1458: fprintf (file, "\tldw %d(30),2\n\tbv 0(2)\n\tldo %d(30),30\n",
1459: -(actual_fsize + 20), -actual_fsize);
1460: else if (regs_ever_live[2])
1461: fprintf (file,
1462: "\taddil L'%d,30\n\tldw %d(1),2\n\tbv 0(2)\n\tldo R'%d(1),30\n",
1463: - actual_fsize,
1464: - ((actual_fsize + 20) - (actual_fsize & ~0x7ff)),
1465: - actual_fsize);
1466: else if (VAL_14_BITS_P (actual_fsize))
1467: fprintf (file, "\tbv 0(2)\n\tldo %d(30),30\n", - actual_fsize);
1468: else
1469: fprintf (file, "\taddil L'%d,30\n\tbv 0(2)\n\tldo R'%d(1),30\n");
1470: }
1471: else if (current_function_epilogue_delay_list)
1472: {
1473: fprintf (file, "\tbv 0(2)\n");
1474: final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
1475: file, write_symbols, 1, 0, 1);
1476: }
1477: else
1478: fprintf (file, "\tbv,n 0(2)\n");
1479: fprintf (file, "\t.EXIT\n\t.PROCEND\n");
1480: }
1481:
1482: rtx
1483: gen_compare_reg (code, x, y)
1484: enum rtx_code code;
1485: rtx x, y;
1486: {
1487: enum machine_mode mode = SELECT_CC_MODE (code, x);
1488: rtx cc_reg = gen_rtx (REG, mode, 0);
1489:
1490: emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
1491: gen_rtx (COMPARE, mode, x, y)));
1492:
1493: return cc_reg;
1494: }
1495:
1496: /* Return nonzero if TRIAL can go into the function epilogue's
1497: delay slot. SLOT is the slot we are trying to fill. */
1498:
1499: int
1500: eligible_for_epilogue_delay (trial, slot)
1501: rtx trial;
1502: int slot;
1503: {
1504: if (slot >= 1)
1505: return 0;
1506: if (GET_CODE (trial) != INSN
1507: || GET_CODE (PATTERN (trial)) != SET)
1508: return 0;
1509: if (get_attr_length (trial) != 1)
1510: return 0;
1511: return (leaf_function &&
1512: get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_TRUE);
1513: }
1514:
1515: rtx
1516: gen_scond_fp (code, operand0)
1517: enum rtx_code code;
1518: rtx operand0;
1519: {
1520: return gen_rtx (SET, VOIDmode, operand0,
1521: gen_rtx (code, CCFPmode,
1522: gen_rtx (REG, CCFPmode, 0), const0_rtx));
1523: }
1524:
1525: void
1526: emit_bcond_fp (code, operand0)
1527: enum rtx_code code;
1528: rtx operand0;
1529: {
1530: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
1531: gen_rtx (IF_THEN_ELSE, VOIDmode,
1532: gen_rtx (code, VOIDmode,
1533: gen_rtx (REG, CCFPmode, 0),
1534: const0_rtx),
1535: gen_rtx (LABEL_REF, VOIDmode, operand0),
1536: pc_rtx)));
1537:
1538: }
1539:
1540: rtx
1541: gen_cmp_fp (code, operand0, operand1)
1542: enum rtx_code code;
1543: rtx operand0, operand1;
1544: {
1545: return gen_rtx (SET, VOIDmode, gen_rtx (REG, CCFPmode, 0),
1546: gen_rtx (code, CCFPmode, operand0, operand1));
1547: }
1548:
1549:
1550: /* Print operand X (an rtx) in assembler syntax to file FILE.
1551: CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1552: For `%' followed by punctuation, CODE is the punctuation and X is null. */
1553:
1554: void
1555: print_operand (file, x, code)
1556: FILE *file;
1557: rtx x;
1558: int code;
1559: {
1560: switch (code)
1561: {
1562: case '#':
1563: /* Output a 'nop' if there's nothing for the delay slot. */
1564: if (dbr_sequence_length () == 0)
1565: fputs ("\n\tnop", file);
1566: return;
1567: case '*':
1568: /* Output an nullification completer if there's nothing for the */
1569: /* delay slot or nullification is requested. */
1570: if (dbr_sequence_length () == 0 ||
1571: (final_sequence &&
1572: INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))))
1573: fputs (",n", file);
1574: return;
1575: case 'R':
1576: /* Print out the second register name of a register pair.
1577: I.e., R (6) => 7. */
1578: fputs (reg_names[REGNO (x)+1], file);
1579: return;
1580: case 'r':
1581: /* A register or zero. */
1582: if (x == const0_rtx)
1583: {
1584: fputs ("0", file);
1585: return;
1586: }
1587: else
1588: break;
1589: case 'O':
1590: switch (GET_CODE (x))
1591: {
1592: case PLUS:
1593: fprintf (file, "add%s",
1594: GET_CODE (XEXP (x, 1)) == CONST_INT ? "i" : ""); break;
1595: case MINUS:
1596: fprintf (file, "sub%s",
1597: GET_CODE (XEXP (x, 0)) == CONST_INT ? "i" : ""); break;
1598: case AND:
1599: fprintf (file, "and%s",
1600: GET_CODE (XEXP (x, 1)) == NOT ? "cm" : ""); break;
1601: case IOR:
1602: fprintf (file, "or"); break;
1603: case XOR:
1604: fprintf (file, "xor"); break;
1605: case ASHIFT:
1606: fprintf (file, "sh%dadd", INTVAL (XEXP (x, 1))); break;
1607: /* Too lazy to handle bitfield conditions yet. */
1608: default:
1609: printf ("Can't grok '%c' operator:\n", code);
1610: debug_rtx (x);
1611: abort ();
1612: }
1613: return;
1614: case 'C':
1615: case 'X':
1616: switch (GET_CODE (x))
1617: {
1618: case EQ:
1619: fprintf (file, "="); break;
1620: case NE:
1621: if (code == 'C')
1622: fprintf (file, "<>");
1623: else
1624: fprintf (file, "!=");
1625: break;
1626: case GT:
1627: fprintf (file, ">"); break;
1628: case GE:
1629: fprintf (file, ">="); break;
1630: case GEU:
1631: fprintf (file, ">>="); break;
1632: case GTU:
1633: fprintf (file, ">>"); break;
1634: case LT:
1635: fprintf (file, "<"); break;
1636: case LE:
1637: fprintf (file, "<="); break;
1638: case LEU:
1639: fprintf (file, "<<="); break;
1640: case LTU:
1641: fprintf (file, "<<"); break;
1642: default:
1643: printf ("Can't grok '%c' operator:\n", code);
1644: debug_rtx (x);
1645: abort ();
1646: }
1647: return;
1648: case 'N':
1649: case 'Y':
1650: switch (GET_CODE (x))
1651: {
1652: case EQ:
1653: if (code == 'N')
1654: fprintf (file, "<>");
1655: else
1656: fprintf (file, "!=");
1657: break;
1658: case NE:
1659: fprintf (file, "="); break;
1660: case GT:
1661: fprintf (file, "<="); break;
1662: case GE:
1663: fprintf (file, "<"); break;
1664: case GEU:
1665: fprintf (file, "<<"); break;
1666: case GTU:
1667: fprintf (file, "<<="); break;
1668: case LT:
1669: fprintf (file, ">="); break;
1670: case LE:
1671: fprintf (file, ">"); break;
1672: case LEU:
1673: fprintf (file, ">>"); break;
1674: case LTU:
1675: fprintf (file, ">>="); break;
1676: default:
1677: printf ("Can't grok '%c' operator:\n", code);
1678: debug_rtx (x);
1679: abort ();
1680: }
1681: return;
1682: case 'M':
1683: switch (GET_CODE (XEXP (x, 0)))
1684: {
1685: case PRE_DEC:
1686: case PRE_INC:
1687: fprintf (file, "s,mb");
1688: break;
1689: case POST_DEC:
1690: case POST_INC:
1691: fprintf (file, "s,ma");
1692: break;
1693: default:
1694: break;
1695: }
1696: return;
1697: case 'F':
1698: switch (GET_CODE (XEXP (x, 0)))
1699: {
1700: case PRE_DEC:
1701: case PRE_INC:
1702: fprintf (file, ",mb");
1703: break;
1704: case POST_DEC:
1705: case POST_INC:
1706: fprintf (file, ",ma");
1707: break;
1708: default:
1709: break;
1710: }
1711: return;
1712: case 'G':
1713: output_global_address (file, x);
1714: return;
1715: case 0: /* Don't do anything special */
1716: break;
1717: default:
1718: abort ();
1719: }
1720: if (GET_CODE (x) == REG)
1721: fprintf (file, "%s", reg_names [REGNO (x)]);
1722: else if (GET_CODE (x) == MEM)
1723: {
1724: int size = GET_MODE_SIZE (GET_MODE (x));
1725: rtx base = XEXP (XEXP (x, 0), 0);
1726: switch (GET_CODE (XEXP (x, 0)))
1727: {
1728: case PRE_DEC:
1729: case POST_DEC:
1730: fprintf (file, "-%d(0,%s)", size, reg_names [REGNO (base)]);
1731: break;
1732: case PRE_INC:
1733: case POST_INC:
1734: fprintf (file, "%d(0,%s)", size, reg_names [REGNO (base)]);
1735: break;
1736: default:
1737: output_address (XEXP (x, 0));
1738: break;
1739: }
1740: }
1741: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
1742: {
1743: union { double d; int i[2]; } u;
1744: union { float f; int i; } u1;
1745: u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
1746: u1.f = u.d;
1747: if (code == 'f')
1748: fprintf (file, "0r%.9g", u1.f);
1749: else
1750: fprintf (file, "0x%x", u1.i);
1751: }
1752: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
1753: {
1754: union { double d; int i[2]; } u;
1755: u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
1756: fprintf (file, "0r%.20g", u.d);
1757: }
1758: else
1759: output_addr_const (file, x);
1760: }
1761:
1762: /* output a SYMBOL_REF or a CONST expression involving a SYMBOL_REF. */
1763:
1764: void
1765: output_global_address (file, x)
1766: FILE *file;
1767: rtx x;
1768: {
1769: if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x))
1770: assemble_name (file, XSTR (x, 0));
1771: else if (GET_CODE (x) == SYMBOL_REF)
1772: {
1773: assemble_name (file, XSTR (x, 0));
1774: fprintf (file, "-$global$");
1775: }
1776: else if (GET_CODE (x) == CONST)
1777: {
1778: char *sep = "";
1779: int offset = 0; /* assembler wants -$global$ at end */
1780: rtx base;
1781:
1782: if (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
1783: {
1784: base = XEXP (XEXP (x, 0), 0);
1785: output_addr_const (file, base);
1786: }
1787: else
1788: if (GET_CODE(XEXP (XEXP (x, 0), 0)) == CONST_INT)
1789: offset = INTVAL (XEXP (XEXP (x, 0), 0));
1790: else abort();
1791: if (GET_CODE (XEXP (XEXP (x, 0), 1)) == SYMBOL_REF)
1792: {
1793: base = XEXP (XEXP (x, 0), 1);
1794: output_addr_const (file, base);
1795: }
1796: else
1797: if (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
1798: offset = INTVAL (XEXP (XEXP (x, 0),1));
1799: else abort();
1800: if (GET_CODE (XEXP (x, 0)) == PLUS)
1801: sep= "+";
1802: else
1803: if (GET_CODE (XEXP (x, 0)) == MINUS
1804: && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
1805: sep = "-";
1806: else abort();
1807: if (!read_only_operand (base))
1808: fprintf (file, "-$global$");
1809: fprintf (file, "%s", sep);
1810: if (offset) fprintf(file,"%d", offset);
1811: }
1812: else
1813: output_addr_const (file, x);
1814: }
1815:
1816: /* MEM rtls here are never SYMBOL_REFs (I think), so fldws is safe. */
1817:
1818: char *
1819: output_floatsisf2 (operands)
1820: rtx *operands;
1821: {
1822: if (GET_CODE (operands[1]) == MEM)
1823: return "fldws %1,%0\n\tfcnvxf,sgl,sgl %0,%0";
1824: else if (FP_REG_P (operands[1]))
1825: return "fcnvxf,sgl,sgl %1,%0";
1826: return "stwm %r1,4(0,30)\n\tfldws,mb -4(0,30),%0\n\tfcnvxf,sgl,sgl %0,%0";
1827: }
1828:
1829: char *
1830: output_floatsidf2 (operands)
1831: rtx *operands;
1832: {
1833: if (GET_CODE (operands[1]) == MEM)
1834: return "fldws %1,%0\n\tfcnvxf,sgl,dbl %0,%0";
1835: else if (FP_REG_P (operands[1]))
1836: return "fcnvxf,sgl,dbl %1,%0";
1837: return "stwm %r1,4(0,30)\n\tfldws,mb -4(0,30),%0\n\tfcnvxf,sgl,dbl %0,%0";
1838: }
1839:
1840: enum rtx_code
1841: reverse_relop (code)
1842: enum rtx_code code;
1843: {
1844: switch (code)
1845: {
1846: case GT:
1847: return LT;
1848: case LT:
1849: return GT;
1850: case GE:
1851: return LE;
1852: case LE:
1853: return GE;
1854: case LTU:
1855: return GTU;
1856: case GTU:
1857: return LTU;
1858: case GEU:
1859: return LEU;
1860: case LEU:
1861: return GEU;
1862: default:
1863: abort ();
1864: }
1865: }
1866:
1867: /* What the spectrum lacks in hardware, make up for in software.
1868: Compute a fairly good sequence of shift and add insns
1869: to make a multiply happen. This should punt and call millicode if
1870: the sequence gets too big, but that's hard to do at this stage
1871: because it involves clobbering several registers. Oh, well. */
1872:
1873: #define ABS(x) ((x) < 0 ? -(x) : x)
1874:
1875: static rtx *mul_operands;
1876:
1877: void mul_by_constant_aux ();
1878:
1879: int
1880: emit_mul_by_constant (operands, unsignedp)
1881: rtx *operands;
1882: int unsignedp;
1883: {
1884: int constant;
1885: mul_operands = operands;
1886:
1887: constant = INTVAL (operands[2]);
1888: if (constant == 0)
1889: {
1890: /* Does happen, at least when not optimizing. */
1891: emit_insn (gen_rtx (SET, VOIDmode, operands[0], const0_rtx));
1892: return 1;
1893: }
1894: if (constant == 1)
1895: {
1896: emit_insn (gen_rtx (SET, VOIDmode, operands[0], operands[1]));
1897: return 1;
1898: }
1899: mul_by_constant_aux (ABS(constant));
1900: if (constant < 0)
1901: emit_insn (gen_negsi2 (operands[0], operands[0]));
1902: return 1;
1903: }
1904:
1905: /* This greedy algorithm uses the fact that several constant
1906: multiplies are rather cheap on the PA:
1907: * 2^n (shift n places)
1908: * (2^n + 1) and (2^n - 1) (shift n and add or subtract)
1909: * 3, 5, 9 (sh1add, sh2add, sh3add) */
1910:
1911: void
1912: mul_by_constant_aux (constant)
1913: int constant;
1914: {
1915: int log2, diff; /* log2 of constant and difference */
1916: /* from a power of 2 */
1917: int ffs_res;
1918: rtx xoperands[4];
1919:
1920: xoperands[0] = mul_operands[0]; xoperands[1] = mul_operands[1];
1921: log2 = log2_and_diff(constant, &diff);
1922: /* constant = 2^n or 2^n +/- 1? constant = 3,5,9 is handled better
1923: by the shift and add instructions. */
1924: if (!diff || (diff == 1 && constant != 3 && constant != 5 && constant != 9)
1925: || (diff == -1 && constant != 3))
1926: {
1927: emit_insn (gen_rtx (SET, VOIDmode,
1928: mul_operands[0],
1929: gen_rtx (ASHIFT, SImode,
1930: mul_operands[1],
1931: gen_rtx (CONST_INT, VOIDmode, log2))));
1932: if (diff == 1)
1933: emit_insn (gen_addsi3 (mul_operands[0],
1934: mul_operands[0],
1935: mul_operands[1]));
1936: else if (diff == -1)
1937: emit_insn (gen_subsi3 (mul_operands[0],
1938: mul_operands[0],
1939: mul_operands[1]));
1940: }
1941: /* The things we try are ordered by how many binary digits of
1942: constant they consume */
1943: /* is 2^n a factor of constant, n > 3? */
1944: else if ((ffs_res = ffs (constant)) > 4)
1945: {
1946: mul_by_constant_aux ((constant >> (ffs_res - 1)));
1947: emit_insn (gen_rtx (SET, VOIDmode,
1948: mul_operands[0],
1949: gen_rtx (ASHIFT, SImode,
1950: mul_operands[0],
1951: gen_rtx (CONST_INT, VOIDmode,
1952: ffs_res - 1))));
1953: }
1954: /* If the bottom n bits of constant are all 1's, that's the same as
1955: multiplying the total by 2^n and subtracting the multiplicand. */
1956: else if ((ffs_res = ffs (~constant)) > 4)
1957: {
1958: mul_by_constant_aux ((constant >> (ffs_res - 1)) | 1);
1959: emit_insn (gen_rtx (SET, VOIDmode,
1960: mul_operands[0],
1961: gen_rtx (ASHIFT, SImode,
1962: mul_operands[0],
1963: gen_rtx (CONST_INT, VOIDmode,
1964: ffs_res - 1))));
1965: emit_insn (gen_subsi3 (mul_operands[0],
1966: mul_operands[0],
1967: mul_operands[1]));
1968: }
1969: /* factor and test for possible shift/add combinations */
1970: else if (test_factor_and_output (constant, 9));
1971: else if (test_factor_and_output (constant, 8));
1972: else if ((constant & 0x7) == 0x1)
1973: {
1974: mul_by_constant_aux (constant >> 3);
1975: emit_insn (gen_rtx (SET, VOIDmode,
1976: mul_operands[0],
1977: gen_rtx (PLUS, SImode,
1978: mul_operands[1],
1979: gen_rtx (MULT, SImode,
1980: mul_operands[0],
1981: gen_rtx (CONST_INT, VOIDmode,
1982: 8)))));
1983: }
1984: else if (test_factor_and_output (constant, 5));
1985: else if (test_factor_and_output (constant, 4));
1986: else if ((constant & 0x3) == 0x1)
1987: {
1988: mul_by_constant_aux (constant >> 2);
1989: emit_insn (gen_rtx (SET, VOIDmode,
1990: mul_operands[0],
1991: gen_rtx (PLUS, SImode,
1992: mul_operands[1],
1993: gen_rtx (MULT, SImode,
1994: mul_operands[0],
1995: gen_rtx (CONST_INT, VOIDmode,
1996: 4)))));
1997: }
1998: else if (test_factor_and_output (constant, 3));
1999: else if (test_factor_and_output (constant, 2));
2000: else
2001: {
2002: mul_by_constant_aux (constant >> 1);
2003: emit_insn (gen_rtx (SET, VOIDmode,
2004: mul_operands[0],
2005: gen_rtx (PLUS, SImode,
2006: mul_operands[1],
2007: gen_rtx (MULT, SImode,
2008: mul_operands[0],
2009: gen_rtx (CONST_INT, VOIDmode,
2010: 2)))));
2011: }
2012: }
2013:
2014: /* If FACTOR is a factor of CONSTANT, output the appropriate shift and
2015: add instruction */
2016:
2017: int
2018: test_factor_and_output (constant, factor)
2019: int constant, factor;
2020: {
2021: rtx xoperands0, xoperands1, xoperands2;
2022: int shift, add_op = 0;
2023:
2024: xoperands0 = mul_operands[0];
2025: if (!(constant % factor))
2026: {
2027: switch (factor)
2028: {
2029: case 9:
2030: shift = 3; add_op = 1; break;
2031: case 8:
2032: shift = 3; break;
2033: case 5:
2034: shift = 2; add_op = 1; break;
2035: case 4:
2036: shift = 2; break;
2037: case 3:
2038: shift = 1; add_op = 1; break;
2039: case 2:
2040: shift = 1; break;
2041: default:
2042: abort ();
2043: }
2044: if (constant / factor == 1)
2045: {
2046: xoperands1 = mul_operands[1];
2047: xoperands2 = mul_operands[1];
2048: }
2049: else
2050: {
2051: mul_by_constant_aux (constant / factor);
2052: xoperands1 = mul_operands[0];
2053: xoperands2 = mul_operands[0];
2054: }
2055: if (add_op)
2056: emit_insn (gen_rtx (SET, VOIDmode,
2057: xoperands0,
2058: gen_rtx (PLUS, SImode,
2059: xoperands1,
2060: gen_rtx (MULT, SImode,
2061: xoperands2,
2062: gen_rtx (CONST_INT, VOIDmode,
2063: 1 << shift)))));
2064: else
2065: emit_insn (gen_rtx (SET, VOIDmode,
2066: xoperands0,
2067: gen_rtx (ASHIFT, SImode,
2068: xoperands1,
2069: gen_rtx (CONST_INT, VOIDmode, shift))));
2070: return 1;
2071: }
2072: return 0;
2073: }
2074:
2075: /* This routine finds the floor_log2 of val and returns it and the
2076: difference between val and 2^log2(val). If val is 1 less than a
2077: power of 2, that power's log and -1 are returned. */
2078:
2079: int log2_and_diff (val, diff)
2080: int val, *diff;
2081: {
2082: int log = floor_log2 (val);
2083:
2084: *diff = val - (1 << log);
2085: if (!*diff || *diff == 1)
2086: {
2087: return log;
2088: }
2089: else /* see if val is one less than a power */
2090: { /* of 2 */
2091: int alt_log = floor_log2 (val + 1);
2092: if (!((val + 1) - (1 << alt_log)))
2093: {
2094: *diff = -1;
2095: return alt_log;
2096: }
2097: }
2098: return log;
2099: }
2100:
2101:
2102: /* HP's millicode routines mean something special to the assembler.
2103: Keep track of which ones we have used. */
2104:
2105: enum millicodes { remI, remU, divI, divU, mulI, mulU, end1000 };
2106: static char imported[(int)end1000];
2107: static char *milli_names[] = {"remI", "remU", "divI", "divU", "mulI", "mulU"};
2108: static char import_string[] = ".IMPORT $$....,MILLICODE";
2109: #define MILLI_START 10
2110:
2111: static int
2112: import_milli (code)
2113: enum millicodes code;
2114: {
2115: char str[sizeof(import_string)];
2116:
2117: if (!imported[(int)code])
2118: {
2119: imported[(int)code] = 1;
2120: strcpy (str, import_string);
2121: strncpy (str + MILLI_START, milli_names[(int)code], 4);
2122: output_asm_insn (str, 0);
2123: }
2124: }
2125:
2126: /* The register constraints have put the operands and return value in
2127: the proper registers. */
2128:
2129: char *
2130: output_mul_insn (unsignedp)
2131: int unsignedp;
2132: {
2133: if (unsignedp)
2134: {
2135: import_milli (mulU);
2136: return "bl $$mulU,31\n\tnop";
2137: }
2138: else
2139: {
2140: import_milli (mulI);
2141: return "bl $$mulI,31\n\tnop";
2142: }
2143: }
2144:
2145: /* If operands isn't NULL, then it's a CONST_INT with which we can do
2146: something */
2147:
2148:
2149: /* Emit the rtl for doing a division by a constant. */
2150:
2151: /* Do magic division millicodes exist for this value? */
2152:
2153: static int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
2154: 1, 1};
2155:
2156: /* We'll use an array to keep track of the magic millicodes and
2157: whether or not we've used them already. [n][0] is signed, [n][1] is
2158: unsigned. */
2159:
2160:
2161: static int div_milli[16][2];
2162:
2163: int
2164: div_operand (op, mode)
2165: rtx op;
2166: enum machine_mode mode;
2167: {
2168: return (mode == SImode
2169: && ((GET_CODE (op) == REG && REGNO (op) == 25)
2170: || (GET_CODE (op) == CONST_INT && INTVAL (op) > 0
2171: && INTVAL (op) < 16 && magic_milli[INTVAL (op)])));
2172: }
2173:
2174: int
2175: emit_hpdiv_const(operands, unsignedp)
2176: rtx *operands;
2177: int unsignedp;
2178: {
2179: if (GET_CODE (operands[2]) == CONST_INT
2180: && INTVAL (operands[2]) > 0
2181: && INTVAL (operands[2]) < 16
2182: && magic_milli[INTVAL (operands[2])])
2183: {
2184: emit_move_insn ( gen_rtx (REG, SImode, 26), operands[1]);
2185: emit
2186: (gen_rtx
2187: (PARALLEL, VOIDmode,
2188: gen_rtvec (5, gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 29),
2189: gen_rtx (unsignedp ? UDIV : DIV, SImode,
2190: gen_rtx (REG, SImode, 26),
2191: operands[2])),
2192: gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, SImode, 0)),
2193: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 26)),
2194: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 25)),
2195: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 31)))));
2196: emit_move_insn (operands[0], gen_rtx (REG, SImode, 29));
2197: return 1;
2198: }
2199: return 0;
2200: }
2201:
2202: char *
2203: output_div_insn(operands, unsignedp)
2204: rtx *operands;
2205: int unsignedp;
2206: {
2207: int divisor;
2208:
2209: /* If the divisor is a constant, try to use one of the special
2210: opcodes .*/
2211: if (GET_CODE (operands[0]) == CONST_INT)
2212: {
2213: divisor = INTVAL (operands[0]);
2214: if (!div_milli[divisor][unsignedp])
2215: {
2216: if (unsignedp)
2217: output_asm_insn (".IMPORT $$divU_%0,MILLICODE", operands);
2218: else
2219: output_asm_insn (".IMPORT $$divI_%0,MILLICODE", operands);
2220: div_milli[divisor][unsignedp] = 1;
2221: }
2222: if (unsignedp)
2223: return "bl $$divU_%0,31%#";
2224: return "bl $$divI_%0,31%#";
2225: }
2226: /* Divisor isn't a special constant. */
2227: else
2228: {
2229: if (unsignedp)
2230: {
2231: import_milli (divU);
2232: return "bl $$divU,31%#";
2233: }
2234: else
2235: {
2236: import_milli (divI);
2237: return "bl $$divI,31%#";
2238: }
2239: }
2240: }
2241:
2242: /* Output a $$rem millicode to do mod. */
2243:
2244: char *
2245: output_mod_insn (unsignedp)
2246: int unsignedp;
2247: {
2248: if (unsignedp)
2249: {
2250: import_milli (remU);
2251: return "bl $$remU,31%#";
2252: }
2253: else
2254: {
2255: import_milli (remI);
2256: return "bl $$remI,31%#";
2257: }
2258: }
2259:
2260: void
2261: output_arg_descriptor (insn)
2262: rtx insn;
2263: {
2264: char *arg_regs[4];
2265: enum machine_mode arg_mode;
2266: rtx prev_insn;
2267: int i, output_flag = 0;
2268: int regno;
2269:
2270: for (i = 0; i < 4; i++)
2271: arg_regs[i] = 0;
2272:
2273: for (prev_insn = PREV_INSN (insn); GET_CODE (prev_insn) == INSN;
2274: prev_insn = PREV_INSN (prev_insn))
2275: {
2276: if (!(GET_CODE (PATTERN (prev_insn)) == USE &&
2277: GET_CODE (XEXP (PATTERN (prev_insn), 0)) == REG &&
2278: FUNCTION_ARG_REGNO_P (REGNO (XEXP (PATTERN (prev_insn), 0)))))
2279: break;
2280: arg_mode = GET_MODE (XEXP (PATTERN (prev_insn), 0));
2281: regno = REGNO (XEXP (PATTERN (prev_insn), 0));
2282: if (regno >= 23 && regno <= 26)
2283: arg_regs[26 - regno] = "GR";
2284: else if (!TARGET_SNAKE) /* fp args */
2285: {
2286: if (arg_mode == SFmode)
2287: arg_regs[regno - 36] = "FR";
2288: else
2289: {
2290: #ifdef hpux8
2291: arg_regs[regno - 37] = "FR";
2292: arg_regs[regno - 36] = "FU";
2293: #else
2294: arg_regs[regno - 37] = "FU";
2295: arg_regs[regno - 36] = "FR";
2296: #endif
2297: }
2298: }
2299: else
2300: {
2301: if (arg_mode == SFmode)
2302: arg_regs[(regno - 56) / 2] = "FR";
2303: else
2304: {
2305: arg_regs[regno - 58] = "FR";
2306: arg_regs[regno - 57] = "FU";
2307: }
2308: }
2309: }
2310: fputs ("\t.CALL ", asm_out_file);
2311: for (i = 0; i < 4; i++)
2312: {
2313: if (arg_regs[i])
2314: {
2315: if (output_flag++)
2316: fputc (',', asm_out_file);
2317: fprintf (asm_out_file, "ARGW%d=%s", i, arg_regs[i]);
2318: }
2319: }
2320: fputc ('\n', asm_out_file);
2321: }
2322:
2323: /* Memory loads/stores to/from fp registers may need a scratch
2324: register in which to reload the address. */
2325:
2326: enum reg_class
2327: secondary_reload_class (class, mode, in)
2328: enum reg_class class;
2329: enum machine_mode mode;
2330: rtx in;
2331: {
2332: int regno = true_regnum (in);
2333:
2334: if (regno >= FIRST_PSEUDO_REGISTER)
2335: regno = -1;
2336:
2337: if (class == FP_REGS || class == SNAKE_FP_REGS || class == HI_SNAKE_FP_REGS)
2338: {
2339: if (regno = -1 || !REGNO_OK_FOR_FP_P (regno))
2340: return GENERAL_REGS;
2341: }
2342: return NO_REGS;
2343: }
2344:
2345: enum direction {none, upward, downward};
2346:
2347: enum direction
2348: function_arg_padding (mode, type)
2349: enum machine_mode mode;
2350: tree type;
2351: {
2352: int size;
2353:
2354: if (mode == BLKmode)
2355: {
2356: if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
2357: size = int_size_in_bytes (type) * BITS_PER_UNIT;
2358: else
2359: return upward; /* Don't know if this is right, but */
2360: /* same as old definition. */
2361: }
2362: else
2363: size = GET_MODE_BITSIZE (mode);
2364: if (size < PARM_BOUNDARY)
2365: return downward;
2366: else if (size % PARM_BOUNDARY)
2367: return upward;
2368: else
2369: return none;
2370: }
2371:
2372: int
2373: use_milli_regs (insn)
2374: rtx insn;
2375: {
2376: return (reg_mentioned_p (gen_rtx (REG, SImode, 1), insn) ||
2377: reg_mentioned_p (gen_rtx (REG, SImode, 25), insn) ||
2378: reg_mentioned_p (gen_rtx (REG, SImode, 26), insn) ||
2379: reg_mentioned_p (gen_rtx (REG, SImode, 29), insn) ||
2380: reg_mentioned_p (gen_rtx (REG, SImode, 31), insn));
2381: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.