|
|
1.1 root 1: /* Subroutines for insn-output.c for Intel 80386.
2: Copyright (C) 1988 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
6: GNU CC is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 2, or (at your option)
9: any later version.
10:
11: GNU CC is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU CC; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20: #include <stdio.h>
21: #include "config.h"
22: #include "rtl.h"
23: #include "regs.h"
24: #include "hard-reg-set.h"
25: #include "real.h"
26: #include "insn-config.h"
27: #include "conditions.h"
28: #include "insn-flags.h"
29: #include "output.h"
30: #include "insn-attr.h"
31: #include "tree.h"
32: #include "flags.h"
33:
1.1.1.2 root 34: #ifdef EXTRA_CONSTRAINT
35: /* If EXTRA_CONSTRAINT is defined, then the 'S'
36: constraint in REG_CLASS_FROM_LETTER will no longer work, and various
37: asm statements that need 'S' for class SIREG will break. */
38: #error EXTRA_CONSTRAINT conflicts with S constraint letter
39: #endif
40:
1.1 root 41: #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
42:
43: extern FILE *asm_out_file;
44: extern char *strcat ();
45:
46: char *singlemove_string ();
47: char *output_move_const_single ();
1.1.1.3 ! root 48: char *output_fp_cc0_set ();
1.1 root 49:
50: static char *hi_reg_name[] = HI_REGISTER_NAMES;
51: static char *qi_reg_name[] = QI_REGISTER_NAMES;
52: static char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
53:
54: /* Array of the smallest class containing reg number REGNO, indexed by
55: REGNO. Used by REGNO_REG_CLASS in i386.h. */
56:
57: enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
58: {
59: /* ax, dx, cx, bx */
1.1.1.2 root 60: AREG, DREG, CREG, BREG,
1.1 root 61: /* si, di, bp, sp */
62: SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
63: /* FP registers */
64: FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
65: FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
66: /* arg pointer */
67: INDEX_REGS
68: };
1.1.1.3 ! root 69:
! 70: /* Test and compare insns in i386.md store the information needed to
! 71: generate branch and scc insns here. */
! 72:
! 73: struct rtx_def *i386_compare_op0, *i386_compare_op1;
! 74: struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
1.1 root 75:
76: /* Output an insn whose source is a 386 integer register. SRC is the
77: rtx for the register, and TEMPLATE is the op-code template. SRC may
78: be either SImode or DImode.
79:
80: The template will be output with operands[0] as SRC, and operands[1]
81: as a pointer to the top of the 386 stack. So a call from floatsidf2
82: would look like this:
83:
84: output_op_from_reg (operands[1], AS1 (fild%z0,%1));
85:
86: where %z0 corresponds to the caller's operands[1], and is used to
87: emit the proper size suffix.
88:
89: ??? Extend this to handle HImode - a 387 can load and store HImode
90: values directly. */
91:
92: void
93: output_op_from_reg (src, template)
94: rtx src;
95: char *template;
96: {
97: rtx xops[4];
98:
99: xops[0] = src;
100: xops[1] = AT_SP (Pmode);
101: xops[2] = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (src)));
102: xops[3] = stack_pointer_rtx;
103:
104: if (GET_MODE_SIZE (GET_MODE (src)) > UNITS_PER_WORD)
105: {
106: rtx high = gen_rtx (REG, SImode, REGNO (src) + 1);
107: output_asm_insn (AS1 (push%L0,%0), &high);
108: }
109: output_asm_insn (AS1 (push%L0,%0), &src);
110:
111: output_asm_insn (template, xops);
112:
113: output_asm_insn (AS2 (add%L3,%2,%3), xops);
114: }
115:
116: /* Output an insn to pop an value from the 387 top-of-stack to 386
117: register DEST. The 387 register stack is popped if DIES is true. If
118: the mode of DEST is an integer mode, a `fist' integer store is done,
119: otherwise a `fst' float store is done. */
120:
121: void
122: output_to_reg (dest, dies)
123: rtx dest;
124: int dies;
125: {
126: rtx xops[4];
127:
128: xops[0] = AT_SP (Pmode);
129: xops[1] = stack_pointer_rtx;
130: xops[2] = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (dest)));
131: xops[3] = dest;
132:
133: output_asm_insn (AS2 (sub%L1,%2,%1), xops);
134:
135: if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
136: {
137: if (dies)
138: output_asm_insn (AS1 (fistp%z3,%y0), xops);
139: else
140: output_asm_insn (AS1 (fist%z3,%y0), xops);
141: }
142: else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)
143: {
144: if (dies)
145: output_asm_insn (AS1 (fstp%z3,%y0), xops);
146: else
147: output_asm_insn (AS1 (fst%z3,%y0), xops);
148: }
149: else
150: abort ();
151:
152: output_asm_insn (AS1 (pop%L0,%0), &dest);
153:
154: if (GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD)
155: {
156: dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
157: output_asm_insn (AS1 (pop%L0,%0), &dest);
158: }
159: }
160:
161: char *
162: singlemove_string (operands)
163: rtx *operands;
164: {
165: rtx x;
166: if (GET_CODE (operands[0]) == MEM
167: && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
168: {
169: if (XEXP (x, 0) != stack_pointer_rtx)
170: abort ();
171: return "push%L1 %1";
172: }
173: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
174: {
175: return output_move_const_single (operands);
176: }
177: else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
178: return AS2 (mov%L0,%1,%0);
179: else if (CONSTANT_P (operands[1]))
180: return AS2 (mov%L0,%1,%0);
181: else
182: {
183: output_asm_insn ("push%L1 %1", operands);
184: return "pop%L0 %0";
185: }
186: }
187:
188: /* Return a REG that occurs in ADDR with coefficient 1.
189: ADDR can be effectively incremented by incrementing REG. */
190:
191: static rtx
192: find_addr_reg (addr)
193: rtx addr;
194: {
195: while (GET_CODE (addr) == PLUS)
196: {
197: if (GET_CODE (XEXP (addr, 0)) == REG)
198: addr = XEXP (addr, 0);
199: else if (GET_CODE (XEXP (addr, 1)) == REG)
200: addr = XEXP (addr, 1);
201: else if (CONSTANT_P (XEXP (addr, 0)))
202: addr = XEXP (addr, 1);
203: else if (CONSTANT_P (XEXP (addr, 1)))
204: addr = XEXP (addr, 0);
205: else
206: abort ();
207: }
208: if (GET_CODE (addr) == REG)
209: return addr;
210: abort ();
211: }
212:
213: /* Output an insn to add the constant N to the register X. */
214:
215: static void
216: asm_add (n, x)
217: int n;
218: rtx x;
219: {
220: rtx xops[2];
221: xops[1] = x;
222: if (n < 0)
223: {
224: xops[0] = gen_rtx (CONST_INT, VOIDmode, -n);
225: output_asm_insn (AS2 (sub%L0,%0,%1), xops);
226: }
227: else if (n > 0)
228: {
229: xops[0] = gen_rtx (CONST_INT, VOIDmode, n);
230: output_asm_insn (AS2 (add%L0,%0,%1), xops);
231: }
232: }
233:
234: /* Output assembler code to perform a doubleword move insn
235: with operands OPERANDS. */
236:
237: char *
238: output_move_double (operands)
239: rtx *operands;
240: {
241: enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
242: rtx latehalf[2];
243: rtx addreg0 = 0, addreg1 = 0;
244:
245: /* First classify both operands. */
246:
247: if (REG_P (operands[0]))
248: optype0 = REGOP;
249: else if (offsettable_memref_p (operands[0]))
250: optype0 = OFFSOP;
251: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
252: optype0 = POPOP;
253: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
254: optype0 = PUSHOP;
255: else if (GET_CODE (operands[0]) == MEM)
256: optype0 = MEMOP;
257: else
258: optype0 = RNDOP;
259:
260: if (REG_P (operands[1]))
261: optype1 = REGOP;
262: else if (CONSTANT_P (operands[1]))
263: optype1 = CNSTOP;
264: else if (offsettable_memref_p (operands[1]))
265: optype1 = OFFSOP;
266: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
267: optype1 = POPOP;
268: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
269: optype1 = PUSHOP;
270: else if (GET_CODE (operands[1]) == MEM)
271: optype1 = MEMOP;
272: else
273: optype1 = RNDOP;
274:
275: /* Check for the cases that the operand constraints are not
276: supposed to allow to happen. Abort if we get one,
277: because generating code for these cases is painful. */
278:
279: if (optype0 == RNDOP || optype1 == RNDOP)
280: abort ();
281:
282: /* If one operand is decrementing and one is incrementing
283: decrement the former register explicitly
284: and change that operand into ordinary indexing. */
285:
286: if (optype0 == PUSHOP && optype1 == POPOP)
287: {
288: operands[0] = XEXP (XEXP (operands[0], 0), 0);
289: asm_add (-8, operands[0]);
290: operands[0] = gen_rtx (MEM, DImode, operands[0]);
291: optype0 = OFFSOP;
292: }
293: if (optype0 == POPOP && optype1 == PUSHOP)
294: {
295: operands[1] = XEXP (XEXP (operands[1], 0), 0);
296: asm_add (-8, operands[1]);
297: operands[1] = gen_rtx (MEM, DImode, operands[1]);
298: optype1 = OFFSOP;
299: }
300:
301: /* If an operand is an unoffsettable memory ref, find a register
302: we can increment temporarily to make it refer to the second word. */
303:
304: if (optype0 == MEMOP)
305: addreg0 = find_addr_reg (XEXP (operands[0], 0));
306:
307: if (optype1 == MEMOP)
308: addreg1 = find_addr_reg (XEXP (operands[1], 0));
309:
310: /* Ok, we can do one word at a time.
311: Normally we do the low-numbered word first,
312: but if either operand is autodecrementing then we
313: do the high-numbered word first.
314:
315: In either case, set up in LATEHALF the operands to use
316: for the high-numbered word and in some cases alter the
317: operands in OPERANDS to be suitable for the low-numbered word. */
318:
319: if (optype0 == REGOP)
320: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
321: else if (optype0 == OFFSOP)
322: latehalf[0] = adj_offsettable_operand (operands[0], 4);
323: else
324: latehalf[0] = operands[0];
325:
326: if (optype1 == REGOP)
327: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
328: else if (optype1 == OFFSOP)
329: latehalf[1] = adj_offsettable_operand (operands[1], 4);
330: else if (optype1 == CNSTOP)
331: {
332: if (GET_CODE (operands[1]) == CONST_DOUBLE)
333: split_double (operands[1], &operands[1], &latehalf[1]);
334: else if (CONSTANT_P (operands[1]))
1.1.1.2 root 335: {
336: if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0)
337: latehalf[1] = constm1_rtx;
338: else
339: latehalf[1] = const0_rtx;
340: }
1.1 root 341: }
342: else
343: latehalf[1] = operands[1];
344:
345: /* If insn is effectively movd N (sp),-(sp) then we will do the
346: high word first. We should use the adjusted operand 1 (which is N+4 (sp))
347: for the low word as well, to compensate for the first decrement of sp. */
348: if (optype0 == PUSHOP
349: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
350: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
351: operands[1] = latehalf[1];
352:
353: /* If one or both operands autodecrementing,
354: do the two words, high-numbered first. */
355:
356: /* Likewise, the first move would clobber the source of the second one,
357: do them in the other order. This happens only for registers;
358: such overlap can't happen in memory unless the user explicitly
359: sets it up, and that is an undefined circumstance. */
360:
361: if (optype0 == PUSHOP || optype1 == PUSHOP
362: || (optype0 == REGOP && optype1 == REGOP
363: && REGNO (operands[0]) == REGNO (latehalf[1])))
364: {
365: /* Make any unoffsettable addresses point at high-numbered word. */
366: if (addreg0)
367: asm_add (4, addreg0);
368: if (addreg1)
369: asm_add (4, addreg1);
370:
371: /* Do that word. */
372: output_asm_insn (singlemove_string (latehalf), latehalf);
373:
374: /* Undo the adds we just did. */
375: if (addreg0)
376: asm_add (-4, addreg0);
377: if (addreg1)
378: asm_add (-4, addreg1);
379:
380: /* Do low-numbered word. */
381: return singlemove_string (operands);
382: }
383:
384: /* Normal case: do the two words, low-numbered first. */
385:
386: output_asm_insn (singlemove_string (operands), operands);
387:
388: /* Make any unoffsettable addresses point at high-numbered word. */
389: if (addreg0)
390: asm_add (4, addreg0);
391: if (addreg1)
392: asm_add (4, addreg1);
393:
394: /* Do that word. */
395: output_asm_insn (singlemove_string (latehalf), latehalf);
396:
397: /* Undo the adds we just did. */
398: if (addreg0)
399: asm_add (-4, addreg0);
400: if (addreg1)
401: asm_add (-4, addreg1);
402:
403: return "";
404: }
405:
406: int
407: standard_80387_constant_p (x)
408: rtx x;
409: {
410: union real_extract u;
411: register double d;
412:
413: bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u);
414: d = u.d;
415:
416: if (d == 0)
417: return 1;
418:
419: if (d == 1)
420: return 2;
421:
422: /* Note that on the 80387, other constants, such as pi,
423: are much slower to load as standard constants
424: than to load from doubles in memory! */
425:
426: return 0;
427: }
428:
429: char *
430: output_move_const_single (operands)
431: rtx *operands;
432: {
433: if (FP_REG_P (operands[0]))
434: {
435: int conval = standard_80387_constant_p (operands[1]);
436:
437: if (conval == 1)
438: return "fldz";
439:
440: if (conval == 2)
441: return "fld1";
442: }
443: if (GET_CODE (operands[1]) == CONST_DOUBLE)
444: {
445: union { int i[2]; double d;} u1;
446: union { int i; float f;} u2;
447: u1.i[0] = CONST_DOUBLE_LOW (operands[1]);
448: u1.i[1] = CONST_DOUBLE_HIGH (operands[1]);
449: u2.f = u1.d;
450: operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i);
451: }
452: return singlemove_string (operands);
453: }
454:
455: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
456: reference and a constant. */
457:
458: int
459: symbolic_operand (op, mode)
460: register rtx op;
461: enum machine_mode mode;
462: {
463: switch (GET_CODE (op))
464: {
465: case SYMBOL_REF:
466: case LABEL_REF:
467: return 1;
468: case CONST:
469: op = XEXP (op, 0);
470: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
471: || GET_CODE (XEXP (op, 0)) == LABEL_REF)
472: && GET_CODE (XEXP (op, 1)) == CONST_INT);
473: default:
474: return 0;
475: }
476: }
477:
478: /* Returns 1 if OP contains a symbol reference */
479:
480: int
481: symbolic_reference_mentioned_p (op)
482: rtx op;
483: {
484: register char *fmt;
485: register int i;
486:
487: if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
488: return 1;
489:
490: fmt = GET_RTX_FORMAT (GET_CODE (op));
491: for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
492: {
493: if (fmt[i] == 'E')
494: {
495: register int j;
496:
497: for (j = XVECLEN (op, i) - 1; j >= 0; j--)
498: if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
499: return 1;
500: }
501: else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
502: return 1;
503: }
504:
505: return 0;
506: }
507:
508: /* Return a legitimate reference for ORIG (an address) using the
509: register REG. If REG is 0, a new pseudo is generated.
510:
511: There are three types of references that must be handled:
512:
513: 1. Global data references must load the address from the GOT, via
514: the PIC reg. An insn is emitted to do this load, and the reg is
515: returned.
516:
517: 2. Static data references must compute the address as an offset
518: from the GOT, whose base is in the PIC reg. An insn is emitted to
519: compute the address into a reg, and the reg is returned. Static
520: data objects have SYMBOL_REF_FLAG set to differentiate them from
521: global data objects.
522:
523: 3. Constant pool addresses must be handled special. They are
524: considered legitimate addresses, but only if not used with regs.
525: When printed, the output routines know to print the reference with the
526: PIC reg, even though the PIC reg doesn't appear in the RTL.
527:
528: GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
529: reg also appears in the address (except for constant pool references,
530: noted above).
531:
532: "switch" statements also require special handling when generating
533: PIC code. See comments by the `casesi' insn in i386.md for details. */
534:
535: rtx
536: legitimize_pic_address (orig, reg)
537: rtx orig;
538: rtx reg;
539: {
540: rtx addr = orig;
541: rtx new = orig;
542:
543: if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
544: {
545: if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
546: reg = new = orig;
547: else
548: {
549: if (reg == 0)
550: reg = gen_reg_rtx (Pmode);
551:
552: if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
553: new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
554: else
555: new = gen_rtx (MEM, Pmode,
556: gen_rtx (PLUS, Pmode,
557: pic_offset_table_rtx, orig));
558:
559: emit_move_insn (reg, new);
560: }
561: current_function_uses_pic_offset_table = 1;
562: return reg;
563: }
564: else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
565: {
566: rtx base;
567:
568: if (GET_CODE (addr) == CONST)
569: {
570: addr = XEXP (addr, 0);
571: if (GET_CODE (addr) != PLUS)
572: abort ();
573: }
574:
575: if (XEXP (addr, 0) == pic_offset_table_rtx)
576: return orig;
577:
578: if (reg == 0)
579: reg = gen_reg_rtx (Pmode);
580:
581: base = legitimize_pic_address (XEXP (addr, 0), reg);
582: addr = legitimize_pic_address (XEXP (addr, 1), base == reg ? 0 : reg);
583:
584: if (GET_CODE (addr) == CONST_INT)
585: return plus_constant (base, INTVAL (addr));
586:
587: if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
588: {
589: base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
590: addr = XEXP (addr, 1);
591: }
592: return gen_rtx (PLUS, Pmode, base, addr);
593: }
594: return new;
595: }
596:
597: /* Emit insns to move operands[1] into operands[0]. */
598:
599: void
600: emit_pic_move (operands, mode)
601: rtx *operands;
602: enum machine_mode mode;
603: {
604: rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
605:
606: if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
607: operands[1] = (rtx) force_reg (SImode, operands[1]);
608: else
609: operands[1] = legitimize_pic_address (operands[1], temp);
610: }
611:
612: /* This function generates the assembly code for function entry.
613: FILE is an stdio stream to output the code to.
614: SIZE is an int: how many units of temporary storage to allocate. */
615:
616: void
617: function_prologue (file, size)
618: FILE *file;
619: int size;
620: {
621: register int regno;
622: int limit;
623: rtx xops[4];
1.1.1.3 ! root 624: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
! 625: || current_function_uses_const_pool);
1.1 root 626:
627: xops[0] = stack_pointer_rtx;
628: xops[1] = frame_pointer_rtx;
629: xops[2] = gen_rtx (CONST_INT, VOIDmode, size);
630: if (frame_pointer_needed)
631: {
632: output_asm_insn ("push%L1 %1", xops);
633: output_asm_insn (AS2 (mov%L0,%0,%1), xops);
634: }
635:
636: if (size)
637: output_asm_insn (AS2 (sub%L0,%2,%0), xops);
638:
639: /* Note If use enter it is NOT reversed args.
640: This one is not reversed from intel!!
641: I think enter is slower. Also sdb doesn't like it.
642: But if you want it the code is:
643: {
644: xops[3] = const0_rtx;
645: output_asm_insn ("enter %2,%3", xops);
646: }
647: */
648: limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
649: for (regno = limit - 1; regno >= 0; regno--)
650: if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root 651: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1 root 652: {
653: xops[0] = gen_rtx (REG, SImode, regno);
654: output_asm_insn ("push%L0 %0", xops);
655: }
656:
1.1.1.3 ! root 657: if (pic_reg_used)
1.1 root 658: {
659: xops[0] = pic_offset_table_rtx;
660: xops[1] = (rtx) gen_label_rtx ();
661:
662: output_asm_insn (AS1 (call,%P1), xops);
663: ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1]));
664: output_asm_insn (AS1 (pop%L0,%0), xops);
665: output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
666: }
667: }
668:
669: /* Return 1 if it is appropriate to emit `ret' instructions in the
670: body of a function. Do this only if the epilogue is simple, needing a
671: couple of insns. Prior to reloading, we can't tell how many registers
672: must be saved, so return 0 then.
673:
674: If NON_SAVING_SETJMP is defined and true, then it is not possible
675: for the epilogue to be simple, so return 0. This is a special case
676: since NON_SAVING_SETJMP will not cause regs_ever_live to change until
677: final, but jump_optimize may need to know sooner if a `return' is OK. */
678:
679: int
680: simple_386_epilogue ()
681: {
682: int regno;
683: int nregs = 0;
684: int reglimit = (frame_pointer_needed
685: ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
1.1.1.3 ! root 686: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
! 687: || current_function_uses_const_pool);
1.1 root 688:
689: #ifdef NON_SAVING_SETJMP
690: if (NON_SAVING_SETJMP && current_function_calls_setjmp)
691: return 0;
692: #endif
693:
694: if (! reload_completed)
695: return 0;
696:
697: for (regno = reglimit - 1; regno >= 0; regno--)
698: if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root 699: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1 root 700: nregs++;
701:
702: return nregs == 0 || ! frame_pointer_needed;
703: }
704:
705: /* This function generates the assembly code for function exit.
706: FILE is an stdio stream to output the code to.
707: SIZE is an int: how many units of temporary storage to deallocate. */
708:
709: void
710: function_epilogue (file, size)
711: FILE *file;
712: int size;
713: {
714: register int regno;
715: register int nregs, limit;
716: int offset;
717: rtx xops[3];
1.1.1.3 ! root 718: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
! 719: || current_function_uses_const_pool);
1.1 root 720:
721: /* Compute the number of registers to pop */
722:
723: limit = (frame_pointer_needed
724: ? FRAME_POINTER_REGNUM
725: : STACK_POINTER_REGNUM);
726:
727: nregs = 0;
728:
729: for (regno = limit - 1; regno >= 0; regno--)
730: if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root 731: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1 root 732: nregs++;
733:
734: /* sp is often unreliable so we must go off the frame pointer,
735: */
736:
737: /* In reality, we may not care if sp is unreliable, because we can
738: restore the register relative to the frame pointer. In theory,
739: since each move is the same speed as a pop, and we don't need the
740: leal, this is faster. For now restore multiple registers the old
741: way. */
742:
743: offset = -size - (nregs * UNITS_PER_WORD);
744:
745: xops[2] = stack_pointer_rtx;
746:
747: if (nregs > 1 || ! frame_pointer_needed)
748: {
749: if (frame_pointer_needed)
750: {
751: xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset);
752: output_asm_insn (AS2 (lea%L2,%0,%2), xops);
753: }
754:
755: for (regno = 0; regno < limit; regno++)
756: if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root 757: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1 root 758: {
759: xops[0] = gen_rtx (REG, SImode, regno);
760: output_asm_insn ("pop%L0 %0", xops);
761: }
762: }
763: else
764: for (regno = 0; regno < limit; regno++)
765: if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root 766: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1 root 767: {
768: xops[0] = gen_rtx (REG, SImode, regno);
769: xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
770: output_asm_insn (AS2 (mov%L0,%1,%0), xops);
771: offset += 4;
772: }
773:
774: if (frame_pointer_needed)
775: {
776: /* On i486, mov & pop is faster than "leave". */
777:
778: if (TARGET_486)
779: {
780: xops[0] = frame_pointer_rtx;
781: output_asm_insn (AS2 (mov%L2,%0,%2), xops);
782: output_asm_insn ("pop%L0 %0", xops);
783: }
784: else
785: output_asm_insn ("leave", xops);
786: }
787: else if (size)
788: {
789: /* If there is no frame pointer, we must still release the frame. */
790:
791: xops[0] = gen_rtx (CONST_INT, VOIDmode, size);
792: output_asm_insn (AS2 (add%L2,%0,%2), xops);
793: }
794:
795: if (current_function_pops_args && current_function_args_size)
796: {
797: xops[1] = gen_rtx (CONST_INT, VOIDmode, current_function_pops_args);
798:
799: /* i386 can only pop 32K bytes (maybe 64K? Is it signed?). If
800: asked to pop more, pop return address, do explicit add, and jump
801: indirectly to the caller. */
802:
803: if (current_function_pops_args >= 32768)
804: {
805: /* ??? Which register to use here? */
806: xops[0] = gen_rtx (REG, SImode, 2);
807: output_asm_insn ("pop%L0 %0", xops);
808: output_asm_insn (AS2 (add%L2,%1,%2), xops);
809: output_asm_insn ("jmp %*%0", xops);
810: }
811: else
812: output_asm_insn ("ret %1", xops);
813: }
814: else
815: output_asm_insn ("ret", xops);
816: }
817:
818: /* Print an integer constant expression in assembler syntax. Addition
819: and subtraction are the only arithmetic that may appear in these
820: expressions. FILE is the stdio stream to write to, X is the rtx, and
821: CODE is the operand print code from the output string. */
822:
823: static void
824: output_pic_addr_const (file, x, code)
825: FILE *file;
826: rtx x;
827: int code;
828: {
829: char buf[256];
830:
831: switch (GET_CODE (x))
832: {
833: case PC:
834: if (flag_pic)
835: putc ('.', file);
836: else
837: abort ();
838: break;
839:
840: case SYMBOL_REF:
841: case LABEL_REF:
842: if (GET_CODE (x) == SYMBOL_REF)
843: assemble_name (file, XSTR (x, 0));
844: else
845: {
846: ASM_GENERATE_INTERNAL_LABEL (buf, "L",
847: CODE_LABEL_NUMBER (XEXP (x, 0)));
848: assemble_name (asm_out_file, buf);
849: }
850:
851: if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
852: fprintf (file, "@GOTOFF(%%ebx)");
853: else if (code == 'P')
854: fprintf (file, "@PLT");
855: else if (GET_CODE (x) == LABEL_REF || ! SYMBOL_REF_FLAG (x))
856: fprintf (file, "@GOT");
857: else
858: fprintf (file, "@GOTOFF");
859:
860: break;
861:
862: case CODE_LABEL:
863: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
864: assemble_name (asm_out_file, buf);
865: break;
866:
867: case CONST_INT:
868: fprintf (file, "%d", INTVAL (x));
869: break;
870:
871: case CONST:
872: /* This used to output parentheses around the expression,
873: but that does not work on the 386 (either ATT or BSD assembler). */
874: output_pic_addr_const (file, XEXP (x, 0), code);
875: break;
876:
877: case CONST_DOUBLE:
878: if (GET_MODE (x) == VOIDmode)
879: {
880: /* We can use %d if the number is <32 bits and positive. */
881: if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
882: fprintf (file, "0x%x%08x",
883: CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
884: else
885: fprintf (file, "%d", CONST_DOUBLE_LOW (x));
886: }
887: else
888: /* We can't handle floating point constants;
889: PRINT_OPERAND must handle them. */
890: output_operand_lossage ("floating constant misused");
891: break;
892:
893: case PLUS:
894: /* Some assemblers need integer constants to appear last (eg masm). */
895: if (GET_CODE (XEXP (x, 0)) == CONST_INT)
896: {
897: output_pic_addr_const (file, XEXP (x, 1), code);
898: if (INTVAL (XEXP (x, 0)) >= 0)
899: fprintf (file, "+");
900: output_pic_addr_const (file, XEXP (x, 0), code);
901: }
902: else
903: {
904: output_pic_addr_const (file, XEXP (x, 0), code);
905: if (INTVAL (XEXP (x, 1)) >= 0)
906: fprintf (file, "+");
907: output_pic_addr_const (file, XEXP (x, 1), code);
908: }
909: break;
910:
911: case MINUS:
912: output_pic_addr_const (file, XEXP (x, 0), code);
913: fprintf (file, "-");
914: output_pic_addr_const (file, XEXP (x, 1), code);
915: break;
916:
917: default:
918: output_operand_lossage ("invalid expression as operand");
919: }
920: }
921:
922: /* Print the name of a register based on its machine mode and number.
923: If CODE is 'w', pretend the mode is HImode.
924: If CODE is 'b', pretend the mode is QImode.
925: If CODE is 'k', pretend the mode is SImode.
926: If CODE is 'h', pretend the reg is the `high' byte register.
927: If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */
928:
929: #define PRINT_REG(X, CODE, FILE) \
930: do { if (REGNO (X) == ARG_POINTER_REGNUM) \
931: abort (); \
932: fprintf (FILE, "%s", RP); \
933: switch ((CODE == 'w' ? 2 \
934: : CODE == 'b' ? 1 \
935: : CODE == 'k' ? 4 \
936: : CODE == 'y' ? 3 \
937: : CODE == 'h' ? 0 \
938: : GET_MODE_SIZE (GET_MODE (X)))) \
939: { \
940: case 3: \
941: if (STACK_TOP_P (X)) \
942: { \
943: fputs ("st(0)", FILE); \
944: break; \
945: } \
946: case 4: \
947: case 8: \
948: if (!FP_REG_P (X)) fputs ("e", FILE); \
949: case 2: \
950: fputs (hi_reg_name[REGNO (X)], FILE); \
951: break; \
952: case 1: \
953: fputs (qi_reg_name[REGNO (X)], FILE); \
954: break; \
955: case 0: \
956: fputs (qi_high_reg_name[REGNO (X)], FILE); \
957: break; \
958: } \
959: } while (0)
960:
961: /* Meaning of CODE:
962: f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
963: D,L,W,B,Q,S -- print the opcode suffix for specified size of operand.
964: R -- print the prefix for register names.
965: z -- print the opcode suffix for the size of the current operand.
966: * -- print a star (in certain assembler syntax)
967: w -- print the operand as if it's a "word" (HImode) even if it isn't.
968: c -- don't print special prefixes before constant operands.
969: */
970:
971: void
972: print_operand (file, x, code)
973: FILE *file;
974: rtx x;
975: int code;
976: {
977: if (code)
978: {
979: switch (code)
980: {
981: case '*':
982: if (USE_STAR)
983: putc ('*', file);
984: return;
985:
986: case 'L':
987: PUT_OP_SIZE (code, 'l', file);
988: return;
989:
990: case 'W':
991: PUT_OP_SIZE (code, 'w', file);
992: return;
993:
994: case 'B':
995: PUT_OP_SIZE (code, 'b', file);
996: return;
997:
998: case 'Q':
999: PUT_OP_SIZE (code, 'l', file);
1000: return;
1001:
1002: case 'S':
1003: PUT_OP_SIZE (code, 's', file);
1004: return;
1005:
1006: case 'z':
1007: /* 387 opcodes don't get size suffixes if the operands are
1008: registers. */
1009:
1010: if (STACK_REG_P (x))
1011: return;
1012:
1013: /* this is the size of op from size of operand */
1014: switch (GET_MODE_SIZE (GET_MODE (x)))
1015: {
1016: case 1:
1017: PUT_OP_SIZE ('B', 'b', file);
1018: return;
1019:
1020: case 2:
1021: PUT_OP_SIZE ('W', 'w', file);
1022: return;
1023:
1024: case 4:
1025: if (GET_MODE (x) == SFmode)
1026: {
1027: PUT_OP_SIZE ('S', 's', file);
1028: return;
1029: }
1030: else
1031: PUT_OP_SIZE ('L', 'l', file);
1032: return;
1033:
1034: case 8:
1035: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
1.1.1.3 ! root 1036: {
! 1037: #ifdef GAS_MNEMONICS
! 1038: PUT_OP_SIZE ('Q', 'q', file);
! 1039: return;
! 1040: #else
! 1041: PUT_OP_SIZE ('Q', 'l', file); /* Fall through */
! 1042: #endif
! 1043: }
1.1 root 1044:
1045: PUT_OP_SIZE ('Q', 'l', file);
1046: return;
1047: }
1.1.1.3 ! root 1048:
! 1049: case 'b':
! 1050: case 'w':
! 1051: case 'k':
! 1052: case 'h':
! 1053: case 'y':
! 1054: case 'P':
! 1055: break;
! 1056:
! 1057: default:
! 1058: abort ();
1.1 root 1059: }
1060: }
1061: if (GET_CODE (x) == REG)
1062: {
1063: PRINT_REG (x, code, file);
1064: }
1065: else if (GET_CODE (x) == MEM)
1066: {
1067: PRINT_PTR (x, file);
1068: if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
1069: {
1070: if (flag_pic)
1071: output_pic_addr_const (file, XEXP (x, 0), code);
1072: else
1073: output_addr_const (file, XEXP (x, 0));
1074: }
1075: else
1076: output_address (XEXP (x, 0));
1077: }
1078: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
1079: {
1080: union { double d; int i[2]; } u;
1081: union { float f; int i; } u1;
1082: u.i[0] = CONST_DOUBLE_LOW (x);
1083: u.i[1] = CONST_DOUBLE_HIGH (x);
1084: u1.f = u.d;
1.1.1.3 ! root 1085: PRINT_IMMED_PREFIX (file);
! 1086: fprintf (file, "0x%x", u1.i);
1.1 root 1087: }
1088: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
1089: {
1090: union { double d; int i[2]; } u;
1091: u.i[0] = CONST_DOUBLE_LOW (x);
1092: u.i[1] = CONST_DOUBLE_HIGH (x);
1093: fprintf (file, "%.22e", u.d);
1094: }
1095: else
1096: {
1.1.1.3 ! root 1097: if (code != 'P')
1.1 root 1098: {
1.1.1.3 ! root 1099: if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
1.1 root 1100: PRINT_IMMED_PREFIX (file);
1101: else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF
1102: || GET_CODE (x) == LABEL_REF)
1103: PRINT_OFFSET_PREFIX (file);
1104: }
1105: if (flag_pic)
1106: output_pic_addr_const (file, x, code);
1107: else
1108: output_addr_const (file, x);
1109: }
1110: }
1111:
1112: /* Print a memory operand whose address is ADDR. */
1113:
1114: void
1115: print_operand_address (file, addr)
1116: FILE *file;
1117: register rtx addr;
1118: {
1119: register rtx reg1, reg2, breg, ireg;
1120: rtx offset;
1121:
1122: switch (GET_CODE (addr))
1123: {
1124: case REG:
1125: ADDR_BEG (file);
1126: fprintf (file, "%se", RP);
1127: fputs (hi_reg_name[REGNO (addr)], file);
1128: ADDR_END (file);
1129: break;
1130:
1131: case PLUS:
1132: reg1 = 0;
1133: reg2 = 0;
1134: ireg = 0;
1135: breg = 0;
1136: offset = 0;
1137: if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
1138: {
1139: offset = XEXP (addr, 0);
1140: addr = XEXP (addr, 1);
1141: }
1142: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
1143: {
1144: offset = XEXP (addr, 1);
1145: addr = XEXP (addr, 0);
1146: }
1147: if (GET_CODE (addr) != PLUS) ;
1148: else if (GET_CODE (XEXP (addr, 0)) == MULT)
1149: {
1150: reg1 = XEXP (addr, 0);
1151: addr = XEXP (addr, 1);
1152: }
1153: else if (GET_CODE (XEXP (addr, 1)) == MULT)
1154: {
1155: reg1 = XEXP (addr, 1);
1156: addr = XEXP (addr, 0);
1157: }
1158: else if (GET_CODE (XEXP (addr, 0)) == REG)
1159: {
1160: reg1 = XEXP (addr, 0);
1161: addr = XEXP (addr, 1);
1162: }
1163: else if (GET_CODE (XEXP (addr, 1)) == REG)
1164: {
1165: reg1 = XEXP (addr, 1);
1166: addr = XEXP (addr, 0);
1167: }
1168: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
1169: {
1170: if (reg1 == 0) reg1 = addr;
1171: else reg2 = addr;
1172: addr = 0;
1173: }
1174: if (offset != 0)
1175: {
1176: if (addr != 0) abort ();
1177: addr = offset;
1178: }
1179: if ((reg1 && GET_CODE (reg1) == MULT)
1180: || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
1181: {
1182: breg = reg2;
1183: ireg = reg1;
1184: }
1185: else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
1186: {
1187: breg = reg1;
1188: ireg = reg2;
1189: }
1190:
1191: if (ireg != 0 || breg != 0)
1192: {
1193: int scale = 1;
1194:
1195: if (addr != 0)
1196: {
1197: if (GET_CODE (addr) == LABEL_REF)
1198: output_asm_label (addr);
1199: else
1200: {
1201: if (flag_pic)
1202: output_pic_addr_const (file, addr, 0);
1203: else
1204: output_addr_const (file, addr);
1205: }
1206: }
1207:
1208: if (ireg != 0 && GET_CODE (ireg) == MULT)
1209: {
1210: scale = INTVAL (XEXP (ireg, 1));
1211: ireg = XEXP (ireg, 0);
1212: }
1213:
1214: /* The stack pointer can only appear as a base register,
1215: never an index register, so exchange the regs if it is wrong. */
1216:
1217: if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM)
1218: {
1219: rtx tmp;
1220:
1221: tmp = breg;
1222: breg = ireg;
1223: ireg = tmp;
1224: }
1225:
1226: /* output breg+ireg*scale */
1227: PRINT_B_I_S (breg, ireg, scale, file);
1228: break;
1229: }
1230:
1231: case MULT:
1232: {
1233: int scale;
1234: if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1235: {
1236: scale = INTVAL (XEXP (addr, 0));
1237: ireg = XEXP (addr, 1);
1238: }
1239: else
1240: {
1241: scale = INTVAL (XEXP (addr, 1));
1242: ireg = XEXP (addr, 0);
1243: }
1244: output_addr_const (file, const0_rtx);
1245: PRINT_B_I_S ((rtx) 0, ireg, scale, file);
1246: }
1247: break;
1248:
1249: default:
1250: if (GET_CODE (addr) == CONST_INT
1251: && INTVAL (addr) < 0x8000
1252: && INTVAL (addr) >= -0x8000)
1253: fprintf (file, "%d", INTVAL (addr));
1254: else
1255: {
1256: if (flag_pic)
1257: output_pic_addr_const (file, addr, 0);
1258: else
1259: output_addr_const (file, addr);
1260: }
1261: }
1262: }
1263:
1264: /* Set the cc_status for the results of an insn whose pattern is EXP.
1265: On the 80386, we assume that only test and compare insns, as well
1266: as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT,
1267: ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
1268: Also, we assume that jumps, moves and sCOND don't affect the condition
1269: codes. All else clobbers the condition codes, by assumption.
1270:
1271: We assume that ALL integer add, minus, etc. instructions effect the
1272: condition codes. This MUST be consistent with i386.md.
1273:
1274: We don't record any float test or compare - the redundant test &
1275: compare check in final.c does not handle stack-like regs correctly. */
1276:
1277: void
1278: notice_update_cc (exp)
1279: rtx exp;
1280: {
1281: if (GET_CODE (exp) == SET)
1282: {
1283: /* Jumps do not alter the cc's. */
1284: if (SET_DEST (exp) == pc_rtx)
1285: return;
1286: /* Moving register or memory into a register:
1287: it doesn't alter the cc's, but it might invalidate
1288: the RTX's which we remember the cc's came from.
1289: (Note that moving a constant 0 or 1 MAY set the cc's). */
1290: if (REG_P (SET_DEST (exp))
1291: && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
1292: || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
1293: {
1294: if (cc_status.value1
1295: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1296: cc_status.value1 = 0;
1297: if (cc_status.value2
1298: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1299: cc_status.value2 = 0;
1300: return;
1301: }
1302: /* Moving register into memory doesn't alter the cc's.
1303: It may invalidate the RTX's which we remember the cc's came from. */
1304: if (GET_CODE (SET_DEST (exp)) == MEM
1305: && (REG_P (SET_SRC (exp))
1306: || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
1307: {
1308: if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
1309: cc_status.value1 = 0;
1310: if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
1311: cc_status.value2 = 0;
1312: return;
1313: }
1314: /* Function calls clobber the cc's. */
1315: else if (GET_CODE (SET_SRC (exp)) == CALL)
1316: {
1317: CC_STATUS_INIT;
1318: return;
1319: }
1320: /* Tests and compares set the cc's in predictable ways. */
1321: else if (SET_DEST (exp) == cc0_rtx)
1322: {
1323: CC_STATUS_INIT;
1324: cc_status.value1 = SET_SRC (exp);
1325: return;
1326: }
1327: /* Certain instructions effect the condition codes. */
1328: else if (GET_MODE (SET_SRC (exp)) == SImode
1329: || GET_MODE (SET_SRC (exp)) == HImode
1330: || GET_MODE (SET_SRC (exp)) == QImode)
1331: switch (GET_CODE (SET_SRC (exp)))
1332: {
1333: case ASHIFTRT: case LSHIFTRT:
1334: case ASHIFT: case LSHIFT:
1335: /* Shifts on the 386 don't set the condition codes if the
1336: shift count is zero. */
1337: if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
1338: {
1339: CC_STATUS_INIT;
1340: break;
1341: }
1342: /* We assume that the CONST_INT is non-zero (this rtx would
1343: have been deleted if it were zero. */
1344:
1345: case PLUS: case MINUS: case NEG:
1346: case AND: case IOR: case XOR:
1347: cc_status.flags = CC_NO_OVERFLOW;
1348: cc_status.value1 = SET_SRC (exp);
1349: cc_status.value2 = SET_DEST (exp);
1350: break;
1351:
1352: default:
1353: CC_STATUS_INIT;
1354: }
1355: else
1356: {
1357: CC_STATUS_INIT;
1358: }
1359: }
1360: else if (GET_CODE (exp) == PARALLEL
1361: && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1362: {
1363: if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
1364: return;
1365: if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
1366: {
1367: CC_STATUS_INIT;
1368: if (! stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
1369: cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
1.1.1.3 ! root 1370:
! 1371: cc_status.flags |= CC_IN_80387;
1.1 root 1372: return;
1373: }
1374: CC_STATUS_INIT;
1375: }
1376: else
1377: {
1378: CC_STATUS_INIT;
1379: }
1380: }
1381:
1382: /* Split one or more DImode RTL references into pairs of SImode
1383: references. The RTL can be REG, offsettable MEM, integer constant, or
1384: CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1385: split and "num" is its length. lo_half and hi_half are output arrays
1386: that parallel "operands". */
1387:
1388: void
1389: split_di (operands, num, lo_half, hi_half)
1390: rtx operands[];
1391: int num;
1392: rtx lo_half[], hi_half[];
1393: {
1394: while (num--)
1395: {
1396: if (GET_CODE (operands[num]) == REG)
1397: {
1398: lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
1399: hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
1400: }
1401: else if (CONSTANT_P (operands[num]))
1402: {
1403: split_double (operands[num], &lo_half[num], &hi_half[num]);
1404: }
1405: else if (offsettable_memref_p (operands[num]))
1406: {
1407: lo_half[num] = operands[num];
1408: hi_half[num] = adj_offsettable_operand (operands[num], 4);
1409: }
1410: else
1411: abort();
1412: }
1413: }
1414:
1415: /* Return 1 if this is a valid binary operation on a 387.
1416: OP is the expression matched, and MODE is its mode. */
1417:
1418: int
1419: binary_387_op (op, mode)
1420: register rtx op;
1421: enum machine_mode mode;
1422: {
1423: if (mode != VOIDmode && mode != GET_MODE (op))
1424: return 0;
1425:
1426: switch (GET_CODE (op))
1427: {
1428: case PLUS:
1429: case MINUS:
1430: case MULT:
1431: case DIV:
1432: return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
1433:
1434: default:
1435: return 0;
1436: }
1437: }
1438:
1439: /* Return 1 if this is a valid conversion operation on a 387.
1440: OP is the expression matched, and MODE is its mode. */
1441:
1442: int
1443: convert_387_op (op, mode)
1444: register rtx op;
1445: enum machine_mode mode;
1446: {
1447: if (mode != VOIDmode && mode != GET_MODE (op))
1448: return 0;
1449:
1450: switch (GET_CODE (op))
1451: {
1452: case FLOAT:
1453: return GET_MODE (XEXP (op, 0)) == SImode;
1454:
1455: case FLOAT_EXTEND:
1456: return mode == DFmode && GET_MODE (XEXP (op, 0)) == SFmode;
1457:
1458: default:
1459: return 0;
1460: }
1461: }
1462:
1463: /* Return 1 if this is a valid "float from int" operation on a 387.
1464: OP is the expression matched, and MODE is its mode. */
1465:
1466: int
1467: float_op (op, mode)
1468: register rtx op;
1469: enum machine_mode mode;
1470: {
1471: if (mode != VOIDmode && mode != GET_MODE (op))
1472: return 0;
1473:
1474: return GET_CODE (op) == FLOAT
1475: && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
1476: }
1477:
1478: /* Return 1 if this is a valid shift or rotate operation on a 386.
1479: OP is the expression matched, and MODE is its mode. */
1480:
1481: int
1482: shift_op (op, mode)
1483: register rtx op;
1484: enum machine_mode mode;
1485: {
1486: rtx operand = XEXP (op, 0);
1487:
1488: if (mode != VOIDmode && mode != GET_MODE (op))
1489: return 0;
1490:
1491: if (GET_MODE (operand) != GET_MODE (op)
1492: || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT)
1493: return 0;
1494:
1495: return (GET_CODE (op) == ASHIFT
1496: || GET_CODE (op) == ASHIFTRT
1497: || GET_CODE (op) == LSHIFTRT
1498: || GET_CODE (op) == ROTATE
1499: || GET_CODE (op) == ROTATERT);
1500: }
1501:
1502: /* Output code to perform a 387 binary operation in INSN, one of PLUS,
1503: MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3]
1504: is the expression of the binary operation. The output may either be
1505: emitted here, or returned to the caller, like all output_* functions.
1506:
1507: There is no guarantee that the operands are the same mode, as they
1508: might be within FLOAT or FLOAT_EXTEND expressions. */
1509:
1510: char *
1511: output_387_binary_op (insn, operands)
1512: rtx insn;
1513: rtx *operands;
1514: {
1515: rtx temp;
1516: char *base_op;
1517: static char buf[100];
1518:
1519: switch (GET_CODE (operands[3]))
1520: {
1521: case PLUS:
1522: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
1523: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
1524: base_op = "fiadd";
1525: else
1526: base_op = "fadd";
1527: break;
1528:
1529: case MINUS:
1530: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
1531: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
1532: base_op = "fisub";
1533: else
1534: base_op = "fsub";
1535: break;
1536:
1537: case MULT:
1538: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
1539: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
1540: base_op = "fimul";
1541: else
1542: base_op = "fmul";
1543: break;
1544:
1545: case DIV:
1546: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
1547: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
1548: base_op = "fidiv";
1549: else
1550: base_op = "fdiv";
1551: break;
1552:
1553: default:
1554: abort ();
1555: }
1556:
1557: strcpy (buf, base_op);
1558:
1559: switch (GET_CODE (operands[3]))
1560: {
1561: case MULT:
1562: case PLUS:
1563: if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
1564: {
1565: temp = operands[2];
1566: operands[2] = operands[1];
1567: operands[1] = temp;
1568: }
1569:
1570: if (GET_CODE (operands[2]) == MEM)
1571: return strcat (buf, AS1 (%z2,%2));
1572:
1573: if (NON_STACK_REG_P (operands[1]))
1574: {
1575: output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
1576: RET;
1577: }
1578: else if (NON_STACK_REG_P (operands[2]))
1579: {
1580: output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
1581: RET;
1582: }
1583:
1584: if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
1585: return strcat (buf, AS2 (p,%2,%0));
1586:
1587: if (STACK_TOP_P (operands[0]))
1588: return strcat (buf, AS2 (,%y2,%0));
1589: else
1590: return strcat (buf, AS2 (,%2,%0));
1591:
1592: case MINUS:
1593: case DIV:
1594: if (GET_CODE (operands[1]) == MEM)
1595: return strcat (buf, AS1 (r%z1,%1));
1596:
1597: if (GET_CODE (operands[2]) == MEM)
1598: return strcat (buf, AS1 (%z2,%2));
1599:
1600: if (NON_STACK_REG_P (operands[1]))
1601: {
1602: output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1)));
1603: RET;
1604: }
1605: else if (NON_STACK_REG_P (operands[2]))
1606: {
1607: output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
1608: RET;
1609: }
1610:
1611: if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
1612: abort ();
1613:
1614: if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
1615: return strcat (buf, AS2 (rp,%2,%0));
1616:
1617: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
1618: return strcat (buf, AS2 (p,%1,%0));
1619:
1620: if (STACK_TOP_P (operands[0]))
1621: {
1622: if (STACK_TOP_P (operands[1]))
1623: return strcat (buf, AS2 (,%y2,%0));
1624: else
1625: return strcat (buf, AS2 (r,%y1,%0));
1626: }
1627: else if (STACK_TOP_P (operands[1]))
1628: return strcat (buf, AS2 (,%1,%0));
1629: else
1630: return strcat (buf, AS2 (r,%2,%0));
1631:
1632: default:
1633: abort ();
1634: }
1635: }
1636:
1637: /* Output code for INSN to convert a float to a signed int. OPERANDS
1638: are the insn operands. The output may be SFmode or DFmode and the
1639: input operand may be SImode or DImode. As a special case, make sure
1640: that the 387 stack top dies if the output mode is DImode, because the
1641: hardware requires this. */
1642:
1643: char *
1644: output_fix_trunc (insn, operands)
1645: rtx insn;
1646: rtx *operands;
1647: {
1648: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1649: rtx xops[6];
1650:
1651: if (! STACK_TOP_P (operands[1]) ||
1652: (GET_MODE (operands[0]) == DImode && ! stack_top_dies))
1653: abort ();
1654:
1655: xops[0] = stack_pointer_rtx;
1656: xops[1] = AT_SP (SImode);
1657: xops[2] = adj_offsettable_operand (xops[1], 2);
1658: xops[3] = gen_rtx (CONST_INT, VOIDmode, 4);
1659: xops[4] = gen_rtx (CONST_INT, VOIDmode, 0xc00);
1660: xops[5] = operands[2];
1661:
1662: output_asm_insn (AS2 (sub%L0,%3,%0), xops);
1663: output_asm_insn (AS1 (fnstc%W5,%1), xops);
1664: output_asm_insn (AS2 (mov%W5,%1,%5), xops);
1665: output_asm_insn (AS2 (or%W5,%4,%5), xops);
1666: output_asm_insn (AS2 (mov%W5,%5,%2), xops);
1667: output_asm_insn (AS1 (fldc%W5,%2), xops);
1668:
1669: if (NON_STACK_REG_P (operands[0]))
1670: output_to_reg (operands[0], stack_top_dies);
1671: else if (GET_CODE (operands[0]) == MEM)
1672: {
1673: /* If frame pointer elimination is being done, the MEM reference
1674: might be an index off of the stack pointer. In that case,
1675: since we have already adjusted %esp above, adjust the operand
1676: address so it points where it should. */
1677:
1678: if (! frame_pointer_needed
1679: && reg_mentioned_p (stack_pointer_rtx, operands[0]))
1680: operands[0] = adj_offsettable_operand (operands[0], 4);
1681:
1682: if (stack_top_dies)
1683: output_asm_insn (AS1 (fistp%z0,%0), operands);
1684: else
1685: output_asm_insn (AS1 (fist%z0,%0), operands);
1686: }
1687: else
1688: abort ();
1689:
1690: output_asm_insn (AS1 (fldc%W5,%1), xops);
1691: output_asm_insn (AS2 (add%L0,%3,%0), xops);
1692:
1693: RET;
1694: }
1695:
1696: /* Output code for INSN to compare OPERANDS. The two operands might
1697: not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
1.1.1.3 ! root 1698: expression. If the compare is in mode CCFPEQmode, use an opcode that
! 1699: will not fault if a qNaN is present. */
1.1 root 1700:
1701: char *
1702: output_float_compare (insn, operands)
1703: rtx insn;
1704: rtx *operands;
1705: {
1706: int stack_top_dies;
1.1.1.3 ! root 1707: rtx body = XVECEXP (PATTERN (insn), 0, 0);
! 1708: int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
1.1 root 1709:
1710: if (! STACK_TOP_P (operands[0]))
1711: abort ();
1712:
1713: stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1714:
1715: if (STACK_REG_P (operands[1])
1716: && stack_top_dies
1717: && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))
1718: && REGNO (operands[1]) != FIRST_STACK_REG)
1719: {
1720: /* If both the top of the 387 stack dies, and the other operand
1721: is also a stack register that dies, then this must be a
1722: `fcompp' float compare */
1723:
1.1.1.3 ! root 1724: if (unordered_compare)
! 1725: output_asm_insn ("fucompp", operands);
! 1726: else
! 1727: output_asm_insn ("fcompp", operands);
1.1 root 1728: }
1729: else
1730: {
1731: static char buf[100];
1732:
1.1.1.3 ! root 1733: /* Decide if this is the integer or float compare opcode, or the
! 1734: unordered float compare. */
1.1 root 1735:
1.1.1.3 ! root 1736: if (unordered_compare)
! 1737: strcpy (buf, "fucom");
! 1738: else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
1.1 root 1739: strcpy (buf, "fcom");
1740: else
1741: strcpy (buf, "ficom");
1742:
1743: /* Modify the opcode if the 387 stack is to be popped. */
1744:
1745: if (stack_top_dies)
1746: strcat (buf, "p");
1747:
1748: if (NON_STACK_REG_P (operands[1]))
1749: output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
1750: else
1751: output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
1752: }
1753:
1754: /* Now retrieve the condition code. */
1755:
1.1.1.3 ! root 1756: return output_fp_cc0_set (insn);
! 1757: }
! 1758:
! 1759: /* Output opcodes to transfer the results of FP compare or test INSN
! 1760: from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the
! 1761: result of the compare or test is unordered, no comparison operator
! 1762: succeeds except NE. Return an output template, if any. */
! 1763:
! 1764: char *
! 1765: output_fp_cc0_set (insn)
! 1766: rtx insn;
! 1767: {
! 1768: rtx xops[3];
! 1769: rtx unordered_label;
! 1770: rtx next;
! 1771: enum rtx_code code;
! 1772:
! 1773: xops[0] = gen_rtx (REG, HImode, 0);
! 1774: output_asm_insn (AS1 (fnsts%W0,%0), xops);
! 1775:
! 1776: if (! TARGET_IEEE_FP)
! 1777: return "sahf";
! 1778:
! 1779: next = next_cc0_user (insn);
1.1 root 1780:
1.1.1.3 ! root 1781: if (GET_CODE (next) == JUMP_INSN
! 1782: && GET_CODE (PATTERN (next)) == SET
! 1783: && SET_DEST (PATTERN (next)) == pc_rtx
! 1784: && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
! 1785: {
! 1786: code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
! 1787: }
! 1788: else if (GET_CODE (PATTERN (next)) == SET)
! 1789: {
! 1790: code = GET_CODE (SET_SRC (PATTERN (next)));
! 1791: }
! 1792: else
! 1793: abort ();
! 1794:
! 1795: xops[0] = gen_rtx (REG, QImode, 0);
! 1796:
! 1797: switch (code)
! 1798: {
! 1799: case GT:
! 1800: xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
! 1801: output_asm_insn (AS2 (and%B0,%1,%h0), xops);
! 1802: /* je label */
! 1803: break;
! 1804:
! 1805: case LT:
! 1806: xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
! 1807: xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x01);
! 1808: output_asm_insn (AS2 (and%B0,%1,%h0), xops);
! 1809: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
! 1810: /* je label */
! 1811: break;
! 1812:
! 1813: case GE:
! 1814: xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x05);
! 1815: output_asm_insn (AS2 (and%B0,%1,%h0), xops);
! 1816: /* je label */
! 1817: break;
! 1818:
! 1819: case LE:
! 1820: xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
! 1821: xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
! 1822: output_asm_insn (AS2 (and%B0,%1,%h0), xops);
! 1823: output_asm_insn (AS1 (dec%B0,%h0), xops);
! 1824: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
! 1825: /* jb label */
! 1826: break;
! 1827:
! 1828: case EQ:
! 1829: xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
! 1830: xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
! 1831: output_asm_insn (AS2 (and%B0,%1,%h0), xops);
! 1832: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
! 1833: /* je label */
! 1834: break;
! 1835:
! 1836: case NE:
! 1837: xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x44);
! 1838: xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
! 1839: output_asm_insn (AS2 (and%B0,%1,%h0), xops);
! 1840: output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
! 1841: /* jne label */
! 1842: break;
! 1843:
! 1844: case GTU:
! 1845: case LTU:
! 1846: case GEU:
! 1847: case LEU:
! 1848: default:
! 1849: abort ();
! 1850: }
! 1851: RET;
1.1 root 1852: }
1853:
1854: #ifdef HANDLE_PRAGMA
1855:
1856: /* When structure field packing is in effect, this variable is the
1857: number of bits to use as the maximum alignment. When packing is not
1858: in effect, this is zero. */
1859:
1860: int maximum_field_alignment = 0;
1861:
1862: /* Handle a pragma directive. HANDLE_PRAGMA conspires to parse the
1863: input following #pragma into tokens based on yylex. TOKEN is the
1864: current token, and STRING is its printable form. */
1865:
1866: void
1867: handle_pragma_token (string, token)
1868: char *string;
1869: tree token;
1870: {
1871: static enum pragma_state
1872: {
1873: ps_start,
1874: ps_done,
1875: ps_bad,
1876: ps_weak,
1877: ps_name,
1878: ps_equals,
1879: ps_value,
1880: ps_pack,
1881: ps_left,
1882: ps_align,
1883: ps_right
1884: } state = ps_start, type;
1885: static char *name;
1886: static char *value;
1887: static int align;
1888:
1889: if (string == 0)
1890: {
1891: if (type == ps_pack)
1892: {
1893: if (state == ps_right)
1894: maximum_field_alignment = align * 8;
1895: else
1896: warning ("ignoring malformed #pragma pack( [ 1 | 2 | 4 ] )");
1897: }
1898: #ifdef WEAK_ASM_OP
1899: else if (type == ps_weak)
1900: {
1901: if (state == ps_name || state == ps_value)
1902: {
1903: fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
1904: ASM_OUTPUT_LABELREF (asm_out_file, name);
1905: fputc ('\n', asm_out_file);
1906: if (state == ps_value)
1907: {
1.1.1.3 ! root 1908: fprintf (asm_out_file, "\t%s\t", SET_ASM_OP);
1.1 root 1909: ASM_OUTPUT_LABELREF (asm_out_file, name);
1910: fputc (',', asm_out_file);
1911: ASM_OUTPUT_LABELREF (asm_out_file, value);
1912: fputc ('\n', asm_out_file);
1913: }
1914: }
1915: else if (! (state == ps_done || state == ps_start))
1916: warning ("ignoring malformed #pragma weak symbol [=value]");
1917: }
1918: #endif /* WEAK_ASM_OP */
1919:
1920: type = state = ps_start;
1921: return;
1922: }
1923:
1924: switch (state)
1925: {
1926: case ps_start:
1927: if (token && TREE_CODE (token) == IDENTIFIER_NODE)
1928: {
1929: if (strcmp (IDENTIFIER_POINTER (token), "pack") == 0)
1930: type = state = ps_pack;
1931: #ifdef WEAK_ASM_OP
1932: else if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
1933: type = state = ps_weak;
1934: #endif
1935: else
1936: type = state = ps_done;
1937: }
1938: else
1939: type = state = ps_done;
1940: break;
1941:
1942: #ifdef WEAK_ASM_OP
1943: case ps_weak:
1944: if (token && TREE_CODE (token) == IDENTIFIER_NODE)
1945: {
1946: name = IDENTIFIER_POINTER (token);
1947: state = ps_name;
1948: }
1949: else
1950: state = ps_bad;
1951: break;
1952:
1953: case ps_name:
1954: state = (strcmp (string, "=") ? ps_bad : ps_equals);
1955: break;
1956:
1957: case ps_equals:
1958: if (token && TREE_CODE (token) == IDENTIFIER_NODE)
1959: {
1960: value = IDENTIFIER_POINTER (token);
1961: state = ps_value;
1962: }
1963: else
1964: state = ps_bad;
1965: break;
1966:
1967: case ps_value:
1968: state = ps_bad;
1969: break;
1970: #endif /* WEAK_ASM_OP */
1971:
1972: case ps_pack:
1973: if (strcmp (string, "(") == 0)
1974: state = ps_left;
1975: else
1976: state = ps_bad;
1977: break;
1978:
1979: case ps_left:
1980: if (token && TREE_CODE (token) == INTEGER_CST
1981: && TREE_INT_CST_HIGH (token) == 0)
1982: switch (TREE_INT_CST_LOW (token))
1983: {
1984: case 1:
1985: case 2:
1986: case 4:
1987: align = TREE_INT_CST_LOW (token);
1988: state = ps_align;
1989: break;
1990:
1991: default:
1992: state = ps_bad;
1993: }
1994: else if (! token && strcmp (string, ")") == 0)
1995: {
1996: align = 0;
1997: state = ps_right;
1998: }
1999: else
2000: state = ps_bad;
2001: break;
2002:
2003: case ps_align:
2004: if (strcmp (string, ")") == 0)
2005: state = ps_right;
2006: else
2007: state = ps_bad;
2008: break;
2009:
2010: case ps_right:
2011: state = ps_bad;
2012: break;
2013:
2014: case ps_bad:
2015: case ps_done:
2016: break;
2017:
2018: default:
2019: abort ();
2020: }
2021: }
2022: #endif /* HANDLE_PRAGMA */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.