home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 7 / FreshFishVol7.bin / bbs / gnu / gcc-2.3.3-src.lha / GNU / src / amiga / gcc-2.3.3 / config / i386.c < prev    next >
C/C++ Source or Header  |  1994-02-06  |  48KB  |  1,835 lines

  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 "config.h"
  22. #include "rtl.h"
  23. #include "regs.h"
  24. #include "hard-reg-set.h"
  25. #include "real.h"
  26. #include "insn-config.h"
  27. #include "conditions.h"
  28. #include "insn-flags.h"
  29. #include "output.h"
  30. #include "insn-attr.h"
  31. #include "tree.h"
  32. #include "flags.h"
  33.  
  34. #ifdef EXTRA_CONSTRAINT
  35. /* If EXTRA_CONSTRAINT is defined, then the 'S'
  36.    constraint in REG_CLASS_FROM_LETTER will no longer work, and various
  37.    asm statements that need 'S' for class SIREG will break.  */
  38.  error EXTRA_CONSTRAINT conflicts with S constraint letter
  39. /* The previous line used to be #error, but some compilers barf
  40.    even if the conditional was untrue.  */
  41. #endif
  42.  
  43. #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
  44.  
  45. extern FILE *asm_out_file;
  46. extern char *strcat ();
  47.  
  48. char *singlemove_string ();
  49. char *output_move_const_single ();
  50. char *output_fp_cc0_set ();
  51.  
  52. char *hi_reg_name[] = HI_REGISTER_NAMES;
  53. char *qi_reg_name[] = QI_REGISTER_NAMES;
  54. char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
  55.  
  56. /* Array of the smallest class containing reg number REGNO, indexed by
  57.    REGNO.  Used by REGNO_REG_CLASS in i386.h. */
  58.  
  59. enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
  60. {
  61.   /* ax, dx, cx, bx */
  62.   AREG, DREG, CREG, BREG,
  63.   /* si, di, bp, sp */
  64.   SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
  65.   /* FP registers */
  66.   FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
  67.   FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,       
  68.   /* arg pointer */
  69.   INDEX_REGS
  70. };
  71.  
  72. /* Test and compare insns in i386.md store the information needed to
  73.    generate branch and scc insns here.  */
  74.  
  75. struct rtx_def *i386_compare_op0, *i386_compare_op1;
  76. struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
  77.  
  78. /* Output an insn whose source is a 386 integer register.  SRC is the
  79.    rtx for the register, and TEMPLATE is the op-code template.  SRC may
  80.    be either SImode or DImode.
  81.  
  82.    The template will be output with operands[0] as SRC, and operands[1]
  83.    as a pointer to the top of the 386 stack.  So a call from floatsidf2
  84.    would look like this:
  85.  
  86.       output_op_from_reg (operands[1], AS1 (fild%z0,%1));
  87.  
  88.    where %z0 corresponds to the caller's operands[1], and is used to
  89.    emit the proper size suffix.
  90.  
  91.    ??? Extend this to handle HImode - a 387 can load and store HImode
  92.    values directly. */
  93.  
  94. void
  95. output_op_from_reg (src, template)
  96.      rtx src;
  97.      char *template;
  98. {
  99.   rtx xops[4];
  100.  
  101.   xops[0] = src;
  102.   xops[1] = AT_SP (Pmode);
  103.   xops[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (src)));
  104.   xops[3] = stack_pointer_rtx;
  105.  
  106.   if (GET_MODE_SIZE (GET_MODE (src)) > UNITS_PER_WORD)
  107.     {
  108.       rtx high = gen_rtx (REG, SImode, REGNO (src) + 1);
  109.       output_asm_insn (AS1 (push%L0,%0), &high);
  110.     }
  111.   output_asm_insn (AS1 (push%L0,%0), &src);
  112.  
  113.   output_asm_insn (template, xops);
  114.  
  115.   output_asm_insn (AS2 (add%L3,%2,%3), xops);
  116. }
  117.  
  118. /* Output an insn to pop an value from the 387 top-of-stack to 386
  119.    register DEST. The 387 register stack is popped if DIES is true.  If
  120.    the mode of DEST is an integer mode, a `fist' integer store is done,
  121.    otherwise a `fst' float store is done. */
  122.  
  123. void
  124. output_to_reg (dest, dies)
  125.      rtx dest;
  126.      int dies;
  127. {
  128.   rtx xops[4];
  129.  
  130.   xops[0] = AT_SP (Pmode);
  131.   xops[1] = stack_pointer_rtx;
  132.   xops[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (dest)));
  133.   xops[3] = dest;
  134.  
  135.   output_asm_insn (AS2 (sub%L1,%2,%1), xops);
  136.  
  137.   if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
  138.     {
  139.       if (dies)
  140.     output_asm_insn (AS1 (fistp%z3,%y0), xops);
  141.       else
  142.     output_asm_insn (AS1 (fist%z3,%y0), xops);
  143.     }
  144.   else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)
  145.     {
  146.       if (dies)
  147.     output_asm_insn (AS1 (fstp%z3,%y0), xops);
  148.       else
  149.     output_asm_insn (AS1 (fst%z3,%y0), xops);
  150.     }
  151.   else
  152.     abort ();
  153.  
  154.   output_asm_insn (AS1 (pop%L0,%0), &dest);
  155.  
  156.   if (GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD)
  157.     {
  158.       dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
  159.       output_asm_insn (AS1 (pop%L0,%0), &dest);
  160.     }
  161. }
  162.  
  163. char *
  164. singlemove_string (operands)
  165.      rtx *operands;
  166. {
  167.   rtx x;
  168.   if (GET_CODE (operands[0]) == MEM
  169.       && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
  170.     {
  171.       if (XEXP (x, 0) != stack_pointer_rtx)
  172.     abort ();
  173.       return "push%L1 %1";
  174.     }
  175.   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  176.     {
  177.       return output_move_const_single (operands);
  178.     }
  179.   else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
  180.     return AS2 (mov%L0,%1,%0);
  181.   else if (CONSTANT_P (operands[1]))
  182.     return AS2 (mov%L0,%1,%0);
  183.   else
  184.     {
  185.       output_asm_insn ("push%L1 %1", operands);
  186.       return "pop%L0 %0";
  187.     }
  188. }
  189.  
  190. /* Return a REG that occurs in ADDR with coefficient 1.
  191.    ADDR can be effectively incremented by incrementing REG.  */
  192.  
  193. static rtx
  194. find_addr_reg (addr)
  195.      rtx addr;
  196. {
  197.   while (GET_CODE (addr) == PLUS)
  198.     {
  199.       if (GET_CODE (XEXP (addr, 0)) == REG)
  200.     addr = XEXP (addr, 0);
  201.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  202.     addr = XEXP (addr, 1);
  203.       else if (CONSTANT_P (XEXP (addr, 0)))
  204.     addr = XEXP (addr, 1);
  205.       else if (CONSTANT_P (XEXP (addr, 1)))
  206.     addr = XEXP (addr, 0);
  207.       else
  208.     abort ();
  209.     }
  210.   if (GET_CODE (addr) == REG)
  211.     return addr;
  212.   abort ();
  213. }
  214.  
  215. /* Output an insn to add the constant N to the register X.  */
  216.  
  217. static void
  218. asm_add (n, x)
  219.      int n;
  220.      rtx x;
  221. {
  222.   rtx xops[2];
  223.   xops[1] = x;
  224.   if (n < 0)
  225.     {
  226.       xops[0] = GEN_INT (-n);
  227.       output_asm_insn (AS2 (sub%L0,%0,%1), xops);
  228.     }
  229.   else if (n > 0)
  230.     {
  231.       xops[0] = GEN_INT (n);
  232.       output_asm_insn (AS2 (add%L0,%0,%1), xops);
  233.     }
  234. }
  235.  
  236. /* Output assembler code to perform a doubleword move insn
  237.    with operands OPERANDS.  */
  238.  
  239. char *
  240. output_move_double (operands)
  241.      rtx *operands;
  242. {
  243.   enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  244.   rtx latehalf[2];
  245.   rtx addreg0 = 0, addreg1 = 0;
  246.   int dest_overlapped_low = 0;
  247.  
  248.   /* First classify both operands.  */
  249.  
  250.   if (REG_P (operands[0]))
  251.     optype0 = REGOP;
  252.   else if (offsettable_memref_p (operands[0]))
  253.     optype0 = OFFSOP;
  254.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  255.     optype0 = POPOP;
  256.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  257.     optype0 = PUSHOP;
  258.   else if (GET_CODE (operands[0]) == MEM)
  259.     optype0 = MEMOP;
  260.   else
  261.     optype0 = RNDOP;
  262.  
  263.   if (REG_P (operands[1]))
  264.     optype1 = REGOP;
  265.   else if (CONSTANT_P (operands[1]))
  266.     optype1 = CNSTOP;
  267.   else if (offsettable_memref_p (operands[1]))
  268.     optype1 = OFFSOP;
  269.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  270.     optype1 = POPOP;
  271.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  272.     optype1 = PUSHOP;
  273.   else if (GET_CODE (operands[1]) == MEM)
  274.     optype1 = MEMOP;
  275.   else
  276.     optype1 = RNDOP;
  277.  
  278.   /* Check for the cases that the operand constraints are not
  279.      supposed to allow to happen.  Abort if we get one,
  280.      because generating code for these cases is painful.  */
  281.  
  282.   if (optype0 == RNDOP || optype1 == RNDOP)
  283.     abort ();
  284.  
  285.   /* If one operand is decrementing and one is incrementing
  286.      decrement the former register explicitly
  287.      and change that operand into ordinary indexing.  */
  288.  
  289.   if (optype0 == PUSHOP && optype1 == POPOP)
  290.     {
  291.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  292.       asm_add (-8, operands[0]);
  293.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  294.       optype0 = OFFSOP;
  295.     }
  296.   if (optype0 == POPOP && optype1 == PUSHOP)
  297.     {
  298.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  299.       asm_add (