Add diclaimer of copyright to _osname() manual page.
[unix-history] / gnu / usr.bin / gcc1 / cc1 / config / out-i386.c
CommitLineData
15637ed4
RG
1/*-
2 *
3 * This code is derived from software copyrighted by the Free Software
4 * Foundation.
5 *
6 * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
7 */
8
9#ifndef lint
10static char sccsid[] = "@(#)out-i386.c 6.4 (Berkeley) 5/8/91";
11#endif /* not lint */
12
13/* Subroutines for insn-output.c for Intel 80386.
14 Copyright (C) 1988 Free Software Foundation, Inc.
15
16This file is part of GNU CC.
17
18GNU CC is free software; you can redistribute it and/or modify
19it under the terms of the GNU General Public License as published by
20the Free Software Foundation; either version 1, or (at your option)
21any later version.
22
23GNU CC is distributed in the hope that it will be useful,
24but WITHOUT ANY WARRANTY; without even the implied warranty of
25MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26GNU General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with GNU CC; see the file COPYING. If not, write to
30the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
31
32#ifndef FILE
33#include <stdio.h>
34#endif
35
36#define FP_TOP (gen_rtx(REG, DFmode, FIRST_FLOAT_REG))
37
38#define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx))
39#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
40
41#define RET return ""
42
43/* #define RETCOM(X) fprintf (asm_out_file, "%sX fp_pop_level=%d\n", \
44 COMMENT_BEGIN, fp_pop_level); RET */
45#define RETCOM(X) return ""
46
47#define POP_ONE_FP \
48 { /* fp_pop_level--; */ \
49 fprintf (asm_out_file, "\tfstp %sst(0)\n", RP); }
50
51extern FILE *asm_out_file;
52static char *singlemove_string ();
53static void output_movf ();
54static void replace_float_constant ();
55static int mentions_fp_top ();
56static int call_top_dead_p ();
57static int fp_top_dead_p1 ();
58static rtx via_memory ();
59static void output_asm_insn_double_reg_op ();
60
61/* All output functions must increment or decrement this to indicate
62 the net number of pops or pushes which they perform. Note that it won't
63 necessarily balance with the optimize running, since we might have
64 two different calls with the same pop shared by cross jumping.
65 However on optimize the reg dead heuristic seems to work. */
66
67int fp_pop_level = 0;
68
69static char *hi_reg_name[] = HI_REGISTER_NAMES;
70static char *qi_reg_name[] = QI_REGISTER_NAMES;
71\f
72/* for fabs, fch, .. where the argument operand[1] must first be moved to
73 constraints "=fm" "0" */
74
75#define FP_CALL1(op) \
76 { if (FP_REG_P (operands[0])) \
77 return op; \
78 output_movf (FP_TOP, operands[1]); \
79 output_asm_insn (op, operands); \
80 /* fp_pop_level--; */ \
81 return "fstp%z0 %0"; }
82
83/* handle case of call where op0/op1 is "=mf" and opn is "mrf"
84 eg. fadd */
85#define FP_CALL(op, rev, n) \
86 return fp_call_internal (op, rev, n, operands, insn);
87
88static char *
89fp_call_internal (op, rev, n, operands, insn)
90 char *op;
91 char *rev;
92 int n;
93 rtx *operands;
94 rtx insn;
95{
96 if (!FP_REG_P (operands[0]))
97 {
98 /* Here destination is in memory
99 and source is in the fp stack. */
100 output_movf (FP_TOP, operands[0]);
101 output_asm_insn_double_reg_op (op, rev, insn);
102 return "fstp%z0 %0";
103 }
104
105 if (FP_REG_P (operands[n]))
106 {
107 rtx temp = operands[1];
108 char *tem1 = op;
109 operands[1] = operands[n];
110 op = rev;
111 operands[n] = temp;
112 rev = tem1;
113 }
114
115 if (REG_P (operands[n]))
116 {
117 rtx xops[2];
118 via_memory (operands[n]);
119 operands[n] = AT_SP (GET_MODE (operands[n]));
120 xops[0] = stack_pointer_rtx;
121 xops[1] = gen_rtx (CONST_INT, VOIDmode,
122 GET_MODE_SIZE (GET_MODE (operands[n])));
123 output_asm_insn (op, operands + n);
124 output_asm_insn (AS2 (add%L0,%1,%0), xops);
125 }
126 else
127 output_asm_insn (op, operands + n);
128
129 if (FP_REG_P (operands[0]))
130 {
131 /* It turns out not to work to use top_dead_p because
132 the death notes are not accurate enough.
133 But this ought to work, because the only thing that can
134 live across basic blocks is reg 8, and these insns
135 never involve reg 8 directly. */
136 if (fp_top_dead_p1 (insn))
137 POP_ONE_FP;
138 }
139
140 RET;
141}
142
143/* Output assembler code to perform insn OP
144 with two stack operands, and output on the stack.
145
146 REV is the assembler insn that does the same thing but
147 effectively interchanges the meanings of the two arguments.
148
149 Somewhat counterintuitively, the "first" operand was pushed last.
150
151 The output replaces either the top-of-stack or both of the arguments,
152 depending on whether the other argument is wanted after this insn. */
153
154static void
155output_asm_insn_double_reg_op (op, rev, insn)
156 char *op;
157 char *rev;
158 rtx insn;
159{
160 fputc ('\t', asm_out_file);
161 if (top_dead_p (insn))
162 {
163 /* Here we want the "reversed" insn, fsubr or fdivr.
164 But there is an assembler bug in all 80386 assemblers
165 which exchanges the meanings of fsubr and fsub, and of fdivr and fdiv!
166 So use the "unreversed" opcode (which will assemble into
167 the "reversed" insn). */
168 rev = op;
169
170 while (*rev && *rev != '%')
171 fputc (*rev++, asm_out_file);
172 /* fp_pop_level--; */
173
174 fprintf (asm_out_file, AS2 (p,%sst,%sst(1)), RP, RP);
175 }
176 else
177 {
178 while (*op && *op != '%')
179 fputc (*op++, asm_out_file);
180 fprintf (asm_out_file,AS2 ( ,%sst(1),%sst), RP, RP);
181 }
182 putc ('\n', asm_out_file);
183}
184
185/* Moves X to memory location 8 below stack pointer
186 and returns an RTX for that memory location.
187 X should be a register, in DFmode or SFmode. */
188
189static rtx
190via_memory (x)
191 rtx x;
192{
193 if (!REG_P (x))
194 abort ();
195 if (GET_MODE (x) == DFmode)
196 {
197 rtx xops[1];
198 xops[0] = gen_rtx (REG, SImode, REGNO (x) + 1);
199 output_asm_insn ("push%L0 %0", xops);
200 }
201 output_asm_insn ("push%L0 %0", &x);
202}
203\f
204/* Output an insn to copy the SFmode value in fp0 to OPERAND
205 without clobbering fp0. */
206
207void
208fp_store_sf (target)
209 rtx target;
210{
211 if (REG_P (target))
212 {
213 rtx xoperands[3];
214 xoperands[0] = stack_pointer_rtx;
215 xoperands[1] = AT_SP (Pmode);
216 xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4);
217 output_asm_insn (AS2 (add%L0,%2,%0), xoperands);
218 output_asm_insn ("fst%S0 %1", xoperands);
219 output_asm_insn ("pop%L0 %0", &target);
220 }
221 else if (GET_CODE (target) == MEM)
222 output_asm_insn ("fst%S0 %0", &target);
223}
224
225/* Output an insn to pop an SF value from fp0 into TARGET.
226 This destroys the value of fp0. */
227
228void
229fp_pop_sf (target)
230 rtx target;
231{
232 if (REG_P (target))
233 {
234 rtx xoperands[3];
235 xoperands[0] = stack_pointer_rtx;
236 xoperands[1] = AT_SP (Pmode);
237 xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4);
238 output_asm_insn (AS2 (add%L0,%2,%0), xoperands);
239 output_asm_insn ("fstp%S0 %1", xoperands);
240 output_asm_insn ("pop%L0 %0", &target);
241 /* fp_pop_level--; */
242 }
243 else if (GET_CODE (target) == MEM)
244 {
245 /* fp_pop_level--; */
246 output_asm_insn ("fstp%S0 %0", &target);
247 }
248 else abort ();
249}
250\f
251/* Copy the top of the fpu stack into TARGET, without popping. */
252
253void
254fp_store_df (target)
255 rtx target;
256{
257 if (REG_P (target))
258 {
259 rtx xoperands[4];
260 xoperands[0] = stack_pointer_rtx;
261 xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1);
262 xoperands[2] = AT_SP (Pmode);
263 xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8);
264 output_asm_insn (AS2 (add%L0,%3,%0), xoperands);
265 output_asm_insn ("fst%Q0 %2", xoperands);
266 output_asm_insn ("pop%L0 %0", &target);
267 output_asm_insn ("pop%L0 %1", xoperands);
268 }
269 else if (GET_CODE (target) == MEM)
270 output_asm_insn ("fst%Q0 %0", &target);
271}
272
273/* Copy the top of the fpu stack into TARGET, with popping. */
274
275void
276fp_pop_df (target)
277 rtx target;
278{
279 if (REG_P (target))
280 {
281 rtx xoperands[4];
282 xoperands[0] = stack_pointer_rtx;
283 xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1);
284 xoperands[2] = AT_SP (Pmode);
285 xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8);
286 output_asm_insn (AS2 (add%L0,%3,%0), xoperands);
287 /* fp_pop_level--; */
288 output_asm_insn ("fstp%Q0 %2", xoperands);
289 output_asm_insn ("pop%L0 %0", &target);
290 output_asm_insn ("pop%L0 %1", xoperands);
291 }
292 else if (GET_CODE (target) == MEM)
293 {
294 /* fp_pop_level--; */
295 output_asm_insn ("fstp%z0 %0", &target);
296 }
297}
298\f
299#if 0
300/* Pop the fp stack, convert value to integer and store in TARGET.
301 TARGET may be memory or register, and may have QI, HI or SImode. */
302
303void
304fp_pop_int (target)
305 rtx target;
306{
307 if (REG_P (target) || GET_MODE (target) != SImode)
308 {
309 rtx xxops[2];
310 xxops[0] = stack_pointer_rtx;
311 xxops[1] = gen_rtx (CONST_INT, VOIDmode, 4);
312 output_asm_insn (AS2 (sub%L0,%1,%0), xxops);
313 xxops[0] = AT_SP (Pmode);
314 /* fp_pop_level--; */
315 output_asm_insn ("fistp%L0 %0", xxops);
316 output_asm_insn ("pop%L0 %0", &target);
317 }
318 else if (GET_CODE (target) == MEM)
319 {
320 /* fp_pop_level--; */
321 output_asm_insn ("fistp%L0 %0", &target);
322 }
323 else abort ();
324}
325#endif
326\f
327/* Push the SFmode value X onto the fpu stack. */
328
329void
330fp_push_sf (x)
331 rtx x;
332{
333 /* fp_pop_level++; */
334 if (REG_P (x))
335 {
336 rtx xoperands[2];
337 rtx xfops[3];
338 output_asm_insn ("push%L0 %0", &x);
339 xfops[0] = AT_SP (Pmode);
340 xfops[2] = gen_rtx (CONST_INT, VOIDmode, 4);
341 xfops[1] = stack_pointer_rtx;
342 output_asm_insn ("fld%S0 %0\n\tadd%L0 %2,%1", xfops);
343 }
344 else
345 output_asm_insn ("fld%S0 %0", &x);
346}
347
348/* Push the DFmode value X onto the fpu stack. */
349
350void
351fp_push_df (x)
352 rtx x;
353{
354 /* fp_pop_level++; */
355
356 if (REG_P (x))
357 {
358 rtx xoperands[2];
359 rtx xfops[3];
360 xoperands[0] = x;
361 xoperands[1] = gen_rtx (REG, SImode, REGNO (x) + 1);
362 output_asm_insn ("push%L0 %1", xoperands);
363 output_asm_insn ("push%L0 %0", xoperands);
364 xfops[0] = AT_SP (Pmode);
365 xfops[2] = gen_rtx (CONST_INT, VOIDmode, 8);
366 xfops[1] = stack_pointer_rtx;
367 output_asm_insn ("fld%Q0 %0\n\tadd%L0 %2,%1", xfops);
368 }
369 else if (GET_CODE (x) == MEM)
370 output_asm_insn ("fld%Q0 %0", &x);
371}
372\f
373static char *output_move_const_single ();
374
375static char *
376singlemove_string (operands)
377 rtx *operands;
378{
379 rtx x;
380 if (GET_CODE (operands[0]) == MEM
381 && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
382 {
383 if (XEXP (x, 0) != stack_pointer_rtx)
384 abort ();
385 return "push%L0 %1";
386 }
387 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
388 {
389 return output_move_const_single (operands);
390 }
391 else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
392 return AS2 (mov%L0,%1,%0);
393 else if (CONSTANT_P (operands[1]))
394 return AS2 (mov%L0,%1,%0);
395 else
396 {
397 output_asm_insn ("push%L0 %1", operands);
398 return "pop%L0 %0";
399 }
400}
401\f
402/* Return a REG that occurs in ADDR with coefficient 1.
403 ADDR can be effectively incremented by incrementing REG. */
404
405static rtx
406find_addr_reg (addr)
407 rtx addr;
408{
409 while (GET_CODE (addr) == PLUS)
410 {
411 if (GET_CODE (XEXP (addr, 0)) == REG)
412 addr = XEXP (addr, 0);
413 else if (GET_CODE (XEXP (addr, 1)) == REG)
414 addr = XEXP (addr, 1);
415 else if (CONSTANT_P (XEXP (addr, 0)))
416 addr = XEXP (addr, 1);
417 else if (CONSTANT_P (XEXP (addr, 1)))
418 addr = XEXP (addr, 0);
419 else
420 abort ();
421 }
422 if (GET_CODE (addr) == REG)
423 return addr;
424 abort ();
425}
426
427/* Output an insn to add the constant N to the register X. */
428
429static void
430asm_add (n, x)
431 int n;
432 rtx x;
433{
434 rtx xops[2];
435 xops[1] = x;
436 if (n < 0)
437 {
438 xops[0] = gen_rtx (CONST_INT, VOIDmode, -n);
439 output_asm_insn (AS2 (sub%L0,%0,%1), xops);
440 }
441 else if (n > 0)
442 {
443 xops[0] = gen_rtx (CONST_INT, VOIDmode, n);
444 output_asm_insn (AS2 (add%L0,%0,%1), xops);
445 }
446}
447
448/* Output assembler code to perform a doubleword move insn
449 with operands OPERANDS. */
450
451char *
452output_move_double (operands)
453 rtx *operands;
454{
455 enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
456 rtx latehalf[2];
457 rtx addreg0 = 0, addreg1 = 0;
458
459 /* First classify both operands. */
460
461 if (REG_P (operands[0]))
462 optype0 = REGOP;
463 else if (offsettable_memref_p (operands[0]))
464 optype0 = OFFSOP;
465 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
466 optype0 = POPOP;
467 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
468 optype0 = PUSHOP;
469 else if (GET_CODE (operands[0]) == MEM)
470 optype0 = MEMOP;
471 else
472 optype0 = RNDOP;
473
474 if (REG_P (operands[1]))
475 optype1 = REGOP;
476 else if (CONSTANT_P (operands[1])
477 || GET_CODE (operands[1]) == CONST_DOUBLE)
478 optype1 = CNSTOP;
479 else if (offsettable_memref_p (operands[1]))
480 optype1 = OFFSOP;
481 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
482 optype1 = POPOP;
483 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
484 optype1 = PUSHOP;
485 else if (GET_CODE (operands[1]) == MEM)
486 optype1 = MEMOP;
487 else
488 optype1 = RNDOP;
489
490 /* Check for the cases that the operand constraints are not
491 supposed to allow to happen. Abort if we get one,
492 because generating code for these cases is painful. */
493
494 if (optype0 == RNDOP || optype1 == RNDOP)
495 abort ();
496
497 /* If one operand is decrementing and one is incrementing
498 decrement the former register explicitly
499 and change that operand into ordinary indexing. */
500
501 if (optype0 == PUSHOP && optype1 == POPOP)
502 {
503 operands[0] = XEXP (XEXP (operands[0], 0), 0);
504 asm_add (-8, operands[0]);
505 operands[0] = gen_rtx (MEM, DImode, operands[0]);
506 optype0 = OFFSOP;
507 }
508 if (optype0 == POPOP && optype1 == PUSHOP)
509 {
510 operands[1] = XEXP (XEXP (operands[1], 0), 0);
511 asm_add (-8, operands[1]);
512 operands[1] = gen_rtx (MEM, DImode, operands[1]);
513 optype1 = OFFSOP;
514 }
515
516 /* If an operand is an unoffsettable memory ref, find a register
517 we can increment temporarily to make it refer to the second word. */
518
519 if (optype0 == MEMOP)
520 addreg0 = find_addr_reg (XEXP (operands[0], 0));
521
522 if (optype1 == MEMOP)
523 addreg1 = find_addr_reg (XEXP (operands[1], 0));
524
525 /* Ok, we can do one word at a time.
526 Normally we do the low-numbered word first,
527 but if either operand is autodecrementing then we
528 do the high-numbered word first.
529
530 In either case, set up in LATEHALF the operands to use
531 for the high-numbered word and in some cases alter the
532 operands in OPERANDS to be suitable for the low-numbered word. */
533
534 if (optype0 == REGOP)
535 latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
536 else if (optype0 == OFFSOP)
537 latehalf[0] = adj_offsettable_operand (operands[0], 4);
538 else
539 latehalf[0] = operands[0];
540
541 if (optype1 == REGOP)
542 latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
543 else if (optype1 == OFFSOP)
544 latehalf[1] = adj_offsettable_operand (operands[1], 4);
545 else if (optype1 == CNSTOP)
546 {
547 if (CONSTANT_P (operands[1]))
548 latehalf[1] = const0_rtx;
549 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
550 {
551 latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
552 CONST_DOUBLE_HIGH (operands[1]));
553 operands[1] = gen_rtx (CONST_INT, VOIDmode,
554 CONST_DOUBLE_LOW (operands[1]));
555 }
556 }
557 else
558 latehalf[1] = operands[1];
559
560 /* If insn is effectively movd N (sp),-(sp) then we will do the
561 high word first. We should use the adjusted operand 1 (which is N+4 (sp))
562 for the low word as well, to compensate for the first decrement of sp. */
563 if (optype0 == PUSHOP
564 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
565 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
566 operands[1] = latehalf[1];
567
568 /* If one or both operands autodecrementing,
569 do the two words, high-numbered first. */
570
571 /* Likewise, the first move would clobber the source of the second one,
572 do them in the other order. This happens only for registers;
573 such overlap can't happen in memory unless the user explicitly
574 sets it up, and that is an undefined circumstance. */
575
576 if (optype0 == PUSHOP || optype1 == PUSHOP
577 || (optype0 == REGOP && optype1 == REGOP
578 && REGNO (operands[0]) == REGNO (latehalf[1])))
579 {
580 /* Make any unoffsettable addresses point at high-numbered word. */
581 if (addreg0)
582 asm_add (4, addreg0);
583 if (addreg1)
584 asm_add (4, addreg1);
585
586 /* Do that word. */
587 output_asm_insn (singlemove_string (latehalf), latehalf);
588
589 /* Undo the adds we just did. */
590 if (addreg0)
591 asm_add (-4, addreg0);
592 if (addreg1)
593 asm_add (-4, addreg1);
594
595 /* Do low-numbered word. */
596 return singlemove_string (operands);
597 }
598
599 /* Normal case: do the two words, low-numbered first. */
600
601 output_asm_insn (singlemove_string (operands), operands);
602
603 /* Make any unoffsettable addresses point at high-numbered word. */
604 if (addreg0)
605 asm_add (4, addreg0);
606 if (addreg1)
607 asm_add (4, addreg1);
608
609 /* Do that word. */
610 output_asm_insn (singlemove_string (latehalf), latehalf);
611
612 /* Undo the adds we just did. */
613 if (addreg0)
614 asm_add (-4, addreg0);
615 if (addreg1)
616 asm_add (-4, addreg1);
617
618 return "";
619}
620\f
621int
622standard_80387_constant_p (x)
623 rtx x;
624{
625 union { double d; int i[2];} u;
626 register double d;
627 u.i[0] = XINT (x, 0);
628 u.i[1] = XINT (x, 1);
629 d = u.d;
630
631 if (d == 0)
632 return 1;
633 if (d == 1)
634 return 2;
635 /* Note that on the 80387, other constants, such as pi,
636 are much slower to load as standard constants
637 than to load from doubles in memory! */
638
639 return 0;
640}
641
642static char *
643output_move_const_double (operands)
644 rtx *operands;
645{
646 if (FP_REG_P (operands[0]))
647 {
648 int conval = standard_80387_constant_p (operands[1]);
649
650 /* fp_pop_level++; */
651 if (conval == 1)
652 return "fldz";
653 if (conval == 2)
654 return "fld1";
655 /* fp_pop_level--; */
656 }
657
658 output_move_double (operands);
659}
660
661
662static char *
663output_move_const_single (operands)
664 rtx *operands;
665{
666 if (FP_REG_P (operands[0]))
667 {
668 int conval = standard_80387_constant_p (operands[1]);
669
670 /* fp_pop_level++; */
671 if (conval == 1)
672 return "fldz";
673 if (conval == 2)
674 return "fld1";
675 /* fp_pop_level--; */
676 }
677 if (GET_CODE (operands[1]) == CONST_DOUBLE)
678 {
679 union { int i[2]; double d;} u1;
680 union { int i; float f;} u2;
681 u1.i[0] = CONST_DOUBLE_LOW (operands[1]);
682 u1.i[1] = CONST_DOUBLE_HIGH (operands[1]);
683 u2.f = u1.d;
684 operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i);
685 }
686 return singlemove_string (operands);
687}
688\f
689/* Output an insn to move an SF value from FROM to TO.
690 The kinds of operands are not restricted
691 except that they may not both be in memory. */
692
693void
694output_movsf (to, from)
695 rtx from, to;
696{
697 rtx xops[2];
698 xops[0] = to;
699 xops[1] = from;
700 if (FP_REG_P (from) || FP_REG_P (to))
701 {
702 from = xops[1];
703 }
704
705 if (FP_REG_P (from))
706 {
707#if 0
708 {
709 if (REGNO (from) != REGNO (to))
710 {
711 output_asm_insn ("fld%S0 %1\n\tfstp%S0 %0", xops);
712 }
713 }
714 else
715#endif
716
717 if (! FP_REG_P (to))
718 fp_pop_sf (to);
719 }
720 else if (FP_REG_P (to))
721 fp_push_sf (from);
722 else
723 output_asm_insn (singlemove_string (xops), xops);
724}
725
726/* Output an insn to move a DF value from FROM to TO.
727 The kinds of operands are not restricted
728 except that they may not both be in memory. */
729
730void
731output_movdf (to, from)
732 rtx from, to;
733{
734 rtx xops[2];
735 xops[0] = to;
736 xops[1] = from;
737 if (FP_REG_P (from) || FP_REG_P (to))
738 {
739 from = xops[1];
740 to = xops[0];
741 }
742 if (FP_REG_P (from))
743 {
744#if 0
745 {
746 if (REGNO (from) != REGNO (to))
747 abort ();
748/* output_asm_insn ("fld%Q0 %1\n\t fstp%Q0 %0", xops);*/
749 }
750 else
751 {
752#endif
753 if (! FP_REG_P (to))
754 fp_pop_df (to);
755 }
756 else if (FP_REG_P (to))
757 fp_push_df (from);
758 else
759 output_asm_insn (output_move_double (xops), xops);
760}
761
762/* does move of FROM to TO where the mode is the minimum of the
763two */
764
765static void
766output_movf (to, from)
767 rtx to, from;
768{
769 if (GET_MODE (from) == SFmode || GET_MODE (to) == SFmode)
770 output_movsf (to, from);
771 else
772 output_movdf (to, from);
773}
774\f
775/* Return the best assembler insn template
776 for moving operands[1] into operands[0] as a fullword. */
777
778void
779function_prologue (file, size)
780 FILE *file;
781 int size;
782{
783 register int regno;
784 int nregs, limit;
785 rtx xops[4];
786 extern int frame_pointer_needed;
787
788 /* fp_pop_level = 0; */
789 xops[0] = stack_pointer_rtx;
790 xops[1] = frame_pointer_rtx;
791 xops[2] = gen_rtx (CONST_INT, VOIDmode, size);
792 if (frame_pointer_needed)
793 {
794 output_asm_insn ("push%L0 %1", xops);
795 output_asm_insn (AS2 (mov%L0,%0,%1), xops);
796 if (size)
797 output_asm_insn (AS2 (sub%L0,%2,%0), xops);
798 }
799
800 /* Note If use enter it is NOT reversed args.
801 This one is not reversed from intel!!
802 I think enter is slower. Also sdb doesn't like it.
803 But if you want it the code is:
804 {
805 xops[3] = const0_rtx;
806 output_asm_insn ("enter %2,%3", xops);
807 }
808 */
809 nregs = 0;
810 limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
811 for (regno = limit - 1; regno >= 0; regno--)
812 if (regs_ever_live[regno] && ! call_used_regs[regno])
813 {
814 fprintf (file, "\tpush%s %se%s\n", L_SIZE, RP, hi_reg_name[regno]);
815 }
816}
817
818void
819function_epilogue (file, size)
820 FILE *file;
821 int size;
822{
823 register int regno;
824 register int nregs, limit;
825 int assure_sp_pos;
826 int return_struct_adjust;
827 extern int frame_pointer_needed;
828 extern int current_function_pops_args;
829 extern int current_function_args_size;
830 extern int flag_pcc_struct_return;
831
832 limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
833 nregs = 0;
834
835 return_struct_adjust =
836 (current_function_returns_struct
837#ifdef STRUCT_RETURN_CALLER_POP
838 && !flag_pcc_struct_return
839#endif
840 ? 4 : 0);
841
842 for (regno = (limit -1); regno >= 0; regno--)
843 if (regs_ever_live[regno] && ! call_used_regs[regno])
844 nregs++;
845
846 /* sp is often unreliable so we must go off the frame pointer,
847 */
848
849 if (nregs && frame_pointer_needed)
850 {
851 rtx xops[2];
852 xops[0] = adj_offsettable_operand (AT_BP (Pmode),
853 -size -(nregs*(UNITS_PER_WORD)));
854 xops[1] = stack_pointer_rtx;
855 output_asm_insn (AS2 (lea%L0,%0,%1), xops);
856 }
857 for (regno = 0; regno < limit; regno++)
858 {
859 if (regs_ever_live[regno] && ! call_used_regs[regno])
860 {
861 fprintf (file, "\tpop%s ", L_SIZE);
862 fprintf (file, "%se%s\n", RP, hi_reg_name[regno]);
863 }
864 }
865
866 if (frame_pointer_needed)
867 fprintf (file, "\tleave\n");
868 if (current_function_pops_args && current_function_args_size)
869 fprintf (file, "\tret %s%d\n", IP,
870 (current_function_args_size + return_struct_adjust));
871 else if (return_struct_adjust)
872 fprintf (file, "\tret %s%d\n", IP, return_struct_adjust);
873 else
874 fprintf (file, "\tret\n");
875}
876
877int
878hard_regno_mode_ok (regno, mode)
879 int regno;
880 enum machine_mode mode;
881{
882 return
883 (regno < 2 ? 1
884 /* Used to reject floating modes here */
885 : regno < 4 ? 1
886 : regno >= 8 ? mode == DFmode || mode == SFmode
887 : mode != QImode);
888}
889\f
890/* Print the name of a register based on its machine mode and number.
891 If CODE is 'w', pretend the mode is HImode.
892 If CODE is 'b', pretend the mode is QImode.
893 If CODE is 'k', pretend the mode is SImode. */
894
895#define PRINT_REG(X, CODE, FILE) \
896 do { fprintf (FILE, "%s", RP); \
897 switch ((CODE == 'w' ? 2 \
898 : CODE == 'b' ? 1 \
899 : CODE == 'k' ? 4 \
900 : GET_MODE_SIZE (GET_MODE (X)))) \
901 { \
902 case 4: \
903 case 8: \
904 if (!FP_REG_P (X)) fputs ("e", FILE); \
905 case 2: \
906 fputs (hi_reg_name[REGNO (X)], FILE); \
907 break; \
908 case 1: \
909 fputs (qi_reg_name[REGNO (X)], FILE); \
910 break; \
911 } \
912 } while (0)
913
914/* Meaning of CODE:
915 f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
916 L,W,B,Q,S -- print the opcode suffix for specified size of operand.
917 R -- print the prefix for register names.
918 z -- print the opcode suffix for the size of the current operand.
919 * -- print a star (in certain assembler syntax)
920 w -- print the operand as if it's a "word" (HImode) even if it isn't.
921 c -- don't print special prefixes before constant operands.
922*/
923
924void
925print_operand (file, x, code)
926 FILE *file;
927 rtx x;
928 int code;
929{
930 if (code)
931 {
932 switch (code)
933 {
934 case '*':
935 if (USE_STAR)
936 putc ('*', file);
937 return;
938
939 case 'L':
940 PUT_OP_SIZE (code, 'l', file);
941 return;
942
943 case 'W':
944 PUT_OP_SIZE (code, 'w', file);
945 return;
946
947 case 'B':
948 PUT_OP_SIZE (code, 'b', file);
949 return;
950
951 case 'Q':
952 PUT_OP_SIZE (code, 'l', file);
953 return;
954
955 case 'S':
956 PUT_OP_SIZE (code, 's', file);
957 return;
958
959 case 'R':
960 fprintf (file, "%s", RP);
961 return;
962
963 case 'z':
964 /* this is the size of op from size of operand */
965 switch (GET_MODE_SIZE (GET_MODE (x)))
966 {
967 case 2:
968 PUT_OP_SIZE ('W', 'w', file);
969 return;
970 case 4:
971 if (GET_MODE (x) == SFmode)
972 {
973 PUT_OP_SIZE ('S', 's', file);
974 return;
975 }
976 else
977 PUT_OP_SIZE ('L', 'l', file);
978 return;
979 case 8:
980 if (!FP_REG_P (x)) PUT_OP_SIZE ('Q', 'l', file);
981 return;
982 case 1:
983 PUT_OP_SIZE ('B', 'b', file);
984 return;
985 }
986 }
987 }
988 if (GET_CODE (x) == REG)
989 {
990 PRINT_REG (x, code, file);
991 }
992 else if (GET_CODE (x) == MEM)
993 {
994 PRINT_PTR (x, file);
995 if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
996 output_addr_const (file, XEXP (x, 0));
997 else
998 output_address (XEXP (x, 0));
999 }
1000 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
1001 {
1002 union { double d; int i[2]; } u;
1003 union { float f; int i; } u1;
1004 u.i[0] = CONST_DOUBLE_LOW (x);
1005 u.i[1] = CONST_DOUBLE_HIGH (x);
1006 u1.f = u.d;
1007 if (code == 'f')
1008 fprintf (file, "%.22e", u1.f);
1009 else
1010 {
1011 PRINT_IMMED_PREFIX (file);
1012 fprintf (file, "0x%x", u1.i);
1013 }
1014 }
1015 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
1016 {
1017 union { double d; int i[2]; } u;
1018 u.i[0] = CONST_DOUBLE_LOW (x);
1019 u.i[1] = CONST_DOUBLE_HIGH (x);
1020 fprintf (file, "%.22e", u.d);
1021 }
1022 else
1023 {
1024 if (code != 'c')
1025 {
1026 if (GET_CODE (x) == CONST_INT)
1027 PRINT_IMMED_PREFIX (file);
1028 else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
1029 PRINT_OFFSET_PREFIX (file);
1030 }
1031 output_addr_const (file, x);
1032 }
1033}
1034\f
1035/* Print a memory operand whose address is ADDR. */
1036
1037void
1038print_operand_address (file, addr)
1039 FILE *file;
1040 register rtx addr;
1041{
1042 register rtx reg1, reg2, breg, ireg;
1043 rtx offset;
1044
1045 switch (GET_CODE (addr))
1046 {
1047 case REG:
1048 ADDR_BEG (file);
1049 fprintf (file, "%se", RP);
1050 fputs (hi_reg_name[REGNO (addr)], file);
1051 ADDR_END (file);
1052 break;
1053
1054 case PLUS:
1055 reg1 = 0;
1056 reg2 = 0;
1057 ireg = 0;
1058 breg = 0;
1059 offset = 0;
1060 if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
1061 {
1062 offset = XEXP (addr, 0);
1063 addr = XEXP (addr, 1);
1064 }
1065 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
1066 {
1067 offset = XEXP (addr, 1);
1068 addr = XEXP (addr, 0);
1069 }
1070 if (GET_CODE (addr) != PLUS) ;
1071 else if (GET_CODE (XEXP (addr, 0)) == MULT)
1072 {
1073 reg1 = XEXP (addr, 0);
1074 addr = XEXP (addr, 1);
1075 }
1076 else if (GET_CODE (XEXP (addr, 1)) == MULT)
1077 {
1078 reg1 = XEXP (addr, 1);
1079 addr = XEXP (addr, 0);
1080 }
1081 else if (GET_CODE (XEXP (addr, 0)) == REG)
1082 {
1083 reg1 = XEXP (addr, 0);
1084 addr = XEXP (addr, 1);
1085 }
1086 else if (GET_CODE (XEXP (addr, 1)) == REG)
1087 {
1088 reg1 = XEXP (addr, 1);
1089 addr = XEXP (addr, 0);
1090 }
1091 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
1092 {
1093 if (reg1 == 0) reg1 = addr;
1094 else reg2 = addr;
1095 addr = 0;
1096 }
1097 if (offset != 0)
1098 {
1099 if (addr != 0) abort ();
1100 addr = offset;
1101 }
1102 if ((reg1 && GET_CODE (reg1) == MULT)
1103 || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
1104 {
1105 breg = reg2;
1106 ireg = reg1;
1107 }
1108 else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
1109 {
1110 breg = reg1;
1111 ireg = reg2;
1112 }
1113
1114 if (ireg != 0 || breg != 0)
1115 {
1116 int scale = 1;
1117
1118 if (addr != 0)
1119 {
1120 if (GET_CODE (addr) == LABEL_REF)
1121 output_asm_label (addr);
1122 else
1123 output_addr_const (file, addr);
1124 }
1125
1126 if (ireg != 0 && GET_CODE (ireg) == MULT)
1127 {
1128 scale = INTVAL (XEXP (ireg, 1));
1129 ireg = XEXP (ireg, 0);
1130 }
1131 /* output breg+ireg*scale */
1132 PRINT_B_I_S (breg, ireg, scale, file);
1133 break;
1134 }
1135
1136 case MULT:
1137 {
1138 int scale;
1139 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1140 {
1141 scale = INTVAL (XEXP (addr, 0));
1142 ireg = XEXP (addr, 1);
1143 }
1144 else
1145 {
1146 scale = INTVAL (XEXP (addr, 1));
1147 ireg = XEXP (addr, 0);
1148 }
1149 output_addr_const (file, const0_rtx);
1150 PRINT_B_I_S ((rtx) 0, ireg, scale, file);
1151 }
1152 break;
1153
1154 default:
1155 if (GET_CODE (addr) == CONST_INT
1156 && INTVAL (addr) < 0x8000
1157 && INTVAL (addr) >= -0x8000)
1158 fprintf (file, "%d", INTVAL (addr));
1159 else
1160 output_addr_const (file, addr);
1161 }
1162}
1163\f
1164/* Set the cc_status for the results of an insn whose pattern is EXP.
1165 On the 80386, we assume that only test and compare insns, as well
1166 as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT,
1167 ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
1168 Also, we assume that jumps and moves don't affect the condition codes.
1169 All else, clobbers the condition codes, by assumption.
1170
1171 We assume that ALL add, minus, etc. instructions effect the condition
1172 codes. This MUST be consistent with i386.md. */
1173
1174notice_update_cc (exp)
1175 rtx exp;
1176{
1177 if (GET_CODE (exp) == SET)
1178 {
1179 /* Jumps do not alter the cc's. */
1180 if (SET_DEST (exp) == pc_rtx)
1181 return;
1182 /* Moving register or memory into a register:
1183 it doesn't alter the cc's, but it might invalidate
1184 the RTX's which we remember the cc's came from.
1185 (Note that moving a constant 0 or 1 MAY set the cc's). */
1186 if (REG_P (SET_DEST (exp))
1187 && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM))
1188 {
1189 if (cc_status.value1
1190 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1191 cc_status.value1 = 0;
1192 if (cc_status.value2
1193 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1194 cc_status.value2 = 0;
1195 return;
1196 }
1197 /* Moving register into memory doesn't alter the cc's.
1198 It may invalidate the RTX's which we remember the cc's came from. */
1199 if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp)))
1200 {
1201 if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
1202 cc_status.value1 = 0;
1203 if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
1204 cc_status.value2 = 0;
1205 return;
1206 }
1207 /* Function calls clobber the cc's. */
1208 else if (GET_CODE (SET_SRC (exp)) == CALL)
1209 {
1210 CC_STATUS_INIT;
1211 return;
1212 }
1213 /* Tests and compares set the cc's in predictable ways. */
1214 else if (SET_DEST (exp) == cc0_rtx)
1215 {
1216 CC_STATUS_INIT;
1217 cc_status.value1 = SET_SRC (exp);
1218 return;
1219 }
1220 /* Certain instructions effect the condition codes. */
1221 else if (GET_MODE (SET_SRC (exp)) == SImode
1222 || GET_MODE (SET_SRC (exp)) == HImode
1223 || GET_MODE (SET_SRC (exp)) == QImode)
1224 switch (GET_CODE (SET_SRC (exp)))
1225 {
1226 case ASHIFTRT: case LSHIFTRT:
1227 case ASHIFT: case LSHIFT:
1228 /* Shifts on the 386 don't set the condition codes if the
1229 shift count is zero. */
1230 if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
1231 {
1232 CC_STATUS_INIT;
1233 break;
1234 }
1235 /* We assume that the CONST_INT is non-zero (this rtx would
1236 have been deleted if it were zero. */
1237
1238 case PLUS: case MINUS: case NEG:
1239 case AND: case IOR: case XOR:
1240 cc_status.flags = CC_NO_OVERFLOW;
1241 cc_status.value1 = SET_SRC (exp);
1242 cc_status.value2 = SET_DEST (exp);
1243 break;
1244
1245 default:
1246 CC_STATUS_INIT;
1247 }
1248 else
1249 {
1250 CC_STATUS_INIT;
1251 }
1252 }
1253 else if (GET_CODE (exp) == PARALLEL
1254 && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1255 {
1256 if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
1257 return;
1258 if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
1259 {
1260 CC_STATUS_INIT;
1261 cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
1262 return;
1263 }
1264 CC_STATUS_INIT;
1265 }
1266 else
1267 {
1268 CC_STATUS_INIT;
1269 }
1270}
1271\f
1272/* Nonzero if the top of the fpu stack dies in this insn. */
1273
1274int
1275top_dead_p (insn)
1276 rtx insn;
1277{
1278 extern int optimize;
1279 if (optimize)
1280 return (find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG)
1281 || find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG + 1));
1282
1283 if (GET_CODE (insn) == CALL_INSN)
1284 return call_top_dead_p (insn);
1285
1286 return fp_top_dead_p1 (insn);
1287}
1288
1289/* Following is used after a call_value insn
1290 if obey_regdecls there will not be the REG_DEAD notes
1291 to go by (there won't be any cross jumping to worry about
1292 either), and we depend on seeing if the FP_TOP is used
1293 in the next two insn's. Otherwise we depend on the
1294 REG_DEAD notes.
1295 */
1296
1297static int
1298call_top_dead_p (insn)
1299 rtx insn;
1300{
1301 int i;
1302 for (i = 0; i < 3; i++)
1303 {
1304 insn = NEXT_INSN (insn);
1305 if (insn == 0)
1306 return 1;
1307 if (GET_CODE (insn) == NOTE || GET_CODE (insn) == CODE_LABEL)
1308 continue;
1309 if (GET_CODE (insn) == BARRIER)
1310 abort ();
1311 if (GET_CODE (PATTERN (insn)) == SET
1312 && SET_DEST (PATTERN (insn)) != stack_pointer_rtx)
1313 return (!(mentions_fp_top (SET_SRC (PATTERN (insn)))));
1314 if (GET_CODE (PATTERN (insn)) == CALL)
1315 return 1;
1316 if (GET_CODE (PATTERN (insn)) == USE)
1317 return (! FP_REG_P (XEXP (PATTERN (insn), 0)));
1318 }
1319 return 1;
1320}
1321
1322/* Return 1 if current val of fpu top-of-stack appears unused
1323 in rest of this basic block. */
1324
1325static int
1326fp_top_dead_p1 (insn)
1327 rtx insn;
1328{
1329 extern int optimize;
1330
1331 int past_label = 0;
1332
1333 for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
1334 {
1335 switch (GET_CODE (insn))
1336 {
1337 case CALL_INSN:
1338 /* Function calls clobber this value, so it's dead. */
1339 return 1;
1340
1341 case JUMP_INSN:
1342 if (! optimize)
1343 /* Can't use JUMP_LABEL, but there's no cross-jumping either. */
1344 return 1;
1345 if (JUMP_LABEL (insn) == 0)
1346 return 1;
1347 insn = JUMP_LABEL (insn);
1348 case CODE_LABEL:
1349 /* Go past one label or follow one jump in case of cross-jumping,
1350 which could insert such a label or jump into one basic block. */
1351 if (! optimize)
1352 return 1;
1353 if (past_label)
1354 return 1;
1355 past_label = 1;
1356 break;
1357
1358 case INSN:
1359 if (GET_CODE (PATTERN (insn)) == SET)
1360 {
1361 if ((mentions_fp_top (SET_SRC (PATTERN (insn)))))
1362 return 0;
1363 else if (FP_REG_P (SET_DEST (PATTERN (insn))))
1364 return 1;
1365 }
1366 else if (mentions_fp_top (PATTERN (insn)))
1367 return 0;
1368 break;
1369 }
1370 }
1371 return 1;
1372}
1373
1374/* Return 1 if X involves an FPU register. */
1375
1376static int
1377mentions_fp_top (x)
1378 rtx x;
1379{
1380 register RTX_CODE code;
1381
1382 code = GET_CODE (x);
1383 switch (code)
1384 {
1385 case LABEL_REF:
1386 case SYMBOL_REF:
1387 case CONST_INT:
1388 case CONST:
1389 case CC0:
1390 case PC:
1391 case CLOBBER:
1392 case MEM:
1393 return 0;
1394
1395 case REG:
1396 return FP_REGNO_P (REGNO (x));
1397 }
1398
1399 /* Recursively scan the operands of this expression. */
1400 {
1401 register char *fmt = GET_RTX_FORMAT (code);
1402 register int i;
1403
1404 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
1405 {
1406 if (fmt[i] == 'e')
1407 {
1408 if (mentions_fp_top (XEXP (x, i)))
1409 return 1;
1410 }
1411 if (fmt[i] == 'E')
1412 {
1413 register int j;
1414 for (j = 0; j < XVECLEN (x, i); j++)
1415 if (mentions_fp_top (XVECEXP (x, i, j)))
1416 return 1;
1417 }
1418 }
1419 }
1420 return 0;
1421}
1422
1423/* Some asm-dependent functions. */
1424
1425#ifdef MASM
1426#include "masm386.c"
1427#endif