|
|
1.1 root 1: /* Subroutines for insn-output.c for Sun SPARC.
2: Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
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"
1.1.1.3 ! root 23: #include "tree.h"
1.1 root 24: #include "rtl.h"
25: #include "regs.h"
26: #include "hard-reg-set.h"
27: #include "real.h"
28: #include "insn-config.h"
29: #include "conditions.h"
30: #include "insn-flags.h"
31: #include "output.h"
32: #include "insn-attr.h"
33: #include "flags.h"
34: #include "expr.h"
35: #include "recog.h"
36:
37: /* Global variables for machine-dependent things. */
38:
39: /* Save the operands last given to a compare for use when we
40: generate a scc or bcc insn. */
41:
42: rtx sparc_compare_op0, sparc_compare_op1;
43:
44: /* We may need an epilogue if we spill too many registers.
45: If this is non-zero, then we branch here for the epilogue. */
46: static rtx leaf_label;
47:
48: #ifdef LEAF_REGISTERS
49:
50: /* Vector to say how input registers are mapped to output
51: registers. FRAME_POINTER_REGNUM cannot be remapped by
52: this function to eliminate it. You must use -fomit-frame-pointer
53: to get that. */
54: char leaf_reg_remap[] =
55: { 0, 1, 2, 3, 4, 5, 6, 7,
56: -1, -1, -1, -1, -1, -1, 14, -1,
57: -1, -1, -1, -1, -1, -1, -1, -1,
58: 8, 9, 10, 11, 12, 13, -1, 15,
59:
60: 32, 33, 34, 35, 36, 37, 38, 39,
61: 40, 41, 42, 43, 44, 45, 46, 47,
62: 48, 49, 50, 51, 52, 53, 54, 55,
63: 56, 57, 58, 59, 60, 61, 62, 63};
64:
65: char leaf_reg_backmap[] =
66: { 0, 1, 2, 3, 4, 5, 6, 7,
67: 24, 25, 26, 27, 28, 29, 14, 31,
68: -1, -1, -1, -1, -1, -1, -1, -1,
69: -1, -1, -1, -1, -1, -1, -1, -1,
70:
71: 32, 33, 34, 35, 36, 37, 38, 39,
72: 40, 41, 42, 43, 44, 45, 46, 47,
73: 48, 49, 50, 51, 52, 53, 54, 55,
74: 56, 57, 58, 59, 60, 61, 62, 63};
75: #endif
76:
77: /* Global variables set by FUNCTION_PROLOGUE. */
78: /* Size of frame. Need to know this to emit return insns from
79: leaf procedures. */
80: int apparent_fsize;
81: int actual_fsize;
82:
83: /* Name of where we pretend to think the frame pointer points.
84: Normally, this is "%fp", but if we are in a leaf procedure,
85: this is "%sp+something". */
86: char *frame_base_name;
87:
88: static rtx find_addr_reg ();
89:
90: /* Return non-zero only if OP is a register of mode MODE,
91: or const0_rtx. */
92: int
93: reg_or_0_operand (op, mode)
94: rtx op;
95: enum machine_mode mode;
96: {
97: if (op == const0_rtx || register_operand (op, mode))
98: return 1;
99: if (GET_CODE (op) == CONST_DOUBLE
100: && CONST_DOUBLE_HIGH (op) == 0
101: && CONST_DOUBLE_LOW (op) == 0)
102: return 1;
103: return 0;
104: }
105:
106: /* Nonzero if OP can appear as the dest of a RESTORE insn. */
107: int
108: restore_operand (op, mode)
109: rtx op;
110: enum machine_mode mode;
111: {
112: return (GET_CODE (op) == REG && GET_MODE (op) == mode
113: && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
114: }
115:
116: /* PC-relative call insn on SPARC is independent of `memory_operand'. */
117:
118: int
119: call_operand (op, mode)
120: rtx op;
121: enum machine_mode mode;
122: {
123: if (GET_CODE (op) != MEM)
124: abort ();
125: op = XEXP (op, 0);
126: return (REG_P (op) || CONSTANT_P (op));
127: }
128:
129: int
130: call_operand_address (op, mode)
131: rtx op;
132: enum machine_mode mode;
133: {
134: return (REG_P (op) || CONSTANT_P (op));
135: }
136:
137: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
138: reference and a constant. */
139:
140: int
141: symbolic_operand (op, mode)
142: register rtx op;
143: enum machine_mode mode;
144: {
145: switch (GET_CODE (op))
146: {
147: case SYMBOL_REF:
148: case LABEL_REF:
149: return 1;
150:
151: case CONST:
152: op = XEXP (op, 0);
153: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
154: || GET_CODE (XEXP (op, 0)) == LABEL_REF)
155: && GET_CODE (XEXP (op, 1)) == CONST_INT);
156:
157: /* This clause seems to be irrelevant. */
158: case CONST_DOUBLE:
159: return GET_MODE (op) == mode;
160:
161: default:
162: return 0;
163: }
164: }
165:
166: /* Return truth value of statement that OP is a symbolic memory
167: operand of mode MODE. */
168:
169: int
170: symbolic_memory_operand (op, mode)
171: rtx op;
172: enum machine_mode mode;
173: {
174: if (GET_CODE (op) == SUBREG)
175: op = SUBREG_REG (op);
176: if (GET_CODE (op) != MEM)
177: return 0;
178: op = XEXP (op, 0);
179: return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
180: || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
181: }
182:
183: /* Return 1 if the operand is either a register or a memory operand that is
184: not symbolic. */
185:
186: int
187: reg_or_nonsymb_mem_operand (op, mode)
188: register rtx op;
189: enum machine_mode mode;
190: {
191: if (register_operand (op, mode))
192: return 1;
193:
194: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
195: return 1;
196:
197: return 0;
198: }
199:
200: int
201: sparc_operand (op, mode)
202: rtx op;
203: enum machine_mode mode;
204: {
205: if (register_operand (op, mode))
206: return 1;
207: if (GET_CODE (op) == CONST_INT)
208: return SMALL_INT (op);
209: if (GET_MODE (op) != mode)
210: return 0;
211: if (GET_CODE (op) == SUBREG)
212: op = SUBREG_REG (op);
213: if (GET_CODE (op) != MEM)
214: return 0;
215:
216: op = XEXP (op, 0);
217: if (GET_CODE (op) == LO_SUM)
218: return (GET_CODE (XEXP (op, 0)) == REG
219: && symbolic_operand (XEXP (op, 1), Pmode));
220: return memory_address_p (mode, op);
221: }
222:
223: int
224: move_operand (op, mode)
225: rtx op;
226: enum machine_mode mode;
227: {
228: if (mode == DImode && arith_double_operand (op, mode))
229: return 1;
230: if (register_operand (op, mode))
231: return 1;
232: if (GET_CODE (op) == CONST_INT)
233: return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0);
234:
235: if (GET_MODE (op) != mode)
236: return 0;
237: if (GET_CODE (op) == SUBREG)
238: op = SUBREG_REG (op);
239: if (GET_CODE (op) != MEM)
240: return 0;
241: op = XEXP (op, 0);
242: if (GET_CODE (op) == LO_SUM)
243: return (register_operand (XEXP (op, 0), Pmode)
244: && CONSTANT_P (XEXP (op, 1)));
245: return memory_address_p (mode, op);
246: }
247:
248: int
249: move_pic_label (op, mode)
250: rtx op;
251: enum machine_mode mode;
252: {
253: /* Special case for PIC. */
254: if (flag_pic && GET_CODE (op) == LABEL_REF)
255: return 1;
256: return 0;
257: }
258:
259: /* The rtx for the global offset table which is a special form
260: that *is* a position independent symbolic constant. */
261: rtx pic_pc_rtx;
262:
263: /* Ensure that we are not using patterns that are not OK with PIC. */
264:
265: int
266: check_pic (i)
267: int i;
268: {
269: switch (flag_pic)
270: {
271: case 1:
272: if (GET_CODE (recog_operand[i]) == SYMBOL_REF
273: || (GET_CODE (recog_operand[i]) == CONST
274: && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
275: abort ();
276: case 2:
277: default:
278: return 1;
279: }
280: }
281:
282: /* Return true if X is an address which needs a temporary register when
283: reloaded while generating PIC code. */
284:
285: int
286: pic_address_needs_scratch (x)
287: rtx x;
288: {
289: /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
290: if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
291: && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
292: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
293: && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
294: return 1;
295:
296: return 0;
297: }
298:
299: int
300: memop (op, mode)
301: rtx op;
302: enum machine_mode mode;
303: {
304: if (GET_CODE (op) == MEM)
305: return (mode == VOIDmode || mode == GET_MODE (op));
306: return 0;
307: }
308:
309: /* Return truth value of whether OP is EQ or NE. */
310:
311: int
312: eq_or_neq (op, mode)
313: rtx op;
314: enum machine_mode mode;
315: {
316: return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
317: }
318:
319: /* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
320: or LTU for non-floating-point. We handle those specially. */
321:
322: int
323: normal_comp_operator (op, mode)
324: rtx op;
325: enum machine_mode mode;
326: {
327: enum rtx_code code = GET_CODE (op);
328:
329: if (GET_RTX_CLASS (code) != '<')
330: return 0;
331:
1.1.1.3 ! root 332: if (GET_MODE (XEXP (op, 0)) == CCFPmode
! 333: || GET_MODE (XEXP (op, 0)) == CCFPEmode)
1.1 root 334: return 1;
335:
336: return (code != NE && code != EQ && code != GEU && code != LTU);
337: }
338:
339: /* Return 1 if this is a comparison operator. This allows the use of
340: MATCH_OPERATOR to recognize all the branch insns. */
341:
342: int
343: noov_compare_op (op, mode)
344: register rtx op;
345: enum machine_mode mode;
346: {
347: enum rtx_code code = GET_CODE (op);
348:
349: if (GET_RTX_CLASS (code) != '<')
350: return 0;
351:
352: if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode)
353: /* These are the only branches which work with CC_NOOVmode. */
354: return (code == EQ || code == NE || code == GE || code == LT);
355: return 1;
356: }
357:
358: /* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */
359:
360: int
361: extend_op (op, mode)
362: rtx op;
363: enum machine_mode mode;
364: {
365: return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
366: }
367:
368: /* Return nonzero if OP is an operator of mode MODE which can set
369: the condition codes explicitly. We do not include PLUS and MINUS
370: because these require CC_NOOVmode, which we handle explicitly. */
371:
372: int
373: cc_arithop (op, mode)
374: rtx op;
375: enum machine_mode mode;
376: {
377: if (GET_CODE (op) == AND
378: || GET_CODE (op) == IOR
379: || GET_CODE (op) == XOR)
380: return 1;
381:
382: return 0;
383: }
384:
385: /* Return nonzero if OP is an operator of mode MODE which can bitwise
386: complement its second operand and set the condition codes explicitly. */
387:
388: int
389: cc_arithopn (op, mode)
390: rtx op;
391: enum machine_mode mode;
392: {
393: /* XOR is not here because combine canonicalizes (xor (not ...) ...)
394: and (xor ... (not ...)) to (not (xor ...)). */
395: return (GET_CODE (op) == AND
396: || GET_CODE (op) == IOR);
397: }
398:
399: /* Return truth value of whether OP can be used as an operands in a three
400: address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */
401:
402: int
403: arith_operand (op, mode)
404: rtx op;
405: enum machine_mode mode;
406: {
407: return (register_operand (op, mode)
408: || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
409: }
410:
411: /* Return truth value of whether OP is a register or a CONST_DOUBLE. */
412:
413: int
414: arith_double_operand (op, mode)
415: rtx op;
416: enum machine_mode mode;
417: {
418: return (register_operand (op, mode)
419: || (GET_CODE (op) == CONST_DOUBLE
420: && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
421: && (unsigned) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
422: && ((CONST_DOUBLE_HIGH (op) == -1
423: && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
424: || (CONST_DOUBLE_HIGH (op) == 0
425: && (CONST_DOUBLE_LOW (op) & 0x1000) == 0)))
426: || (GET_CODE (op) == CONST_INT
427: && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
428: && (unsigned) (INTVAL (op) + 0x1000) < 0x2000));
429: }
430:
431: /* Return truth value of whether OP is a integer which fits the
432: range constraining immediate operands in three-address insns. */
433:
434: int
435: small_int (op, mode)
436: rtx op;
437: enum machine_mode mode;
438: {
439: return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
440: }
441:
442: /* Return truth value of statement that OP is a call-clobbered register. */
443: int
444: clobbered_register (op, mode)
445: rtx op;
446: enum machine_mode mode;
447: {
448: return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
449: }
450:
451: /* X and Y are two things to compare using CODE. Emit the compare insn and
452: return the rtx for register 0 in the proper mode. */
453:
454: rtx
455: gen_compare_reg (code, x, y)
456: enum rtx_code code;
457: rtx x, y;
458: {
459: enum machine_mode mode = SELECT_CC_MODE (code, x);
460: rtx cc_reg = gen_rtx (REG, mode, 0);
461:
462: emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
463: gen_rtx (COMPARE, mode, x, y)));
464:
465: return cc_reg;
466: }
467:
468: /* Return nonzero if a return peephole merging return with
469: setting of output register is ok. */
470: int
471: leaf_return_peephole_ok ()
472: {
473: return (actual_fsize == 0);
474: }
475:
476: /* Return nonzero if TRIAL can go into the function epilogue's
477: delay slot. SLOT is the slot we are trying to fill. */
478:
479: int
480: eligible_for_epilogue_delay (trial, slot)
481: rtx trial;
482: int slot;
483: {
484: static char *this_function_name;
485: rtx pat, src;
486:
487: if (slot >= 1)
488: return 0;
489: if (GET_CODE (trial) != INSN
490: || GET_CODE (PATTERN (trial)) != SET)
491: return 0;
492: if (get_attr_length (trial) != 1)
493: return 0;
494:
1.1.1.3 ! root 495: /* In the case of a true leaf function, anything can go into the delay slot.
! 496: A delay slot only exists however if the frame size is zero, otherwise
! 497: we will put an insn to adjust the stack after the return. */
1.1 root 498: if (leaf_function)
499: {
500: if (leaf_return_peephole_ok ())
501: return (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_TRUE);
502: return 0;
503: }
504:
505: /* Otherwise, only operations which can be done in tandem with
506: a `restore' insn can go into the delay slot. */
507: pat = PATTERN (trial);
508: if (GET_CODE (SET_DEST (pat)) != REG
509: || REGNO (SET_DEST (pat)) == 0
1.1.1.3 ! root 510: || REGNO (SET_DEST (pat)) >= 32
! 511: || REGNO (SET_DEST (pat)) < 24)
1.1 root 512: return 0;
1.1.1.3 ! root 513:
1.1 root 514: src = SET_SRC (pat);
515: if (arith_operand (src, GET_MODE (src)))
516: return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
517: if (arith_double_operand (src, GET_MODE (src)))
518: return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
519: if (GET_CODE (src) == PLUS)
520: {
521: if (register_operand (XEXP (src, 0), SImode)
522: && arith_operand (XEXP (src, 1), SImode))
523: return 1;
524: if (register_operand (XEXP (src, 1), SImode)
525: && arith_operand (XEXP (src, 0), SImode))
526: return 1;
527: if (register_operand (XEXP (src, 0), DImode)
528: && arith_double_operand (XEXP (src, 1), DImode))
529: return 1;
530: if (register_operand (XEXP (src, 1), DImode)
531: && arith_double_operand (XEXP (src, 0), DImode))
532: return 1;
533: }
534: if (GET_CODE (src) == MINUS
535: && register_operand (XEXP (src, 0), SImode)
536: && small_int (XEXP (src, 1), VOIDmode))
537: return 1;
538: if (GET_CODE (src) == MINUS
539: && register_operand (XEXP (src, 0), DImode)
540: && !register_operand (XEXP (src, 1), DImode)
541: && arith_double_operand (XEXP (src, 1), DImode))
542: return 1;
543: return 0;
544: }
545:
546: int
547: short_branch (uid1, uid2)
548: int uid1, uid2;
549: {
550: unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2];
551: if (delta + 1024 < 2048)
552: return 1;
553: /* warning ("long branch, distance %d", delta); */
554: return 0;
555: }
556:
557: /* Return non-zero if REG is not used after INSN.
558: We assume REG is a reload reg, and therefore does
559: not live past labels or calls or jumps. */
560: int
561: reg_unused_after (reg, insn)
562: rtx reg;
563: rtx insn;
564: {
565: enum rtx_code code, prev_code = UNKNOWN;
566:
567: while (insn = NEXT_INSN (insn))
568: {
569: if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)])
570: return 1;
571:
572: code = GET_CODE (insn);
573: if (GET_CODE (insn) == CODE_LABEL)
574: return 1;
575:
576: if (GET_RTX_CLASS (code) == 'i')
577: {
578: rtx set = single_set (insn);
579: int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
580: if (set && in_src)
581: return 0;
582: if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
583: return 1;
584: if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
585: return 0;
586: }
587: prev_code = code;
588: }
589: return 1;
590: }
591:
592: /* Legitimize PIC addresses. If the address is already position-independent,
593: we return ORIG. Newly generated position-independent addresses go into a
594: reg. This is REG if non zero, otherwise we allocate register(s) as
595: necessary. If this is called during reload, and we need a second temp
596: register, then we use SCRATCH, which is provided via the
597: SECONDARY_INPUT_RELOAD_CLASS mechanism. */
598:
599: rtx
600: legitimize_pic_address (orig, mode, reg, scratch)
601: rtx orig;
602: enum machine_mode mode;
603: rtx reg, scratch;
604: {
605: if (GET_CODE (orig) == SYMBOL_REF)
606: {
607: rtx pic_ref, address;
608: rtx insn;
609:
610: if (reg == 0)
611: {
1.1.1.2 root 612: if (reload_in_progress || reload_completed)
1.1 root 613: abort ();
614: else
615: reg = gen_reg_rtx (Pmode);
616: }
617:
618: if (flag_pic == 2)
619: {
620: /* If not during reload, allocate another temp reg here for loading
621: in the address, so that these instructions can be optimized
622: properly. */
1.1.1.2 root 623: rtx temp_reg = ((reload_in_progress || reload_completed)
624: ? reg : gen_reg_rtx (Pmode));
1.1 root 625:
1.1.1.2 root 626: /* Must put the SYMBOL_REF inside an UNSPEC here so that cse
627: won't get confused into thinking that these two instructions
628: are loading in the true address of the symbol. If in the
629: future a PIC rtx exists, that should be used instead. */
1.1 root 630: emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
1.1.1.2 root 631: gen_rtx (HIGH, Pmode,
632: gen_rtx (UNSPEC, Pmode,
633: gen_rtvec (1, orig),
634: 0))));
1.1 root 635: emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
1.1.1.2 root 636: gen_rtx (LO_SUM, Pmode, temp_reg,
637: gen_rtx (UNSPEC, Pmode,
638: gen_rtvec (1, orig),
639: 0))));
1.1 root 640: address = temp_reg;
641: }
642: else
643: address = orig;
644:
645: pic_ref = gen_rtx (MEM, Pmode,
646: gen_rtx (PLUS, Pmode,
647: pic_offset_table_rtx, address));
648: current_function_uses_pic_offset_table = 1;
649: RTX_UNCHANGING_P (pic_ref) = 1;
650: insn = emit_move_insn (reg, pic_ref);
651: /* Put a REG_EQUAL note on this insn, so that it can be optimized
652: by loop. */
653: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig,
654: REG_NOTES (insn));
655: return reg;
656: }
657: else if (GET_CODE (orig) == CONST)
658: {
659: rtx base, offset;
660:
661: if (GET_CODE (XEXP (orig, 0)) == PLUS
662: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
663: return orig;
664:
665: if (reg == 0)
666: {
1.1.1.2 root 667: if (reload_in_progress || reload_completed)
1.1 root 668: abort ();
669: else
670: reg = gen_reg_rtx (Pmode);
671: }
672:
673: if (GET_CODE (XEXP (orig, 0)) == PLUS)
674: {
675: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode,
676: reg, 0);
677: offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
678: base == reg ? 0 : reg, 0);
679: }
680: else
681: abort ();
682:
683: if (GET_CODE (offset) == CONST_INT)
684: {
685: if (SMALL_INT (offset))
686: return plus_constant_for_output (base, INTVAL (offset));
1.1.1.2 root 687: else if (! reload_in_progress && ! reload_completed)
1.1 root 688: offset = force_reg (Pmode, offset);
689: /* We can't create any new registers during reload, so use the
690: SCRATCH reg provided by the reload_insi pattern. */
691: else if (scratch)
692: {
693: emit_move_insn (scratch, offset);
694: offset = scratch;
695: }
696: else
697: /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS
698: macro needs to be adjusted so that a scratch reg is provided
699: for this address. */
700: abort ();
701: }
702: return gen_rtx (PLUS, Pmode, base, offset);
703: }
704: else if (GET_CODE (orig) == LABEL_REF)
705: current_function_uses_pic_offset_table = 1;
706:
707: return orig;
708: }
709:
710: /* Set up PIC-specific rtl. This should not cause any insns
711: to be emitted. */
712:
713: void
714: initialize_pic ()
715: {
716: }
717:
718: /* Emit special PIC prologues and epilogues. */
719:
720: void
721: finalize_pic ()
722: {
723: /* The table we use to reference PIC data. */
724: rtx global_offset_table;
725: /* Labels to get the PC in the prologue of this function. */
726: rtx l1, l2;
727: rtx seq;
728: int orig_flag_pic = flag_pic;
729:
730: if (current_function_uses_pic_offset_table == 0)
731: return;
732:
733: if (! flag_pic)
734: abort ();
735:
736: flag_pic = 0;
737: l1 = gen_label_rtx ();
738: l2 = gen_label_rtx ();
739:
740: start_sequence ();
741:
742: emit_label (l1);
743: /* Note that we pun calls and jumps here! */
744: emit_jump_insn (gen_rtx (PARALLEL, VOIDmode,
745: gen_rtvec (2,
746: gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)),
747: gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2)))));
748: emit_label (l2);
749:
750: /* Initialize every time through, since we can't easily
751: know this to be permanent. */
752: global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "*__GLOBAL_OFFSET_TABLE_");
753: pic_pc_rtx = gen_rtx (CONST, Pmode,
754: gen_rtx (MINUS, Pmode,
755: global_offset_table,
756: gen_rtx (CONST, Pmode,
757: gen_rtx (MINUS, Pmode,
758: gen_rtx (LABEL_REF, VOIDmode, l1),
759: pc_rtx))));
760:
761: emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
762: gen_rtx (HIGH, Pmode, pic_pc_rtx)));
763: emit_insn (gen_rtx (SET, VOIDmode,
764: pic_offset_table_rtx,
765: gen_rtx (LO_SUM, Pmode,
766: pic_offset_table_rtx, pic_pc_rtx)));
767: emit_insn (gen_rtx (SET, VOIDmode,
768: pic_offset_table_rtx,
769: gen_rtx (PLUS, Pmode,
770: pic_offset_table_rtx, gen_rtx (REG, Pmode, 15))));
771: /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */
772: LABEL_PRESERVE_P (l1) = 1;
773: LABEL_PRESERVE_P (l2) = 1;
774: flag_pic = orig_flag_pic;
775:
776: seq = gen_sequence ();
777: end_sequence ();
778: emit_insn_after (seq, get_insns ());
779:
780: /* Need to emit this whether or not we obey regdecls,
781: since setjmp/longjmp can cause life info to screw up. */
782: emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
783: }
784:
785: /* For the SPARC, REG and REG+CONST is cost 0, REG+REG is cost 1,
786: and addresses involving symbolic constants are cost 2.
787:
788: We make REG+REG slightly more expensive because it might keep
789: a register live for longer than we might like.
790:
791: PIC addresses are very expensive.
792:
793: It is no coincidence that this has the same structure
794: as GO_IF_LEGITIMATE_ADDRESS. */
795: int
796: sparc_address_cost (X)
797: rtx X;
798: {
799: #if 0
800: /* Handled before calling here. */
801: if (GET_CODE (X) == REG)
802: { return 1; }
803: #endif
804: if (GET_CODE (X) == PLUS)
805: {
806: if (GET_CODE (XEXP (X, 0)) == REG
807: && GET_CODE (XEXP (X, 1)) == REG)
808: return 2;
809: return 1;
810: }
811: else if (GET_CODE (X) == LO_SUM)
812: return 1;
813: else if (GET_CODE (X) == HIGH)
814: return 2;
815: return 4;
816: }
817:
818: /* Emit insns to move operands[1] into operands[0].
819:
820: Return 1 if we have written out everything that needs to be done to
821: do the move. Otherwise, return 0 and the caller will emit the move
822: normally.
823:
824: SCRATCH_REG if non zero can be used as a scratch register for the move
825: operation. It is provided by a SECONDARY_RELOAD_* macro if needed. */
826:
827: int
828: emit_move_sequence (operands, mode, scratch_reg)
829: rtx *operands;
830: enum machine_mode mode;
831: rtx scratch_reg;
832: {
833: register rtx operand0 = operands[0];
834: register rtx operand1 = operands[1];
835:
836: /* Handle most common case first: storing into a register. */
837: if (register_operand (operand0, mode))
838: {
839: if (register_operand (operand1, mode)
840: || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
841: || (GET_CODE (operand1) == CONST_DOUBLE
842: && arith_double_operand (operand1, DImode))
843: || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode)
844: /* Only `general_operands' can come here, so MEM is ok. */
845: || GET_CODE (operand1) == MEM)
846: {
847: /* Run this case quickly. */
848: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
849: return 1;
850: }
851: }
852: else if (GET_CODE (operand0) == MEM)
853: {
854: if (register_operand (operand1, mode) || operand1 == const0_rtx)
855: {
856: /* Run this case quickly. */
857: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
858: return 1;
859: }
860: if (! reload_in_progress)
861: {
862: operands[0] = validize_mem (operand0);
863: operands[1] = operand1 = force_reg (mode, operand1);
864: }
865: }
866:
867: /* Simplify the source if we need to. Must handle DImode HIGH operators
868: here because such a move needs a clobber added. */
869: if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
870: || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode))
871: {
872: if (flag_pic && symbolic_operand (operand1, mode))
873: {
874: rtx temp_reg = reload_in_progress ? operand0 : 0;
875:
876: operands[1] = legitimize_pic_address (operand1, mode, temp_reg,
877: scratch_reg);
878: }
879: else if (GET_CODE (operand1) == CONST_INT
880: ? (! SMALL_INT (operand1)
881: && (INTVAL (operand1) & 0x3ff) != 0)
882: : (GET_CODE (operand1) == CONST_DOUBLE
883: ? ! arith_double_operand (operand1, DImode)
884: : 1))
885: {
886: /* For DImode values, temp must be operand0 because of the way
887: HI and LO_SUM work. The LO_SUM operator only copies half of
888: the LSW from the dest of the HI operator. If the LO_SUM dest is
889: not the same as the HI dest, then the MSW of the LO_SUM dest will
890: never be set.
891:
892: ??? The real problem here is that the ...(HI:DImode pattern emits
893: multiple instructions, and the ...(LO_SUM:DImode pattern emits
894: one instruction. This fails, because the compiler assumes that
895: LO_SUM copies all bits of the first operand to its dest. Better
896: would be to have the HI pattern emit one instruction and the
897: LO_SUM pattern multiple instructions. Even better would be
898: to use four rtl insns. */
899: rtx temp = ((reload_in_progress || mode == DImode)
900: ? operand0 : gen_reg_rtx (mode));
901:
902: emit_insn (gen_rtx (SET, VOIDmode, temp,
903: gen_rtx (HIGH, mode, operand1)));
904: operands[1] = gen_rtx (LO_SUM, mode, temp, operand1);
905: }
906: }
907:
908: if (GET_CODE (operand1) == LABEL_REF && flag_pic)
909: {
910: /* The procedure for doing this involves using a call instruction to
911: get the pc into o7. We need to indicate this explicitly because
912: the tablejump pattern assumes that it can use this value also. */
913: emit_insn (gen_rtx (PARALLEL, VOIDmode,
914: gen_rtvec (2,
915: gen_rtx (SET, VOIDmode, operand0,
916: operand1),
917: gen_rtx (SET, VOIDmode,
918: gen_rtx (REG, mode, 15),
919: pc_rtx))));
920: return 1;
921: }
922:
923: /* Now have insn-emit do whatever it normally does. */
924: return 0;
925: }
926:
927: /* Return the best assembler insn template
928: for moving operands[1] into operands[0] as a fullword. */
929:
930: char *
931: singlemove_string (operands)
932: rtx *operands;
933: {
934: if (GET_CODE (operands[0]) == MEM)
935: {
936: if (GET_CODE (operands[1]) != MEM)
937: return "st %r1,%0";
938: else
939: abort ();
940: }
1.1.1.3 ! root 941: else if (GET_CODE (operands[1]) == MEM)
1.1 root 942: return "ld %1,%0";
1.1.1.3 ! root 943: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
! 944: {
! 945: int i;
! 946: union real_extract u;
! 947: union float_extract { float f; int i; } v;
! 948:
! 949: /* Must be SFmode, otherwise this doesn't make sense. */
! 950: if (GET_MODE (operands[1]) != SFmode)
! 951: abort ();
! 952:
! 953: bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u);
! 954: v.f = REAL_VALUE_TRUNCATE (SFmode, u.d);
! 955: i = v.i;
! 956:
! 957: operands[1] = gen_rtx (CONST_INT, VOIDmode, i);
! 958:
! 959: if (CONST_OK_FOR_LETTER_P (i, 'I'))
! 960: return "mov %1,%0";
! 961: else if ((i & 0x000003FF) != 0)
! 962: return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
! 963: else
! 964: return "sethi %%hi(%a1),%0";
! 965: }
! 966: else if (GET_CODE (operands[1]) == CONST_INT
! 967: && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
1.1 root 968: {
969: int i = INTVAL (operands[1]);
970:
1.1.1.3 ! root 971: /* If all low order 10 bits are clear, then we only need a single
1.1 root 972: sethi insn to load the constant. */
1.1.1.3 ! root 973: if ((i & 0x000003FF) != 0)
1.1 root 974: return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
975: else
976: return "sethi %%hi(%a1),%0";
977: }
1.1.1.3 ! root 978: /* Operand 1 must be a register, or a 'I' type CONST_INT. */
1.1 root 979: return "mov %1,%0";
980: }
981:
1.1.1.3 ! root 982: /* Return non-zero if it is OK to assume that the given memory operand is
! 983: aligned at least to a 8-byte boundary. This should only be called
! 984: for memory accesses whose size is 8 bytes or larger. */
! 985:
! 986: static int
! 987: mem_aligned_8 (mem)
! 988: register rtx mem;
! 989: {
! 990: register rtx addr;
! 991: register rtx base;
! 992: register rtx offset;
! 993:
! 994: if (GET_CODE (mem) != MEM)
! 995: abort (); /* It's gotta be a MEM! */
! 996:
! 997: addr = XEXP (mem, 0);
! 998:
! 999: #if 1
! 1000: /* Now that all misaligned double parms are copied on function entry,
! 1001: we can assume any 64-bit object is 64-bit aligned. */
! 1002:
! 1003: /* See what register we use in the address. */
! 1004: base = 0;
! 1005: if (GET_CODE (addr) == PLUS)
! 1006: {
! 1007: if (GET_CODE (XEXP (addr, 0)) == REG
! 1008: && GET_CODE (XEXP (addr, 1)) == CONST_INT)
! 1009: {
! 1010: base = XEXP (addr, 0);
! 1011: offset = XEXP (addr, 1);
! 1012: }
! 1013: }
! 1014: else if (GET_CODE (addr) == REG)
! 1015: {
! 1016: base = addr;
! 1017: offset = const0_rtx;
! 1018: }
! 1019:
! 1020: /* If it's the stack or frame pointer, check offset alignment.
! 1021: We can have improper aligment in the function entry code. */
! 1022: if (base
! 1023: && (REGNO (base) == FRAME_POINTER_REGNUM
! 1024: || REGNO (base) == STACK_POINTER_REGNUM))
! 1025: {
! 1026: if ((INTVAL (offset) & 0x7) == 0)
! 1027: return 1;
! 1028: }
! 1029: else
! 1030: /* Anything else, we know is properly aligned. */
! 1031: return 1;
! 1032: #else
! 1033: /* If the operand is known to have been allocated in static storage, then
! 1034: it must be aligned. */
! 1035:
! 1036: if (CONSTANT_P (addr) || GET_CODE (addr) == LO_SUM)
! 1037: return 1;
! 1038:
! 1039: base = 0;
! 1040: if (GET_CODE (addr) == PLUS)
! 1041: {
! 1042: if (GET_CODE (XEXP (addr, 0)) == REG
! 1043: && GET_CODE (XEXP (addr, 1)) == CONST_INT)
! 1044: {
! 1045: base = XEXP (addr, 0);
! 1046: offset = XEXP (addr, 1);
! 1047: }
! 1048: }
! 1049: else if (GET_CODE (addr) == REG)
! 1050: {
! 1051: base = addr;
! 1052: offset = const0_rtx;
! 1053: }
! 1054:
! 1055: /* Trust round enough offsets from the stack or frame pointer.
! 1056: If TARGET_HOPE_ALIGN, trust round enough offset from any register.
! 1057: If it is obviously unaligned, don't ever return true. */
! 1058: if (base
! 1059: && (REGNO (base) == FRAME_POINTER_REGNUM
! 1060: || REGNO (base) == STACK_POINTER_REGNUM
! 1061: || TARGET_HOPE_ALIGN))
! 1062: {
! 1063: if ((INTVAL (offset) & 0x7) == 0)
! 1064: return 1;
! 1065: }
! 1066: /* Otherwise, we can assume that an access is aligned if it is to an
! 1067: aggregate. Also, if TARGET_HOPE_ALIGN, then assume everything that isn't
! 1068: obviously unaligned is aligned. */
! 1069: else if (MEM_IN_STRUCT_P (mem) || TARGET_HOPE_ALIGN)
! 1070: return 1;
! 1071: #endif
! 1072:
! 1073: /* An obviously unaligned address. */
! 1074: return 0;
! 1075: }
! 1076:
! 1077: enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP };
! 1078:
1.1 root 1079: /* Output assembler code to perform a doubleword move insn
1.1.1.3 ! root 1080: with operands OPERANDS. This is very similar to the following
! 1081: output_move_quad function. */
1.1 root 1082:
1083: char *
1084: output_move_double (operands)
1085: rtx *operands;
1086: {
1.1.1.3 ! root 1087: register rtx op0 = operands[0];
! 1088: register rtx op1 = operands[1];
! 1089: register enum optype optype0;
! 1090: register enum optype optype1;
1.1 root 1091: rtx latehalf[2];
1.1.1.3 ! root 1092: rtx addreg0 = 0;
! 1093: rtx addreg1 = 0;
1.1 root 1094:
1095: /* First classify both operands. */
1096:
1.1.1.3 ! root 1097: if (REG_P (op0))
1.1 root 1098: optype0 = REGOP;
1.1.1.3 ! root 1099: else if (offsettable_memref_p (op0))
1.1 root 1100: optype0 = OFFSOP;
1.1.1.3 ! root 1101: else if (GET_CODE (op0) == MEM)
1.1 root 1102: optype0 = MEMOP;
1103: else
1104: optype0 = RNDOP;
1105:
1.1.1.3 ! root 1106: if (REG_P (op1))
1.1 root 1107: optype1 = REGOP;
1.1.1.3 ! root 1108: else if (CONSTANT_P (op1))
1.1 root 1109: optype1 = CNSTOP;
1.1.1.3 ! root 1110: else if (offsettable_memref_p (op1))
1.1 root 1111: optype1 = OFFSOP;
1.1.1.3 ! root 1112: else if (GET_CODE (op1) == MEM)
1.1 root 1113: optype1 = MEMOP;
1114: else
1115: optype1 = RNDOP;
1116:
1117: /* Check for the cases that the operand constraints are not
1118: supposed to allow to happen. Abort if we get one,
1119: because generating code for these cases is painful. */
1120:
1.1.1.3 ! root 1121: if (optype0 == RNDOP || optype1 == RNDOP
! 1122: || (optype0 == MEM && optype1 == MEM))
1.1 root 1123: abort ();
1124:
1125: /* If an operand is an unoffsettable memory ref, find a register
1126: we can increment temporarily to make it refer to the second word. */
1127:
1128: if (optype0 == MEMOP)
1.1.1.3 ! root 1129: addreg0 = find_addr_reg (XEXP (op0, 0));
1.1 root 1130:
1131: if (optype1 == MEMOP)
1.1.1.3 ! root 1132: addreg1 = find_addr_reg (XEXP (op1, 0));
1.1 root 1133:
1134: /* Ok, we can do one word at a time.
1.1.1.3 ! root 1135: Set up in LATEHALF the operands to use for the
1.1 root 1136: high-numbered (least significant) word and in some cases alter the
1137: operands in OPERANDS to be suitable for the low-numbered word. */
1138:
1139: if (optype0 == REGOP)
1.1.1.3 ! root 1140: latehalf[0] = gen_rtx (REG, SImode, REGNO (op0) + 1);
1.1 root 1141: else if (optype0 == OFFSOP)
1.1.1.3 ! root 1142: latehalf[0] = adj_offsettable_operand (op0, 4);
1.1 root 1143: else
1.1.1.3 ! root 1144: latehalf[0] = op0;
1.1 root 1145:
1146: if (optype1 == REGOP)
1.1.1.3 ! root 1147: latehalf[1] = gen_rtx (REG, SImode, REGNO (op1) + 1);
1.1 root 1148: else if (optype1 == OFFSOP)
1.1.1.3 ! root 1149: latehalf[1] = adj_offsettable_operand (op1, 4);
1.1 root 1150: else if (optype1 == CNSTOP)
1.1.1.3 ! root 1151: split_double (op1, &operands[1], &latehalf[1]);
1.1 root 1152: else
1.1.1.3 ! root 1153: latehalf[1] = op1;
1.1 root 1154:
1.1.1.3 ! root 1155: /* Easy case: try moving both words at once. Check for moving between
! 1156: an even/odd register pair and a memory location. */
1.1 root 1157: if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP
1.1.1.3 ! root 1158: && (REGNO (op0) & 1) == 0)
1.1 root 1159: || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP
1.1.1.3 ! root 1160: && (REGNO (op1) & 1) == 0))
1.1 root 1161: {
1.1.1.3 ! root 1162: register rtx mem;
1.1 root 1163:
1164: if (optype0 == REGOP)
1.1.1.3 ! root 1165: mem = op1;
1.1 root 1166: else
1.1.1.3 ! root 1167: mem = op0;
1.1 root 1168:
1.1.1.3 ! root 1169: if (mem_aligned_8 (mem))
! 1170: return (mem == op1 ? "ldd %1,%0" : "std %1,%0");
1.1 root 1171: }
1172:
1.1.1.3 ! root 1173: /* If the first move would clobber the source of the second one,
! 1174: do them in the other order. */
! 1175:
! 1176: /* Overlapping registers. */
1.1 root 1177: if (optype0 == REGOP && optype1 == REGOP
1.1.1.3 ! root 1178: && REGNO (op0) == REGNO (latehalf[1]))
1.1 root 1179: {
1180: /* Do that word. */
1181: output_asm_insn (singlemove_string (latehalf), latehalf);
1182: /* Do low-numbered word. */
1183: return singlemove_string (operands);
1184: }
1.1.1.3 ! root 1185: /* Loading into a register which overlaps a register used in the address. */
1.1 root 1186: else if (optype0 == REGOP && optype1 != REGOP
1.1.1.3 ! root 1187: && reg_overlap_mentioned_p (op0, op1))
1.1 root 1188: {
1.1.1.3 ! root 1189: /* ??? This fails if the address is a double register address, each
! 1190: of which is clobbered by operand 0. */
1.1 root 1191: /* Do the late half first. */
1192: output_asm_insn (singlemove_string (latehalf), latehalf);
1193: /* Then clobber. */
1194: return singlemove_string (operands);
1195: }
1196:
1197: /* Normal case: do the two words, low-numbered first. */
1198:
1199: output_asm_insn (singlemove_string (operands), operands);
1200:
1201: /* Make any unoffsettable addresses point at high-numbered word. */
1202: if (addreg0)
1203: output_asm_insn ("add %0,0x4,%0", &addreg0);
1204: if (addreg1)
1205: output_asm_insn ("add %0,0x4,%0", &addreg1);
1206:
1207: /* Do that word. */
1208: output_asm_insn (singlemove_string (latehalf), latehalf);
1209:
1210: /* Undo the adds we just did. */
1211: if (addreg0)
1212: output_asm_insn ("add %0,-0x4,%0", &addreg0);
1213: if (addreg1)
1214: output_asm_insn ("add %0,-0x4,%0", &addreg1);
1215:
1216: return "";
1217: }
1.1.1.3 ! root 1218:
! 1219: /* Output assembler code to perform a quadword move insn
! 1220: with operands OPERANDS. This is very similar to the preceeding
! 1221: output_move_double function. */
! 1222:
! 1223: char *
! 1224: output_move_quad (operands)
! 1225: rtx *operands;
! 1226: {
! 1227: register rtx op0 = operands[0];
! 1228: register rtx op1 = operands[1];
! 1229: register enum optype optype0;
! 1230: register enum optype optype1;
! 1231: rtx wordpart[4][2];
! 1232: rtx addreg0 = 0;
! 1233: rtx addreg1 = 0;
! 1234:
! 1235: /* First classify both operands. */
! 1236:
! 1237: if (REG_P (op0))
! 1238: optype0 = REGOP;
! 1239: else if (offsettable_memref_p (op0))
! 1240: optype0 = OFFSOP;
! 1241: else if (GET_CODE (op0) == MEM)
! 1242: optype0 = MEMOP;
! 1243: else
! 1244: optype0 = RNDOP;
! 1245:
! 1246: if (REG_P (op1))
! 1247: optype1 = REGOP;
! 1248: else if (CONSTANT_P (op1))
! 1249: optype1 = CNSTOP;
! 1250: else if (offsettable_memref_p (op1))
! 1251: optype1 = OFFSOP;
! 1252: else if (GET_CODE (op1) == MEM)
! 1253: optype1 = MEMOP;
! 1254: else
! 1255: optype1 = RNDOP;
! 1256:
! 1257: /* Check for the cases that the operand constraints are not
! 1258: supposed to allow to happen. Abort if we get one,
! 1259: because generating code for these cases is painful. */
! 1260:
! 1261: if (optype0 == RNDOP || optype1 == RNDOP
! 1262: || (optype0 == MEM && optype1 == MEM))
! 1263: abort ();
! 1264:
! 1265: /* If an operand is an unoffsettable memory ref, find a register
! 1266: we can increment temporarily to make it refer to the later words. */
! 1267:
! 1268: if (optype0 == MEMOP)
! 1269: addreg0 = find_addr_reg (XEXP (op0, 0));
! 1270:
! 1271: if (optype1 == MEMOP)
! 1272: addreg1 = find_addr_reg (XEXP (op1, 0));
! 1273:
! 1274: /* Ok, we can do one word at a time.
! 1275: Set up in wordpart the operands to use for each word of the arguments. */
! 1276:
! 1277: if (optype0 == REGOP)
! 1278: {
! 1279: wordpart[0][0] = gen_rtx (REG, SImode, REGNO (op0) + 0);
! 1280: wordpart[1][0] = gen_rtx (REG, SImode, REGNO (op0) + 1);
! 1281: wordpart[2][0] = gen_rtx (REG, SImode, REGNO (op0) + 2);
! 1282: wordpart[3][0] = gen_rtx (REG, SImode, REGNO (op0) + 3);
! 1283: }
! 1284: else if (optype0 == OFFSOP)
! 1285: {
! 1286: wordpart[0][0] = adj_offsettable_operand (op0, 0);
! 1287: wordpart[1][0] = adj_offsettable_operand (op0, 4);
! 1288: wordpart[2][0] = adj_offsettable_operand (op0, 8);
! 1289: wordpart[3][0] = adj_offsettable_operand (op0, 12);
! 1290: }
! 1291: else
! 1292: {
! 1293: wordpart[0][0] = op0;
! 1294: wordpart[1][0] = op0;
! 1295: wordpart[2][0] = op0;
! 1296: wordpart[3][0] = op0;
! 1297: }
! 1298:
! 1299: if (optype1 == REGOP)
! 1300: {
! 1301: wordpart[0][1] = gen_rtx (REG, SImode, REGNO (op1) + 0);
! 1302: wordpart[1][1] = gen_rtx (REG, SImode, REGNO (op1) + 1);
! 1303: wordpart[2][1] = gen_rtx (REG, SImode, REGNO (op1) + 2);
! 1304: wordpart[3][1] = gen_rtx (REG, SImode, REGNO (op1) + 3);
! 1305: }
! 1306: else if (optype1 == OFFSOP)
! 1307: {
! 1308: wordpart[0][1] = adj_offsettable_operand (op1, 0);
! 1309: wordpart[1][1] = adj_offsettable_operand (op1, 4);
! 1310: wordpart[2][1] = adj_offsettable_operand (op1, 8);
! 1311: wordpart[3][1] = adj_offsettable_operand (op1, 12);
! 1312: }
! 1313: else if (optype1 == CNSTOP)
! 1314: {
! 1315: /* This case isn't implemented yet, because there is no internal
! 1316: representation for quad-word constants, and there is no split_quad
! 1317: function. */
! 1318: #if 0
! 1319: split_quad (op1, &wordpart[0][1], &wordpart[1][1],
! 1320: &wordpart[2][1], &wordpart[3][1]);
! 1321: #else
! 1322: abort ();
! 1323: #endif
! 1324: }
! 1325: else
! 1326: {
! 1327: wordpart[0][1] = op1;
! 1328: wordpart[1][1] = op1;
! 1329: wordpart[2][1] = op1;
! 1330: wordpart[3][1] = op1;
! 1331: }
! 1332:
! 1333: /* Easy case: try moving the quad as two pairs. Check for moving between
! 1334: an even/odd register pair and a memory location. */
! 1335: /* ??? Should also handle the case of non-offsettable addresses here.
! 1336: We can at least do the first pair as a ldd/std, and then do the third
! 1337: and fourth words individually. */
! 1338: if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0)
! 1339: || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0))
! 1340: {
! 1341: rtx mem;
! 1342:
! 1343: if (optype0 == REGOP)
! 1344: mem = op1;
! 1345: else
! 1346: mem = op0;
! 1347:
! 1348: if (mem_aligned_8 (mem))
! 1349: {
! 1350: operands[2] = adj_offsettable_operand (mem, 8);
! 1351: if (mem == op1)
! 1352: return "ldd %1,%0;ldd %2,%S0";
! 1353: else
! 1354: return "std %1,%0;std %S1,%2";
! 1355: }
! 1356: }
! 1357:
! 1358: /* If the first move would clobber the source of the second one,
! 1359: do them in the other order. */
! 1360:
! 1361: /* Overlapping registers. */
! 1362: if (optype0 == REGOP && optype1 == REGOP
! 1363: && (REGNO (op0) == REGNO (wordpart[1][3])
! 1364: || REGNO (op0) == REGNO (wordpart[1][2])
! 1365: || REGNO (op0) == REGNO (wordpart[1][1])))
! 1366: {
! 1367: /* Do fourth word. */
! 1368: output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
! 1369: /* Do the third word. */
! 1370: output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
! 1371: /* Do the second word. */
! 1372: output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
! 1373: /* Do lowest-numbered word. */
! 1374: return singlemove_string (wordpart[0]);
! 1375: }
! 1376: /* Loading into a register which overlaps a register used in the address. */
! 1377: if (optype0 == REGOP && optype1 != REGOP
! 1378: && reg_overlap_mentioned_p (op0, op1))
! 1379: {
! 1380: /* ??? Not implemented yet. This is a bit complicated, because we
! 1381: must load which ever part overlaps the address last. If the address
! 1382: is a double-reg address, then there are two parts which need to
! 1383: be done last, which is impossible. We would need a scratch register
! 1384: in that case. */
! 1385: abort ();
! 1386: }
! 1387:
! 1388: /* Normal case: move the four words in lowest to higest address order. */
! 1389:
! 1390: output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
! 1391:
! 1392: /* Make any unoffsettable addresses point at the second word. */
! 1393: if (addreg0)
! 1394: output_asm_insn ("add %0,0x4,%0", &addreg0);
! 1395: if (addreg1)
! 1396: output_asm_insn ("add %0,0x4,%0", &addreg1);
! 1397:
! 1398: /* Do the second word. */
! 1399: output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
! 1400:
! 1401: /* Make any unoffsettable addresses point at the third word. */
! 1402: if (addreg0)
! 1403: output_asm_insn ("add %0,0x4,%0", &addreg0);
! 1404: if (addreg1)
! 1405: output_asm_insn ("add %0,0x4,%0", &addreg1);
! 1406:
! 1407: /* Do the third word. */
! 1408: output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
! 1409:
! 1410: /* Make any unoffsettable addresses point at the fourth word. */
! 1411: if (addreg0)
! 1412: output_asm_insn ("add %0,0x4,%0", &addreg0);
! 1413: if (addreg1)
! 1414: output_asm_insn ("add %0,0x4,%0", &addreg1);
! 1415:
! 1416: /* Do the fourth word. */
! 1417: output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
! 1418:
! 1419: /* Undo the adds we just did. */
! 1420: if (addreg0)
! 1421: output_asm_insn ("add %0,-0xc,%0", &addreg0);
! 1422: if (addreg1)
! 1423: output_asm_insn ("add %0,-0xc,%0", &addreg1);
! 1424:
! 1425: return "";
! 1426: }
1.1 root 1427:
1.1.1.3 ! root 1428: /* Output assembler code to perform a doubleword move insn with operands
! 1429: OPERANDS, one of which must be a floating point register. */
! 1430:
1.1 root 1431: char *
1432: output_fp_move_double (operands)
1433: rtx *operands;
1434: {
1435: rtx addr;
1436:
1437: if (FP_REG_P (operands[0]))
1438: {
1439: if (FP_REG_P (operands[1]))
1440: return "fmovs %1,%0\n\tfmovs %R1,%R0";
1.1.1.3 ! root 1441: else if (GET_CODE (operands[1]) == REG)
1.1 root 1442: {
1443: if ((REGNO (operands[1]) & 1) == 0)
1444: return "std %1,[%@-8]\n\tldd [%@-8],%0";
1445: else
1446: return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0";
1447: }
1.1.1.3 ! root 1448: else
! 1449: return output_move_double (operands);
1.1 root 1450: }
1451: else if (FP_REG_P (operands[1]))
1452: {
1453: if (GET_CODE (operands[0]) == REG)
1454: {
1455: if ((REGNO (operands[0]) & 1) == 0)
1456: return "std %1,[%@-8]\n\tldd [%@-8],%0";
1457: else
1458: return "std %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0";
1459: }
1.1.1.3 ! root 1460: else
! 1461: return output_move_double (operands);
1.1 root 1462: }
1463: else abort ();
1464: }
1.1.1.3 ! root 1465:
! 1466: /* Output assembler code to perform a quadword move insn with operands
! 1467: OPERANDS, one of which must be a floating point register. */
! 1468:
! 1469: char *
! 1470: output_fp_move_quad (operands)
! 1471: rtx *operands;
! 1472: {
! 1473: register rtx op0 = operands[0];
! 1474: register rtx op1 = operands[1];
! 1475: register rtx addr;
! 1476:
! 1477: if (FP_REG_P (op0))
! 1478: {
! 1479: if (FP_REG_P (op1))
! 1480: return "fmovs %1,%0\n\tfmovs %R1,%R0\n\tfmovs %S1,%S0\n\tfmovs %T1,%T0";
! 1481: if (GET_CODE (op1) == REG)
! 1482: {
! 1483: if ((REGNO (op1) & 1) == 0)
! 1484: return "std %1,[%@-8]\n\tldd [%@-8],%0\n\tstd %S1,[%@-8]\n\tldd [%@-8],%S0";
! 1485: else
! 1486: return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0\n\tst %T1,[%@-4]\n\tst %S1,[%@-8]\n\tldd [%@-8],%S0";
! 1487: }
! 1488: else
! 1489: return output_move_quad (operands);
! 1490: }
! 1491: else if (FP_REG_P (op1))
! 1492: {
! 1493: if (GET_CODE (op0) == REG)
! 1494: {
! 1495: if ((REGNO (op0) & 1) == 0)
! 1496: return "std %1,[%@-8]\n\tldd [%@-8],%0\n\tstd %S1,[%@-8]\n\tldd [%@-8],%S0";
! 1497: else
! 1498: return "std %S1,[%@-8]\n\tld [%@-4],%T0\n\tld [%@-8],%S0\n\tstd %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0";
! 1499: }
! 1500: else
! 1501: return output_move_quad (operands);
! 1502: }
! 1503: else
! 1504: abort ();
! 1505: }
1.1 root 1506:
1507: /* Return a REG that occurs in ADDR with coefficient 1.
1508: ADDR can be effectively incremented by incrementing REG. */
1509:
1510: static rtx
1511: find_addr_reg (addr)
1512: rtx addr;
1513: {
1514: while (GET_CODE (addr) == PLUS)
1515: {
1516: /* We absolutely can not fudge the frame pointer here, because the
1517: frame pointer must always be 8 byte aligned. It also confuses
1518: debuggers. */
1519: if (GET_CODE (XEXP (addr, 0)) == REG
1520: && REGNO (XEXP (addr, 0)) != FRAME_POINTER_REGNUM)
1521: addr = XEXP (addr, 0);
1522: else if (GET_CODE (XEXP (addr, 1)) == REG
1523: && REGNO (XEXP (addr, 1)) != FRAME_POINTER_REGNUM)
1524: addr = XEXP (addr, 1);
1525: else if (CONSTANT_P (XEXP (addr, 0)))
1526: addr = XEXP (addr, 1);
1527: else if (CONSTANT_P (XEXP (addr, 1)))
1528: addr = XEXP (addr, 0);
1529: else
1530: abort ();
1531: }
1532: if (GET_CODE (addr) == REG)
1533: return addr;
1534: abort ();
1535: }
1536:
1537: void
1538: output_sized_memop (opname, mode, signedp)
1539: char *opname;
1540: enum machine_mode mode;
1541: int signedp;
1542: {
1543: static char *ld_size_suffix_u[] = { "ub", "uh", "", "?", "d" };
1544: static char *ld_size_suffix_s[] = { "sb", "sh", "", "?", "d" };
1545: static char *st_size_suffix[] = { "b", "h", "", "?", "d" };
1546: char **opnametab, *modename;
1547:
1548: if (opname[0] == 'l')
1549: if (signedp)
1550: opnametab = ld_size_suffix_s;
1551: else
1552: opnametab = ld_size_suffix_u;
1553: else
1554: opnametab = st_size_suffix;
1555: modename = opnametab[GET_MODE_SIZE (mode) >> 1];
1556:
1557: fprintf (asm_out_file, "\t%s%s", opname, modename);
1558: }
1559:
1560: void
1561: output_move_with_extension (operands)
1562: rtx *operands;
1563: {
1564: if (GET_MODE (operands[2]) == HImode)
1565: output_asm_insn ("sll %2,0x10,%0", operands);
1566: else if (GET_MODE (operands[2]) == QImode)
1567: output_asm_insn ("sll %2,0x18,%0", operands);
1568: else
1569: abort ();
1570: }
1571:
1572: /* Load the address specified by OPERANDS[3] into the register
1573: specified by OPERANDS[0].
1574:
1575: OPERANDS[3] may be the result of a sum, hence it could either be:
1576:
1577: (1) CONST
1578: (2) REG
1579: (2) REG + CONST_INT
1580: (3) REG + REG + CONST_INT
1581: (4) REG + REG (special case of 3).
1582:
1583: Note that (3) is not a legitimate address.
1584: All cases are handled here. */
1585:
1586: void
1587: output_load_address (operands)
1588: rtx *operands;
1589: {
1590: rtx base, offset;
1591:
1592: if (CONSTANT_P (operands[3]))
1593: {
1594: output_asm_insn ("set %3,%0", operands);
1595: return;
1596: }
1597:
1598: if (REG_P (operands[3]))
1599: {
1600: if (REGNO (operands[0]) != REGNO (operands[3]))
1601: output_asm_insn ("mov %3,%0", operands);
1602: return;
1603: }
1604:
1605: if (GET_CODE (operands[3]) != PLUS)
1606: abort ();
1607:
1608: base = XEXP (operands[3], 0);
1609: offset = XEXP (operands[3], 1);
1610:
1611: if (GET_CODE (base) == CONST_INT)
1612: {
1613: rtx tmp = base;
1614: base = offset;
1615: offset = tmp;
1616: }
1617:
1618: if (GET_CODE (offset) != CONST_INT)
1619: {
1620: /* Operand is (PLUS (REG) (REG)). */
1621: base = operands[3];
1622: offset = const0_rtx;
1623: }
1624:
1625: if (REG_P (base))
1626: {
1627: operands[6] = base;
1628: operands[7] = offset;
1629: if (SMALL_INT (offset))
1630: output_asm_insn ("add %6,%7,%0", operands);
1631: else
1632: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
1633: }
1634: else if (GET_CODE (base) == PLUS)
1635: {
1636: operands[6] = XEXP (base, 0);
1637: operands[7] = XEXP (base, 1);
1638: operands[8] = offset;
1639:
1640: if (SMALL_INT (offset))
1641: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
1642: else
1643: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
1644: }
1645: else
1646: abort ();
1647: }
1648:
1649: /* Output code to place a size count SIZE in register REG.
1650: ALIGN is the size of the unit of transfer.
1651:
1652: Because block moves are pipelined, we don't include the
1653: first element in the transfer of SIZE to REG. */
1654:
1655: static void
1656: output_size_for_block_move (size, reg, align)
1657: rtx size, reg;
1658: rtx align;
1659: {
1660: rtx xoperands[3];
1661:
1662: xoperands[0] = reg;
1663: xoperands[1] = size;
1664: xoperands[2] = align;
1665: if (GET_CODE (size) == REG)
1666: output_asm_insn ("sub %1,%2,%0", xoperands);
1667: else
1668: {
1669: xoperands[1]
1670: = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
1671: output_asm_insn ("set %1,%0", xoperands);
1672: }
1673: }
1674:
1675: /* Emit code to perform a block move.
1676:
1677: OPERANDS[0] is the destination.
1678: OPERANDS[1] is the source.
1679: OPERANDS[2] is the size.
1680: OPERANDS[3] is the alignment safe to use.
1681: OPERANDS[4] is a register we can safely clobber as a temp. */
1682:
1683: char *
1684: output_block_move (operands)
1685: rtx *operands;
1686: {
1687: /* A vector for our computed operands. Note that load_output_address
1688: makes use of (and can clobber) up to the 8th element of this vector. */
1689: rtx xoperands[10];
1690: rtx zoperands[10];
1691: static int movstrsi_label = 0;
1692: int i;
1693: rtx temp1 = operands[4];
1694: rtx sizertx = operands[2];
1695: rtx alignrtx = operands[3];
1696: int align = INTVAL (alignrtx);
1.1.1.3 ! root 1697: char label3[30], label5[30];
1.1 root 1698:
1699: xoperands[0] = operands[0];
1700: xoperands[1] = operands[1];
1701: xoperands[2] = temp1;
1702:
1.1.1.2 root 1703: /* We can't move more than this many bytes at a time because we have only
1704: one register, %g1, to move them through. */
1705: if (align > UNITS_PER_WORD)
1706: {
1707: align = UNITS_PER_WORD;
1708: alignrtx = gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD);
1709: }
1710:
1711: /* We consider 8 ld/st pairs, for a total of 16 inline insns to be
1712: reasonable here. (Actually will emit a maximum of 18 inline insns for
1713: the case of size == 31 and align == 4). */
1714:
1715: if (GET_CODE (sizertx) == CONST_INT && (INTVAL (sizertx) / align) <= 8
1716: && memory_address_p (QImode, plus_constant_for_output (xoperands[0],
1717: INTVAL (sizertx)))
1718: && memory_address_p (QImode, plus_constant_for_output (xoperands[1],
1719: INTVAL (sizertx))))
1.1 root 1720: {
1.1.1.2 root 1721: int size = INTVAL (sizertx);
1722: int offset = 0;
1723:
1724: /* We will store different integers into this particular RTX. */
1725: xoperands[2] = rtx_alloc (CONST_INT);
1726: PUT_MODE (xoperands[2], VOIDmode);
1727:
1728: /* This case is currently not handled. Abort instead of generating
1729: bad code. */
1730: if (align > 4)
1731: abort ();
1732:
1733: if (align >= 4)
1734: {
1735: for (i = (size >> 2) - 1; i >= 0; i--)
1736: {
1737: INTVAL (xoperands[2]) = (i << 2) + offset;
1738: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
1739: xoperands);
1740: }
1741: offset += (size & ~0x3);
1742: size = size & 0x3;
1743: if (size == 0)
1744: return "";
1745: }
1746:
1747: if (align >= 2)
1748: {
1749: for (i = (size >> 1) - 1; i >= 0; i--)
1750: {
1751: INTVAL (xoperands[2]) = (i << 1) + offset;
1752: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
1753: xoperands);
1754: }
1755: offset += (size & ~0x1);
1756: size = size & 0x1;
1757: if (size == 0)
1758: return "";
1759: }
1760:
1761: if (align >= 1)
1762: {
1763: for (i = size - 1; i >= 0; i--)
1764: {
1765: INTVAL (xoperands[2]) = i + offset;
1766: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
1767: xoperands);
1768: }
1769: return "";
1770: }
1771:
1772: /* We should never reach here. */
1773: abort ();
1.1 root 1774: }
1775:
1776: /* If the size isn't known to be a multiple of the alignment,
1777: we have to do it in smaller pieces. If we could determine that
1778: the size was a multiple of 2 (or whatever), we could be smarter
1779: about this. */
1780: if (GET_CODE (sizertx) != CONST_INT)
1781: align = 1;
1782: else
1783: {
1784: int size = INTVAL (sizertx);
1785: while (size % align)
1786: align >>= 1;
1787: }
1788:
1789: if (align != INTVAL (alignrtx))
1790: alignrtx = gen_rtx (CONST_INT, VOIDmode, align);
1791:
1792: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1793: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
1794: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
1795:
1.1.1.3 ! root 1796: ASM_GENERATE_INTERNAL_LABEL (label3, "Lm", INTVAL (xoperands[3]));
! 1797: ASM_GENERATE_INTERNAL_LABEL (label5, "Lm", INTVAL (xoperands[5]));
! 1798:
1.1.1.2 root 1799: /* This is the size of the transfer. Emit code to decrement the size
1800: value by ALIGN, and store the result in the temp1 register. */
1.1 root 1801: output_size_for_block_move (sizertx, temp1, alignrtx);
1802:
1803: /* Must handle the case when the size is zero or negative, so the first thing
1804: we do is compare the size against zero, and only copy bytes if it is
1805: zero or greater. Note that we have already subtracted off the alignment
1806: once, so we must copy 1 alignment worth of bytes if the size is zero
1807: here.
1808:
1809: The SUN assembler complains about labels in branch delay slots, so we
1.1.1.2 root 1810: do this before outputting the load address, so that there will always
1.1 root 1811: be a harmless insn between the branch here and the next label emitted
1812: below. */
1813:
1.1.1.3 ! root 1814: {
! 1815: char pattern[100];
! 1816:
! 1817: sprintf (pattern, "cmp %%2,0\n\tbl %s", &label5[1]);
! 1818: output_asm_insn (pattern, xoperands);
! 1819: }
1.1 root 1820:
1821: zoperands[0] = operands[0];
1822: zoperands[3] = plus_constant_for_output (operands[0], align);
1823: output_load_address (zoperands);
1824:
1825: /* ??? This might be much faster if the loops below were preconditioned
1826: and unrolled.
1827:
1828: That is, at run time, copy enough bytes one at a time to ensure that the
1829: target and source addresses are aligned to the the largest possible
1830: alignment. Then use a preconditioned unrolled loop to copy say 16
1831: bytes at a time. Then copy bytes one at a time until finish the rest. */
1832:
1833: /* Output the first label separately, so that it is spaced properly. */
1834:
1835: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "Lm", INTVAL (xoperands[3]));
1836:
1.1.1.3 ! root 1837: {
! 1838: char pattern[200];
! 1839: register char *ld_suffix = (align == 1) ? "ub" : (align == 2) ? "uh" : "";
! 1840: register char *st_suffix = (align == 1) ? "b" : (align == 2) ? "h" : "";
! 1841:
! 1842: sprintf (pattern, "ld%s [%%1+%%2],%%%%g1\n\tsubcc %%2,%%4,%%2\n\tbge %s\n\tst%s %%%%g1,[%%0+%%2]\n%s:", ld_suffix, &label3[1], st_suffix, &label5[1]);
! 1843: output_asm_insn (pattern, xoperands);
! 1844: }
! 1845:
1.1 root 1846: return "";
1847: }
1848:
1849: /* Output reasonable peephole for set-on-condition-code insns.
1850: Note that these insns assume a particular way of defining
1851: labels. Therefore, *both* sparc.h and this function must
1852: be changed if a new syntax is needed. */
1853:
1854: char *
1855: output_scc_insn (operands, insn)
1856: rtx operands[];
1857: rtx insn;
1858: {
1859: static char string[100];
1860: rtx label = 0, next = insn;
1861: int need_label = 0;
1862:
1863: /* Try doing a jump optimization which jump.c can't do for us
1864: because we did not expose that setcc works by using branches.
1865:
1866: If this scc insn is followed by an unconditional branch, then have
1867: the jump insn emitted here jump to that location, instead of to
1868: the end of the scc sequence as usual. */
1869:
1870: do
1871: {
1872: if (GET_CODE (next) == CODE_LABEL)
1873: label = next;
1874: next = NEXT_INSN (next);
1875: if (next == 0)
1876: break;
1877: }
1878: while (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL);
1879:
1880: /* If we are in a sequence, and the following insn is a sequence also,
1881: then just following the current insn's next field will take us to the
1882: first insn of the next sequence, which is the wrong place. We don't
1883: want to optimize with a branch that has had its delay slot filled.
1884: Avoid this by verifying that NEXT_INSN (PREV_INSN (next)) == next
1885: which fails only if NEXT is such a branch. */
1886:
1887: if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next)
1888: && (! final_sequence || NEXT_INSN (PREV_INSN (next)) == next))
1889: label = JUMP_LABEL (next);
1890: /* If not optimizing, jump label fields are not set. To be safe, always
1891: check here to whether label is still zero. */
1892: if (label == 0)
1893: {
1894: label = gen_label_rtx ();
1895: need_label = 1;
1896: }
1897:
1898: LABEL_NUSES (label) += 1;
1899:
1900: operands[2] = label;
1901:
1902: /* If we are in a delay slot, assume it is the delay slot of an fpcc
1903: insn since our type isn't allowed anywhere else. */
1904:
1905: /* ??? Fpcc instructions no longer have delay slots, so this code is
1906: probably obsolete. */
1907:
1908: /* The fastest way to emit code for this is an annulled branch followed
1909: by two move insns. This will take two cycles if the branch is taken,
1910: and three cycles if the branch is not taken.
1911:
1912: However, if we are in the delay slot of another branch, this won't work,
1913: because we can't put a branch in the delay slot of another branch.
1914: The above sequence would effectively take 3 or 4 cycles respectively
1915: since a no op would have be inserted between the two branches.
1916: In this case, we want to emit a move, annulled branch, and then the
1917: second move. This sequence always takes 3 cycles, and hence is faster
1918: when we are in a branch delay slot. */
1919:
1920: if (final_sequence)
1921: {
1922: strcpy (string, "mov 0,%0\n\t");
1923: strcat (string, output_cbranch (operands[1], 2, 0, 1, 0));
1924: strcat (string, "\n\tmov 1,%0");
1925: }
1926: else
1927: {
1928: strcpy (string, output_cbranch (operands[1], 2, 0, 1, 0));
1929: strcat (string, "\n\tmov 1,%0\n\tmov 0,%0");
1930: }
1931:
1932: if (need_label)
1933: strcat (string, "\n%l2:");
1934:
1935: return string;
1936: }
1937:
1938: /* Vectors to keep interesting information about registers where
1939: it can easily be got. */
1940:
1941: /* Modes for condition codes. */
1.1.1.3 ! root 1942: #define C_MODES \
! 1943: ((1 << (int) CCmode) | (1 << (int) CC_NOOVmode) \
! 1944: | (1 << (int) CCFPmode) | (1 << (int) CCFPEmode))
1.1 root 1945:
1946: /* Modes for single-word (and smaller) quantities. */
1947: #define S_MODES \
1948: (~C_MODES \
1949: & ~ ((1 << (int) DImode) | (1 << (int) TImode) \
1950: | (1 << (int) DFmode) | (1 << (int) TFmode)))
1951:
1952: /* Modes for double-word (and smaller) quantities. */
1953: #define D_MODES \
1954: (~C_MODES \
1955: & ~ ((1 << (int) TImode) | (1 << (int) TFmode)))
1956:
1957: /* Modes for quad-word quantities. */
1958: #define T_MODES (~C_MODES)
1959:
1960: /* Modes for single-float quantities. */
1961: #define SF_MODES ((1 << (int) SFmode))
1962:
1963: /* Modes for double-float quantities. */
1964: #define DF_MODES (SF_MODES | (1 << (int) DFmode) | (1 << (int) SCmode))
1965:
1966: /* Modes for quad-float quantities. */
1967: #define TF_MODES (DF_MODES | (1 << (int) TFmode) | (1 << (int) DCmode))
1968:
1969: /* Value is 1 if register/mode pair is acceptable on sparc.
1970: The funny mixture of D and T modes is because integer operations
1971: do not specially operate on tetra quantities, so non-quad-aligned
1972: registers can hold quadword quantities (except %o4 and %i4 because
1973: they cross fixed registers. */
1974:
1975: int hard_regno_mode_ok[] = {
1976: C_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
1977: T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
1978: T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
1979: T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
1980:
1981: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
1982: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
1983: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
1984: TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES};
1985:
1986: #ifdef __GNUC__
1987: inline
1988: #endif
1989: static int
1990: save_regs (file, low, high, base, offset, n_fregs)
1991: FILE *file;
1992: int low, high;
1993: char *base;
1994: int offset;
1995: int n_fregs;
1996: {
1997: int i;
1998:
1999: for (i = low; i < high; i += 2)
2000: {
2001: if (regs_ever_live[i] && ! call_used_regs[i])
2002: if (regs_ever_live[i+1] && ! call_used_regs[i+1])
2003: fprintf (file, "\tstd %s,[%s+%d]\n",
2004: reg_names[i], base, offset + 4 * n_fregs),
2005: n_fregs += 2;
2006: else
2007: fprintf (file, "\tst %s,[%s+%d]\n",
2008: reg_names[i], base, offset + 4 * n_fregs),
2009: n_fregs += 2;
2010: else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
2011: fprintf (file, "\tst %s,[%s+%d]\n",
2012: reg_names[i+1], base, offset + 4 * n_fregs),
2013: n_fregs += 2;
2014: }
2015: return n_fregs;
2016: }
2017:
2018: #ifdef __GNUC__
2019: inline
2020: #endif
2021: static int
2022: restore_regs (file, low, high, base, offset, n_fregs)
2023: FILE *file;
2024: int low, high;
2025: char *base;
2026: int offset;
2027: {
2028: int i;
2029:
2030: for (i = low; i < high; i += 2)
2031: {
2032: if (regs_ever_live[i] && ! call_used_regs[i])
2033: if (regs_ever_live[i+1] && ! call_used_regs[i+1])
2034: fprintf (file, "\tldd [%s+%d], %s\n",
2035: base, offset + 4 * n_fregs, reg_names[i]),
2036: n_fregs += 2;
2037: else
2038: fprintf (file, "\tld [%s+%d],%s\n",
2039: base, offset + 4 * n_fregs, reg_names[i]),
2040: n_fregs += 2;
2041: else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
2042: fprintf (file, "\tld [%s+%d],%s\n",
2043: base, offset + 4 * n_fregs, reg_names[i+1]),
2044: n_fregs += 2;
2045: }
2046: return n_fregs;
2047: }
2048:
2049: /* Static variables we want to share between prologue and epilogue. */
2050:
2051: /* Number of live floating point registers needed to be saved. */
2052: static int num_fregs;
2053:
2054: /* Nonzero if any floating point register was ever used. */
2055: static int fregs_ever_live;
2056:
2057: int
2058: compute_frame_size (size, leaf_function)
2059: int size;
2060: int leaf_function;
2061: {
2062: int fregs_ever_live = 0;
2063: int n_fregs = 0, i;
2064: int outgoing_args_size = (current_function_outgoing_args_size
2065: + REG_PARM_STACK_SPACE (current_function_decl));
2066:
2067: apparent_fsize = ((size) + 7 - STARTING_FRAME_OFFSET) & -8;
2068: for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2)
2069: fregs_ever_live |= regs_ever_live[i]|regs_ever_live[i+1];
2070:
2071: if (TARGET_EPILOGUE && fregs_ever_live)
2072: {
2073: for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2)
2074: if ((regs_ever_live[i] && ! call_used_regs[i])
2075: || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
2076: n_fregs += 2;
2077: }
2078:
2079: /* Set up values for use in `function_epilogue'. */
2080: num_fregs = n_fregs;
2081:
2082: apparent_fsize += (outgoing_args_size+7) & -8;
2083: if (leaf_function && n_fregs == 0
2084: && apparent_fsize == (REG_PARM_STACK_SPACE (current_function_decl)
2085: - STARTING_FRAME_OFFSET))
2086: apparent_fsize = 0;
2087:
2088: actual_fsize = apparent_fsize + n_fregs*4;
2089:
2090: /* Make sure nothing can clobber our register windows.
2091: If a SAVE must be done, or there is a stack-local variable,
2092: the register window area must be allocated. */
2093: if (leaf_function == 0 || size > 0)
2094: actual_fsize += (16 * UNITS_PER_WORD)+8;
2095:
2096: return actual_fsize;
2097: }
2098:
1.1.1.3 ! root 2099: /* Output code for the function prologue. */
! 2100:
1.1 root 2101: void
2102: output_function_prologue (file, size, leaf_function)
2103: FILE *file;
2104: int size;
1.1.1.3 ! root 2105: int leaf_function;
1.1 root 2106: {
2107: if (leaf_function)
2108: frame_base_name = "%sp+80";
2109: else
2110: frame_base_name = "%fp";
2111:
1.1.1.3 ! root 2112: /* Need to use actual_fsize, since we are also allocating
! 2113: space for our callee (and our own register save area). */
1.1 root 2114: actual_fsize = compute_frame_size (size, leaf_function);
2115:
2116: fprintf (file, "\t!#PROLOGUE# 0\n");
1.1.1.3 ! root 2117: if (actual_fsize == 0)
! 2118: /* do nothing. */ ;
! 2119: else if (actual_fsize <= 4096)
1.1 root 2120: {
2121: if (! leaf_function)
2122: fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize);
2123: else
2124: fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize);
2125: }
1.1.1.3 ! root 2126: else if (actual_fsize <= 8192)
1.1 root 2127: {
1.1.1.3 ! root 2128: /* For frames in the range 4097..8192, we can use just two insns. */
! 2129: if (! leaf_function)
! 2130: {
! 2131: fprintf (file, "\tsave %%sp,-4096,%%sp\n");
! 2132: fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
! 2133: }
! 2134: else
! 2135: {
! 2136: fprintf (file, "\tadd %%sp,-4096,%%sp\n");
! 2137: fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
! 2138: }
1.1 root 2139: }
2140: else
2141: {
1.1.1.3 ! root 2142: if (! leaf_function)
! 2143: {
! 2144: fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize);
! 2145: if ((actual_fsize & 0x3ff) != 0)
! 2146: fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize);
! 2147: fprintf (file, "\tsave %%sp,%%g1,%%sp\n");
! 2148: }
! 2149: else
! 2150: {
! 2151: fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize);
! 2152: if ((actual_fsize & 0x3ff) != 0)
! 2153: fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize);
! 2154: fprintf (file, "\tadd %%sp,%%g1,%%sp\n");
! 2155: }
1.1 root 2156: }
2157:
2158: /* If doing anything with PIC, do it now. */
2159: if (! flag_pic)
2160: fprintf (file, "\t!#PROLOGUE# 1\n");
2161:
2162: /* Figure out where to save any special registers. */
2163: if (num_fregs)
2164: {
2165: int offset, n_fregs = num_fregs;
2166:
2167: if (! leaf_function)
2168: offset = -apparent_fsize;
2169: else
2170: offset = 0;
2171:
2172: if (TARGET_EPILOGUE && ! leaf_function)
2173: n_fregs = save_regs (file, 0, 16, frame_base_name, offset, 0);
2174: else if (leaf_function)
2175: n_fregs = save_regs (file, 0, 32, frame_base_name, offset, 0);
2176: if (TARGET_EPILOGUE)
2177: save_regs (file, 32, FIRST_PSEUDO_REGISTER,
2178: frame_base_name, offset, n_fregs);
2179: }
2180:
2181: if (regs_ever_live[62])
2182: fprintf (file, "\tst %s,[%s-16]\n\tst %s,[%s-12]\n",
2183: reg_names[0], frame_base_name,
2184: reg_names[0], frame_base_name);
2185:
2186: leaf_label = 0;
2187: if (leaf_function && actual_fsize != 0)
2188: {
2189: /* warning ("leaf procedure with frame size %d", actual_fsize); */
2190: if (! TARGET_EPILOGUE)
2191: leaf_label = gen_label_rtx ();
2192: }
2193: }
2194:
1.1.1.3 ! root 2195: /* Output code for the function epilogue. */
! 2196:
1.1 root 2197: void
1.1.1.3 ! root 2198: output_function_epilogue (file, size, leaf_function)
1.1 root 2199: FILE *file;
2200: int size;
1.1.1.3 ! root 2201: int leaf_function;
1.1 root 2202: {
2203: int n_fregs, i;
2204: char *ret;
2205:
2206: if (leaf_label)
2207: {
2208: emit_label_after (leaf_label, get_last_insn ());
2209: final_scan_insn (get_last_insn (), file, 0, 0, 1);
2210: }
2211:
2212: if (num_fregs)
2213: {
2214: int offset, n_fregs = num_fregs;
2215:
2216: if (! leaf_function)
2217: offset = -apparent_fsize;
2218: else
2219: offset = 0;
2220:
2221: if (TARGET_EPILOGUE && ! leaf_function)
2222: n_fregs = restore_regs (file, 0, 16, frame_base_name, offset, 0);
2223: else if (leaf_function)
2224: n_fregs = restore_regs (file, 0, 32, frame_base_name, offset, 0);
2225: if (TARGET_EPILOGUE)
2226: restore_regs (file, 32, FIRST_PSEUDO_REGISTER,
2227: frame_base_name, offset, n_fregs);
2228: }
2229:
2230: /* Work out how to skip the caller's unimp instruction if required. */
2231: if (leaf_function)
2232: ret = (current_function_returns_struct ? "jmp %o7+12" : "retl");
2233: else
2234: ret = (current_function_returns_struct ? "jmp %i7+12" : "ret");
2235:
1.1.1.3 ! root 2236: if (TARGET_EPILOGUE || leaf_label)
1.1 root 2237: {
1.1.1.3 ! root 2238: int old_target_epilogue = TARGET_EPILOGUE;
! 2239: target_flags &= ~old_target_epilogue;
1.1 root 2240:
1.1.1.3 ! root 2241: if (! leaf_function)
! 2242: {
! 2243: /* If we wound up with things in our delay slot, flush them here. */
! 2244: if (current_function_epilogue_delay_list)
1.1 root 2245: {
1.1.1.3 ! root 2246: rtx insn = emit_jump_insn_after (gen_rtx (RETURN, VOIDmode),
! 2247: get_last_insn ());
! 2248: PATTERN (insn) = gen_rtx (PARALLEL, VOIDmode,
! 2249: gen_rtvec (2,
! 2250: PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
! 2251: PATTERN (insn)));
! 2252: final_scan_insn (insn, file, 1, 0, 1);
1.1 root 2253: }
2254: else
1.1.1.3 ! root 2255: fprintf (file, "\t%s\n\trestore\n", ret);
1.1 root 2256: }
1.1.1.3 ! root 2257: /* All of the following cases are for leaf functions. */
! 2258: else if (current_function_epilogue_delay_list)
1.1 root 2259: {
1.1.1.3 ! root 2260: /* eligible_for_epilogue_delay_slot ensures that if this is a
! 2261: leaf function, then we will only have insn in the delay slot
! 2262: if the frame size is zero, thus no adjust for the stack is
! 2263: needed here. */
! 2264: if (actual_fsize != 0)
! 2265: abort ();
! 2266: fprintf (file, "\t%s\n", ret);
! 2267: final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
! 2268: file, 1, 0, 1);
! 2269: }
! 2270: else if (actual_fsize <= 4096)
! 2271: fprintf (file, "\t%s\n\tsub %%sp,-%d,%%sp\n", ret, actual_fsize);
! 2272: else if (actual_fsize <= 8192)
! 2273: fprintf (file, "\tsub %%sp,-4096,%%sp\n\t%s\n\tsub %%sp,-%d,%%sp\n",
! 2274: ret, actual_fsize - 4096);
! 2275: else if ((actual_fsize & 0x3ff) == 0)
! 2276: fprintf (file, "\tsethi %%hi(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
! 2277: actual_fsize, ret);
! 2278: else
! 2279: fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
! 2280: actual_fsize, actual_fsize, ret);
! 2281: target_flags |= old_target_epilogue;
1.1 root 2282: }
2283: }
2284:
2285: /* Return the string to output a conditional branch to LABEL, which is
2286: the operand number of the label. OP is the conditional expression. The
2287: mode of register 0 says what kind of comparison we made.
2288:
2289: REVERSED is non-zero if we should reverse the sense of the comparison.
2290:
2291: ANNUL is non-zero if we should generate an annulling branch.
2292:
2293: NOOP is non-zero if we have to follow this branch by a noop. */
2294:
2295: char *
2296: output_cbranch (op, label, reversed, annul, noop)
2297: rtx op;
2298: int label;
2299: int reversed, annul, noop;
2300: {
2301: static char string[20];
2302: enum rtx_code code = GET_CODE (op);
2303: enum machine_mode mode = GET_MODE (XEXP (op, 0));
2304: static char labelno[] = " %lX";
2305:
1.1.1.2 root 2306: /* ??? FP branches can not be preceded by another floating point insn.
1.1 root 2307: Because there is currently no concept of pre-delay slots, we can fix
2308: this only by always emitting a nop before a floating point branch. */
2309:
1.1.1.3 ! root 2310: if (mode == CCFPmode || mode == CCFPEmode)
1.1 root 2311: strcpy (string, "nop\n\t");
2312:
2313: /* If not floating-point or if EQ or NE, we can just reverse the code. */
1.1.1.3 ! root 2314: if (reversed
! 2315: && ((mode != CCFPmode && mode != CCFPEmode) || code == EQ || code == NE))
1.1 root 2316: code = reverse_condition (code), reversed = 0;
2317:
2318: /* Start by writing the branch condition. */
2319: switch (code)
2320: {
2321: case NE:
1.1.1.3 ! root 2322: if (mode == CCFPmode || mode == CCFPEmode)
1.1 root 2323: strcat (string, "fbne");
2324: else
2325: strcpy (string, "bne");
2326: break;
2327:
2328: case EQ:
1.1.1.3 ! root 2329: if (mode == CCFPmode || mode == CCFPEmode)
1.1 root 2330: strcat (string, "fbe");
2331: else
2332: strcpy (string, "be");
2333: break;
2334:
2335: case GE:
1.1.1.3 ! root 2336: if (mode == CCFPmode || mode == CCFPEmode)
1.1 root 2337: {
2338: if (reversed)
2339: strcat (string, "fbul");
2340: else
2341: strcat (string, "fbge");
2342: }
2343: else if (mode == CC_NOOVmode)
2344: strcpy (string, "bpos");
2345: else
2346: strcpy (string, "bge");
2347: break;
2348:
2349: case GT:
1.1.1.3 ! root 2350: if (mode == CCFPmode || mode == CCFPEmode)
1.1 root 2351: {
2352: if (reversed)
2353: strcat (string, "fbule");
2354: else
2355: strcat (string, "fbg");
2356: }
2357: else
2358: strcpy (string, "bg");
2359: break;
2360:
2361: case LE:
1.1.1.3 ! root 2362: if (mode == CCFPmode || mode == CCFPEmode)
1.1 root 2363: {
2364: if (reversed)
2365: strcat (string, "fbug");
2366: else
2367: strcat (string, "fble");
2368: }
2369: else
2370: strcpy (string, "ble");
2371: break;
2372:
2373: case LT:
1.1.1.3 ! root 2374: if (mode == CCFPmode || mode == CCFPEmode)
1.1 root 2375: {
2376: if (reversed)
2377: strcat (string, "fbuge");
2378: else
2379: strcat (string, "fbl");
2380: }
2381: else if (mode == CC_NOOVmode)
2382: strcpy (string, "bneg");
2383: else
2384: strcpy (string, "bl");
2385: break;
2386:
2387: case GEU:
2388: strcpy (string, "bgeu");
2389: break;
2390:
2391: case GTU:
2392: strcpy (string, "bgu");
2393: break;
2394:
2395: case LEU:
2396: strcpy (string, "bleu");
2397: break;
2398:
2399: case LTU:
2400: strcpy (string, "blu");
2401: break;
2402: }
2403:
2404: /* Now add the annulling, the label, and a possible noop. */
2405: if (annul)
2406: strcat (string, ",a");
2407:
2408: labelno[3] = label + '0';
2409: strcat (string, labelno);
2410:
2411: if (noop)
2412: strcat (string, "\n\tnop");
2413:
2414: return string;
2415: }
2416:
1.1.1.3 ! root 2417: /* Output assembler code to return from a function. */
! 2418:
1.1 root 2419: char *
2420: output_return (operands)
2421: rtx *operands;
2422: {
2423: if (leaf_label)
2424: {
2425: operands[0] = leaf_label;
2426: return "b,a %l0";
2427: }
2428: else if (leaf_function)
2429: {
1.1.1.3 ! root 2430: /* If we didn't allocate a frame pointer for the current function,
! 2431: the stack pointer might have been adjusted. Output code to
! 2432: restore it now. */
! 2433:
1.1 root 2434: operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize);
1.1.1.3 ! root 2435:
! 2436: /* Use sub of negated value in first two cases instead of add to
! 2437: allow actual_fsize == 4096. */
! 2438:
! 2439: if (actual_fsize <= 4096)
1.1 root 2440: {
2441: if (current_function_returns_struct)
1.1.1.3 ! root 2442: return "jmp %%o7+12\n\tsub %%sp,-%0,%%sp";
1.1 root 2443: else
1.1.1.3 ! root 2444: return "retl\n\tsub %%sp,-%0,%%sp";
1.1 root 2445: }
1.1.1.3 ! root 2446: else if (actual_fsize <= 8192)
1.1 root 2447: {
1.1.1.3 ! root 2448: operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize - 4096);
1.1 root 2449: if (current_function_returns_struct)
1.1.1.3 ! root 2450: return "sub %%sp,-4096,%%sp\n\tjmp %%o7+12\n\tsub %%sp,-%0,%%sp";
! 2451: else
! 2452: return "sub %%sp,-4096,%%sp\n\tretl\n\tsub %%sp,-%0,%%sp";
! 2453: }
! 2454: else if (current_function_returns_struct)
! 2455: {
! 2456: if ((actual_fsize & 0x3ff) != 0)
1.1 root 2457: return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
2458: else
1.1.1.3 ! root 2459: return "sethi %%hi(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
! 2460: }
! 2461: else
! 2462: {
! 2463: if ((actual_fsize & 0x3ff) != 0)
1.1 root 2464: return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
1.1.1.3 ! root 2465: else
! 2466: return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
1.1 root 2467: }
2468: }
2469: else
2470: {
2471: if (current_function_returns_struct)
2472: return "jmp %%i7+12\n\trestore";
2473: else
2474: return "ret\n\trestore";
2475: }
2476: }
2477:
1.1.1.3 ! root 2478: /* Output assembler code for a SImode to SFmode conversion. */
! 2479:
1.1 root 2480: char *
2481: output_floatsisf2 (operands)
2482: rtx *operands;
2483: {
2484: if (GET_CODE (operands[1]) == MEM)
2485: return "ld %1,%0\n\tfitos %0,%0";
2486: else if (FP_REG_P (operands[1]))
2487: return "fitos %1,%0";
2488: return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitos %0,%0";
2489: }
2490:
1.1.1.3 ! root 2491: /* Output assembler code for a SImode to DFmode conversion. */
! 2492:
1.1 root 2493: char *
2494: output_floatsidf2 (operands)
2495: rtx *operands;
2496: {
2497: if (GET_CODE (operands[1]) == MEM)
2498: return "ld %1,%0\n\tfitod %0,%0";
2499: else if (FP_REG_P (operands[1]))
2500: return "fitod %1,%0";
2501: return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitod %0,%0";
2502: }
2503:
1.1.1.3 ! root 2504: /* Output assembler code for a SImode to TFmode conversion. */
1.1 root 2505:
1.1.1.3 ! root 2506: char *
! 2507: output_floatsitf2 (operands)
! 2508: rtx *operands;
! 2509: {
! 2510: if (GET_CODE (operands[1]) == MEM)
! 2511: return "ld %1,%0\n\tfitoq %0,%0";
! 2512: else if (FP_REG_P (operands[1]))
! 2513: return "fitoq %1,%0";
! 2514: return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitoq %0,%0";
1.1 root 2515: }
2516:
2517: /* Leaf functions and non-leaf functions have different needs. */
2518:
2519: static int
2520: reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER;
2521:
2522: static int
2523: reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER;
2524:
2525: static int *reg_alloc_orders[] = {
2526: reg_leaf_alloc_order,
2527: reg_nonleaf_alloc_order};
2528:
2529: void
2530: order_regs_for_local_alloc ()
2531: {
2532: static int last_order_nonleaf = 1;
2533:
2534: if (regs_ever_live[15] != last_order_nonleaf)
2535: {
2536: last_order_nonleaf = !last_order_nonleaf;
2537: bcopy (reg_alloc_orders[last_order_nonleaf], reg_alloc_order,
2538: FIRST_PSEUDO_REGISTER * sizeof (int));
2539: }
2540: }
2541:
2542: /* Machine dependent routines for the branch probability, arc profiling
2543: code. */
2544:
2545: /* The label used by the arc profiling code. */
2546:
2547: static rtx profiler_label;
2548:
2549: void
2550: init_arc_profiler ()
2551: {
2552: /* Generate and save a copy of this so it can be shared. */
2553: profiler_label = gen_rtx (SYMBOL_REF, Pmode, "*LPBX2");
2554: }
2555:
2556: void
2557: output_arc_profiler (arcno, insert_after)
2558: int arcno;
2559: rtx insert_after;
2560: {
2561: rtx profiler_target_addr
2562: = gen_rtx (CONST, Pmode,
2563: gen_rtx (PLUS, Pmode, profiler_label,
2564: gen_rtx (CONST_INT, VOIDmode, 4 * arcno)));
2565: register rtx profiler_reg = gen_reg_rtx (SImode);
1.1.1.2 root 2566: register rtx address_reg = gen_reg_rtx (Pmode);
2567: rtx mem_ref;
2568:
2569: insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, address_reg,
2570: gen_rtx (HIGH, Pmode,
2571: profiler_target_addr)),
2572: insert_after);
2573:
2574: mem_ref = gen_rtx (MEM, SImode, gen_rtx (LO_SUM, Pmode, address_reg,
2575: profiler_target_addr));
2576: insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg,
2577: mem_ref),
2578: insert_after);
2579:
2580: insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg,
2581: gen_rtx (PLUS, SImode, profiler_reg,
2582: const1_rtx)),
2583: insert_after);
2584:
2585: /* This is the same rtx as above, but it is not legal to share this rtx. */
2586: mem_ref = gen_rtx (MEM, SImode, gen_rtx (LO_SUM, Pmode, address_reg,
2587: profiler_target_addr));
2588: emit_insn_after (gen_rtx (SET, VOIDmode, mem_ref, profiler_reg),
1.1 root 2589: insert_after);
2590: }
1.1.1.3 ! root 2591:
! 2592: /* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
! 2593: This makes them candidates for using ldd and std insns.
! 2594:
! 2595: Note reg1 and reg2 *must* be hard registers. To be sure we will
! 2596: abort if we are passed pseudo registers. */
! 2597:
! 2598: int
! 2599: registers_ok_for_ldd (reg1, reg2)
! 2600: rtx reg1, reg2;
1.1 root 2601: {
2602:
1.1.1.3 ! root 2603: /* We might have been passed a SUBREG. */
! 2604: if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
! 2605: return 0;
! 2606:
! 2607: /* Should never happen. */
! 2608: if (REGNO (reg1) > FIRST_PSEUDO_REGISTER
! 2609: || REGNO (reg2) > FIRST_PSEUDO_REGISTER)
! 2610: abort ();
! 2611:
! 2612: if (REGNO (reg1) % 2 != 0)
! 2613: return 0;
! 2614:
! 2615: return (REGNO (reg1) == REGNO (reg2) - 1);
! 2616:
! 2617: }
! 2618:
! 2619: /* Return 1 if addr1 and addr2 are suitable for use in an ldd or
! 2620: std insn.
1.1 root 2621:
1.1.1.3 ! root 2622: This can only happen when addr1 and addr2 are consecutive memory
! 2623: locations (addr1 + 4 == addr2). addr1 must also be aligned on a
! 2624: 64 bit boundary (addr1 % 8 == 0).
1.1 root 2625:
1.1.1.3 ! root 2626: We know %sp and %fp are kept aligned on a 64 bit boundary. Other
! 2627: registers are assumed to *never* be properly aligned and are
! 2628: rejected.
1.1 root 2629:
1.1.1.3 ! root 2630: Knowing %sp and %fp are kept aligned on a 64 bit boundary, we
! 2631: need only check that the offset for addr1 % 8 == 0. */
! 2632:
! 2633: int
! 2634: memory_ok_for_ldd (addr1, addr2)
! 2635: rtx addr1, addr2;
! 2636: {
! 2637: int reg1, offset1;
1.1 root 2638:
1.1.1.3 ! root 2639: /* Extract a register number and offset (if used) from the first addr. */
! 2640: if (GET_CODE (addr1) == PLUS)
1.1 root 2641: {
1.1.1.3 ! root 2642: /* If not a REG, return zero. */
! 2643: if (GET_CODE (XEXP (addr1, 0)) != REG)
! 2644: return 0;
1.1 root 2645: else
1.1.1.3 ! root 2646: {
! 2647: reg1 = REGNO (XEXP (addr1, 0));
! 2648: /* The offset must be constant! */
! 2649: if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
! 2650: return 0;
! 2651: offset1 = INTVAL (XEXP (addr1, 1));
! 2652: }
1.1 root 2653: }
1.1.1.3 ! root 2654: else if (GET_CODE (addr1) != REG)
! 2655: return 0;
1.1 root 2656: else
2657: {
1.1.1.3 ! root 2658: reg1 = REGNO (addr1);
! 2659: /* This was a simple (mem (reg)) expression. Offset is 0. */
! 2660: offset1 = 0;
1.1 root 2661: }
1.1.1.3 ! root 2662:
! 2663: /* Make sure the second address is a (mem (plus (reg) (const_int). */
! 2664: if (GET_CODE (addr2) != PLUS)
! 2665: return 0;
! 2666:
! 2667: if (GET_CODE (XEXP (addr2, 0)) != REG
! 2668: || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
! 2669: return 0;
! 2670:
! 2671: /* Only %fp and %sp are allowed. Additionally both addresses must
! 2672: use the same register. */
! 2673: if (reg1 != FRAME_POINTER_REGNUM && reg1 != STACK_POINTER_REGNUM)
! 2674: return 0;
! 2675:
! 2676: if (reg1 != REGNO (XEXP (addr2, 0)))
! 2677: return 0;
! 2678:
! 2679: /* The first offset must be evenly divisable by 8 to ensure the
! 2680: address is 64 bit aligned. */
! 2681: if (offset1 % 8 != 0)
! 2682: return 0;
! 2683:
! 2684: /* The offset for the second addr must be 4 more than the first addr. */
! 2685: if (INTVAL (XEXP (addr2, 1)) != offset1 + 4)
! 2686: return 0;
! 2687:
! 2688: /* All the tests passed. addr1 and addr2 are valid for ldd and std
! 2689: instructions. */
! 2690: return 1;
1.1 root 2691: }
2692:
2693: /* Print operand X (an rtx) in assembler syntax to file FILE.
2694: CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
2695: For `%' followed by punctuation, CODE is the punctuation and X is null. */
2696:
2697: void
2698: print_operand (file, x, code)
2699: FILE *file;
2700: rtx x;
2701: int code;
2702: {
2703: switch (code)
2704: {
2705: case '#':
2706: /* Output a 'nop' if there's nothing for the delay slot. */
2707: if (dbr_sequence_length () == 0)
2708: fputs ("\n\tnop", file);
2709: return;
2710: case '*':
2711: /* Output an annul flag if there's nothing for the delay slot. */
2712: if (dbr_sequence_length () == 0)
2713: fputs (",a", file);
2714: return;
2715: case 'Y':
2716: /* Adjust the operand to take into account a RESTORE operation. */
2717: if (GET_CODE (x) != REG)
2718: abort ();
2719: if (REGNO (x) < 8)
2720: fputs (reg_names[REGNO (x)], file);
2721: else if (REGNO (x) >= 24 && REGNO (x) < 32)
2722: fputs (reg_names[REGNO (x)-16], file);
2723: else
2724: abort ();
2725: return;
2726: case '@':
2727: /* Print out what we are using as the frame pointer. This might
2728: be %fp, or might be %sp+offset. */
2729: fputs (frame_base_name, file);
2730: return;
2731: case 'R':
1.1.1.3 ! root 2732: /* Print out the second register name of a register pair or quad.
1.1 root 2733: I.e., R (%o0) => %o1. */
2734: fputs (reg_names[REGNO (x)+1], file);
2735: return;
1.1.1.3 ! root 2736: case 'S':
! 2737: /* Print out the third register name of a register quad.
! 2738: I.e., S (%o0) => %o2. */
! 2739: fputs (reg_names[REGNO (x)+2], file);
! 2740: return;
! 2741: case 'T':
! 2742: /* Print out the fourth register name of a register quad.
! 2743: I.e., T (%o0) => %o3. */
! 2744: fputs (reg_names[REGNO (x)+3], file);
! 2745: return;
1.1 root 2746: case 'm':
2747: /* Print the operand's address only. */
2748: output_address (XEXP (x, 0));
2749: return;
2750: case 'r':
2751: /* In this case we need a register. Use %g0 if the
1.1.1.3 ! root 2752: operand is const0_rtx. */
! 2753: if (x == const0_rtx
! 2754: || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
1.1 root 2755: {
2756: fputs ("%g0", file);
2757: return;
2758: }
2759: else
2760: break;
2761:
2762: case 'A':
2763: switch (GET_CODE (x))
2764: {
2765: case IOR: fputs ("or", file); break;
2766: case AND: fputs ("and", file); break;
2767: case XOR: fputs ("xor", file); break;
2768: default: abort ();
2769: }
2770: return;
2771:
2772: case 'B':
2773: switch (GET_CODE (x))
2774: {
2775: case IOR: fputs ("orn", file); break;
2776: case AND: fputs ("andn", file); break;
2777: case XOR: fputs ("xnor", file); break;
2778: default: abort ();
2779: }
2780: return;
2781:
2782: case 'b':
2783: {
2784: /* Print a sign-extended character. */
2785: int i = INTVAL (x) & 0xff;
2786: if (i & 0x80)
2787: i |= 0xffffff00;
2788: fprintf (file, "%d", i);
2789: return;
2790: }
2791:
2792: case 0:
2793: /* Do nothing special. */
2794: break;
2795:
2796: default:
2797: /* Undocumented flag. */
2798: abort ();
2799: }
2800:
2801: if (GET_CODE (x) == REG)
2802: fputs (reg_names[REGNO (x)], file);
2803: else if (GET_CODE (x) == MEM)
2804: {
2805: fputc ('[', file);
2806: if (CONSTANT_P (XEXP (x, 0)))
2807: /* Poor Sun assembler doesn't understand absolute addressing. */
2808: fputs ("%g0+", file);
2809: output_address (XEXP (x, 0));
2810: fputc (']', file);
2811: }
2812: else if (GET_CODE (x) == HIGH)
2813: {
2814: fputs ("%hi(", file);
2815: output_addr_const (file, XEXP (x, 0));
2816: fputc (')', file);
2817: }
2818: else if (GET_CODE (x) == LO_SUM)
2819: {
2820: print_operand (file, XEXP (x, 0), 0);
2821: fputs ("+%lo(", file);
2822: output_addr_const (file, XEXP (x, 1));
2823: fputc (')', file);
2824: }
2825: else if (GET_CODE (x) == CONST_DOUBLE)
2826: {
2827: if (CONST_DOUBLE_HIGH (x) == 0)
2828: fprintf (file, "%u", CONST_DOUBLE_LOW (x));
2829: else if (CONST_DOUBLE_HIGH (x) == -1
2830: && CONST_DOUBLE_LOW (x) < 0)
2831: fprintf (file, "%d", CONST_DOUBLE_LOW (x));
2832: else
2833: abort ();
2834: }
2835: else { output_addr_const (file, x); }
2836: }
2837:
2838: /* This function outputs assembler code for VALUE to FILE, where VALUE is
2839: a 64 bit (DImode) value. */
2840:
2841: /* ??? If there is a 64 bit counterpart to .word that the assembler
2842: understands, then using that would simply this code greatly. */
2843:
2844: void
2845: output_double_int (file, value)
2846: FILE *file;
2847: rtx value;
2848: {
2849: if (GET_CODE (value) == CONST_INT)
2850: {
2851: if (INTVAL (value) < 0)
2852: ASM_OUTPUT_INT (file, constm1_rtx);
2853: else
2854: ASM_OUTPUT_INT (file, const0_rtx);
2855: ASM_OUTPUT_INT (file, value);
2856: }
2857: else if (GET_CODE (value) == CONST_DOUBLE)
2858: {
2859: ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode,
2860: CONST_DOUBLE_HIGH (value)));
2861: ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode,
2862: CONST_DOUBLE_LOW (value)));
2863: }
2864: else if (GET_CODE (value) == SYMBOL_REF
2865: || GET_CODE (value) == CONST
2866: || GET_CODE (value) == PLUS)
2867: {
2868: /* Addresses are only 32 bits. */
2869: ASM_OUTPUT_INT (file, const0_rtx);
2870: ASM_OUTPUT_INT (file, value);
2871: }
2872: else
2873: abort ();
2874: }
1.1.1.3 ! root 2875:
! 2876: #ifndef CHAR_TYPE_SIZE
! 2877: #define CHAR_TYPE_SIZE BITS_PER_UNIT
! 2878: #endif
! 2879:
! 2880: #ifndef SHORT_TYPE_SIZE
! 2881: #define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2)
! 2882: #endif
! 2883:
! 2884: #ifndef INT_TYPE_SIZE
! 2885: #define INT_TYPE_SIZE BITS_PER_WORD
! 2886: #endif
! 2887:
! 2888: #ifndef LONG_TYPE_SIZE
! 2889: #define LONG_TYPE_SIZE BITS_PER_WORD
! 2890: #endif
! 2891:
! 2892: #ifndef LONG_LONG_TYPE_SIZE
! 2893: #define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
! 2894: #endif
! 2895:
! 2896: #ifndef FLOAT_TYPE_SIZE
! 2897: #define FLOAT_TYPE_SIZE BITS_PER_WORD
! 2898: #endif
! 2899:
! 2900: #ifndef DOUBLE_TYPE_SIZE
! 2901: #define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
! 2902: #endif
! 2903:
! 2904: #ifndef LONG_DOUBLE_TYPE_SIZE
! 2905: #define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
! 2906: #endif
! 2907:
! 2908: unsigned long
! 2909: sparc_type_code (type)
! 2910: register tree type;
! 2911: {
! 2912: register unsigned long qualifiers = 0;
! 2913: register unsigned shift = 6;
! 2914:
! 2915: for (;;)
! 2916: {
! 2917: switch (TREE_CODE (type))
! 2918: {
! 2919: case ERROR_MARK:
! 2920: return qualifiers;
! 2921:
! 2922: case ARRAY_TYPE:
! 2923: qualifiers |= (3 << shift);
! 2924: shift += 2;
! 2925: type = TREE_TYPE (type);
! 2926: break;
! 2927:
! 2928: case FUNCTION_TYPE:
! 2929: case METHOD_TYPE:
! 2930: qualifiers |= (2 << shift);
! 2931: shift += 2;
! 2932: type = TREE_TYPE (type);
! 2933: break;
! 2934:
! 2935: case POINTER_TYPE:
! 2936: case REFERENCE_TYPE:
! 2937: case OFFSET_TYPE:
! 2938: qualifiers |= (1 << shift);
! 2939: shift += 2;
! 2940: type = TREE_TYPE (type);
! 2941: break;
! 2942:
! 2943: case RECORD_TYPE:
! 2944: return (qualifiers | 8);
! 2945:
! 2946: case UNION_TYPE:
! 2947: return (qualifiers | 9);
! 2948:
! 2949: case ENUMERAL_TYPE:
! 2950: return (qualifiers | 10);
1.1 root 2951:
1.1.1.3 ! root 2952: case VOID_TYPE:
! 2953: return (qualifiers | 16);
! 2954:
! 2955: case INTEGER_TYPE:
! 2956: /* Carefully distinguish all the standard types of C,
! 2957: without messing up if the language is not C.
! 2958: Note that we check only for the names that contain spaces;
! 2959: other names might occur by coincidence in other languages. */
! 2960: if (TYPE_NAME (type) != 0
! 2961: && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
! 2962: && DECL_NAME (TYPE_NAME (type)) != 0
! 2963: && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE)
! 2964: {
! 2965: char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
! 2966:
! 2967: if (!strcmp (name, "unsigned char"))
! 2968: return (qualifiers | 12);
! 2969: if (!strcmp (name, "signed char"))
! 2970: return (qualifiers | 2);
! 2971: if (!strcmp (name, "unsigned int"))
! 2972: return (qualifiers | 14);
! 2973: if (!strcmp (name, "short int"))
! 2974: return (qualifiers | 3);
! 2975: if (!strcmp (name, "short unsigned int"))
! 2976: return (qualifiers | 13);
! 2977: if (!strcmp (name, "long int"))
! 2978: return (qualifiers | 5);
! 2979: if (!strcmp (name, "long unsigned int"))
! 2980: return (qualifiers | 15);
! 2981: if (!strcmp (name, "long long int"))
! 2982: return (qualifiers | 5); /* Who knows? */
! 2983: if (!strcmp (name, "long long unsigned int"))
! 2984: return (qualifiers | 15); /* Who knows? */
! 2985: }
! 2986:
! 2987: /* Most integer types will be sorted out above, however, for the
! 2988: sake of special `array index' integer types, the following code
! 2989: is also provided. */
! 2990:
! 2991: if (TYPE_PRECISION (type) == INT_TYPE_SIZE)
! 2992: return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4));
! 2993:
! 2994: if (TYPE_PRECISION (type) == LONG_TYPE_SIZE)
! 2995: return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
! 2996:
! 2997: if (TYPE_PRECISION (type) == LONG_LONG_TYPE_SIZE)
! 2998: return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
! 2999:
! 3000: if (TYPE_PRECISION (type) == SHORT_TYPE_SIZE)
! 3001: return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3));
! 3002:
! 3003: if (TYPE_PRECISION (type) == CHAR_TYPE_SIZE)
! 3004: return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2));
! 3005:
! 3006: abort ();
! 3007:
! 3008: case REAL_TYPE:
! 3009: /* Carefully distinguish all the standard types of C,
! 3010: without messing up if the language is not C. */
! 3011: if (TYPE_NAME (type) != 0
! 3012: && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
! 3013: && DECL_NAME (TYPE_NAME (type)) != 0
! 3014: && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE)
! 3015: {
! 3016: char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
! 3017:
! 3018: if (!strcmp (name, "long double"))
! 3019: return (qualifiers | 7); /* Who knows? */
! 3020: }
! 3021:
! 3022: if (TYPE_PRECISION (type) == DOUBLE_TYPE_SIZE)
! 3023: return (qualifiers | 7);
! 3024: if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE)
! 3025: return (qualifiers | 6);
! 3026: if (TYPE_PRECISION (type) == LONG_DOUBLE_TYPE_SIZE)
! 3027: return (qualifiers | 7); /* Who knows? */
! 3028: abort ();
! 3029:
! 3030: case COMPLEX_TYPE: /* GNU Fortran COMPLEX type. */
! 3031: case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */
! 3032: case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */
! 3033: case FILE_TYPE: /* GNU Pascal FILE type. */
! 3034: case STRING_TYPE: /* GNU Fortran STRING type. */
! 3035: case LANG_TYPE: /* ? */
! 3036: abort ();
! 3037:
! 3038: default:
! 3039: abort (); /* Not a type! */
! 3040: }
! 3041: }
! 3042: }
! 3043:
! 3044: #ifdef HANDLE_PRAGMA
! 3045:
! 3046: /* Handle a pragma directive. HANDLE_PRAGMA conspires to parse the
! 3047: input following #pragma into tokens based on yylex. TOKEN is the
! 3048: current token, and STRING is its printable form. */
! 3049:
! 3050: void
! 3051: handle_pragma_token (string, token)
! 3052: char *string;
! 3053: tree token;
! 3054: {
! 3055: static enum pragma_state
! 3056: {
! 3057: ps_start,
! 3058: ps_done,
! 3059: ps_bad,
! 3060: ps_weak,
! 3061: ps_name,
! 3062: ps_equals,
! 3063: ps_value,
! 3064: } state = ps_start, type;
! 3065: static char *name;
! 3066: static char *value;
! 3067: static int align;
! 3068:
! 3069: if (string == 0)
! 3070: {
! 3071: #ifdef WEAK_ASM_OP
! 3072: if (type == ps_weak)
! 3073: {
! 3074: if (state == ps_name || state == ps_value)
! 3075: {
! 3076: fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
! 3077: ASM_OUTPUT_LABELREF (asm_out_file, name);
! 3078: fputc ('\n', asm_out_file);
! 3079: if (state == ps_value)
! 3080: {
! 3081: fputc ('\t', asm_out_file);
! 3082: ASM_OUTPUT_LABELREF (asm_out_file, name);
! 3083: fputs (" = ", asm_out_file);
! 3084: ASM_OUTPUT_LABELREF (asm_out_file, value);
! 3085: fputc ('\n', asm_out_file);
! 3086: }
! 3087: }
! 3088: else if (! (state == ps_done || state == ps_start))
! 3089: warning ("ignoring malformed #pragma weak symbol [=value]");
! 3090: }
! 3091: #endif /* WEAK_ASM_OP */
! 3092:
! 3093: type = state = ps_start;
! 3094: return;
! 3095: }
! 3096:
! 3097: switch (state)
! 3098: {
! 3099: case ps_start:
! 3100: if (token && TREE_CODE (token) == IDENTIFIER_NODE)
! 3101: {
! 3102: #ifdef WEAK_ASM_OP
! 3103: if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
! 3104: type = state = ps_weak;
! 3105: else
! 3106: #endif
! 3107: type = state = ps_done;
! 3108: }
! 3109: else
! 3110: type = state = ps_done;
! 3111: break;
! 3112:
! 3113: #ifdef WEAK_ASM_OP
! 3114: case ps_weak:
! 3115: if (token && TREE_CODE (token) == IDENTIFIER_NODE)
! 3116: {
! 3117: name = IDENTIFIER_POINTER (token);
! 3118: state = ps_name;
! 3119: }
! 3120: else
! 3121: state = ps_bad;
! 3122: break;
! 3123:
! 3124: case ps_name:
! 3125: state = (strcmp (string, "=") ? ps_bad : ps_equals);
! 3126: break;
! 3127:
! 3128: case ps_equals:
! 3129: if (token && TREE_CODE (token) == IDENTIFIER_NODE)
! 3130: {
! 3131: value = IDENTIFIER_POINTER (token);
! 3132: state = ps_value;
! 3133: }
! 3134: else
! 3135: state = ps_bad;
! 3136: break;
! 3137:
! 3138: case ps_value:
! 3139: state = ps_bad;
! 3140: break;
! 3141: #endif /* WEAK_ASM_OP */
! 3142:
! 3143: case ps_bad:
! 3144: case ps_done:
! 3145: break;
! 3146:
! 3147: default:
! 3148: abort ();
! 3149: }
! 3150: }
! 3151: #endif /* HANDLE_PRAGMA */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.