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