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