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