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