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 / romp.c < prev    next >
C/C++ Source or Header  |  1994-02-06  |  49KB  |  1,900 lines

  1. /* Subroutines used for code generation on ROMP.
  2.    Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  3.    Contributed by Richard Kenner (kenner@nyu.edu)
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. GNU CC is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU CC; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21.  
  22. #include <stdio.h>
  23. #include "config.h"
  24. #include "rtl.h"
  25. #include "regs.h"
  26. #include "hard-reg-set.h"
  27. #include "real.h"
  28. #include "insn-config.h"
  29. #include "conditions.h"
  30. #include "insn-flags.h"
  31. #include "output.h"
  32. #include "insn-attr.h"
  33. #include "flags.h"
  34. #include "recog.h"
  35. #include "expr.h"
  36. #include "obstack.h"
  37. #include "tree.h"
  38.  
  39. #define min(A,B)    ((A) < (B) ? (A) : (B))
  40. #define max(A,B)    ((A) > (B) ? (A) : (B))
  41.  
  42. static int unsigned_comparisons_p ();
  43. static void output_loadsave_fpregs ();
  44. static void output_fpops ();
  45. static void init_fpops ();
  46.  
  47. /* Return 1 if the insn using CC0 set by INSN does not contain
  48.    any unsigned tests applied to the condition codes.
  49.  
  50.    Based on `next_insn_tests_no_inequality' in recog.c.  */
  51.  
  52. int
  53. next_insn_tests_no_unsigned (insn)
  54.      rtx insn;
  55. {
  56.   register rtx next = next_cc0_user (insn);
  57.  
  58.   if (next == 0)
  59.     {
  60.       if (find_reg_note (insn, REG_UNUSED, cc0_rtx))
  61.     return 1;
  62.       else
  63.     abort ();
  64.     }
  65.  
  66.   return ((GET_CODE (next) == JUMP_INSN
  67.        || GET_CODE (next) == INSN
  68.        || GET_CODE (next) == CALL_INSN)
  69.       && ! unsigned_comparisons_p (PATTERN (next)));
  70. }
  71.  
  72. static int
  73. unsigned_comparisons_p (x)
  74.      rtx x;
  75. {
  76.   register char *fmt;
  77.   register int len, i;
  78.   register enum rtx_code code = GET_CODE (x);
  79.  
  80.   switch (code)
  81.     {
  82.     case REG:
  83.     case PC:
  84.     case CC0:
  85.     case CONST_INT:
  86.     case CONST_DOUBLE:
  87.     case CONST:
  88.     case LABEL_REF:
  89.     case SYMBOL_REF:
  90.       return 0;
  91.  
  92.     case LTU:
  93.     case GTU:
  94.     case LEU:
  95.     case GEU:
  96.       return (XEXP (x, 0) == cc0_rtx || XEXP (x, 1) == cc0_rtx);
  97.     }
  98.  
  99.   len = GET_RTX_LENGTH (code);
  100.   fmt = GET_RTX_FORMAT (code);
  101.  
  102.   for (i = 0; i < len; i++)
  103.     {
  104.       if (fmt[i] == 'e')
  105.     {
  106.       if (unsigned_comparisons_p (XEXP (x, i)))
  107.         return 1;
  108.     }
  109.       else if (fmt[i] == 'E')
  110.     {
  111.       register int j;
  112.       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
  113.         if (unsigned_comparisons_p (XVECEXP (x, i, j)))
  114.           return 1;
  115.     }
  116.     }
  117.         
  118.   return 0;
  119. }
  120.  
  121. /* Update the condition code from the insn.  Look mostly at the first
  122.    byte of the machine-specific insn description information.
  123.  
  124.    cc_state.value[12] refer to two possible values that might correspond
  125.    to the CC.  We only store register values.  */
  126.  
  127. update_cc (body, insn)
  128.     rtx body;
  129.     rtx insn;
  130. {
  131.   switch (get_attr_cc (insn))
  132.     {
  133.     case CC_NONE:
  134.       /* Insn does not affect the CC at all.  */
  135.       break;
  136.  
  137.     case CC_CHANGE0:
  138.       /* Insn doesn't affect the CC but does modify operand[0], known to be
  139.      a register.  */
  140.       if (cc_status.value1 != 0
  141.       && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
  142.     cc_status.value1 = 0;
  143.  
  144.       if (cc_status.value2 != 0
  145.       && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
  146.     cc_status.value2 = 0;
  147.  
  148.       break;
  149.  
  150.     case CC_COPY1TO0:
  151.       /* Insn copies operand[1] to operand[0], both registers, but doesn't
  152.          affect the CC.  */
  153.       if (cc_status.value1 != 0
  154.       && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
  155.     cc_status.value1 = 0;
  156.  
  157.       if (cc_status.value2 != 0
  158.       && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
  159.     cc_status.value2 = 0;
  160.  
  161.       if (cc_status.value1 != 0
  162.       && rtx_equal_p (cc_status.value1, recog_operand[1]))
  163.     cc_status.value2 = recog_operand[0];
  164.  
  165.       if (cc_status.value2 != 0
  166.       && rtx_equal_p (cc_status.value2, recog_operand[1]))
  167.     cc_status.value1 = recog_operand[0];
  168.  
  169.       break;
  170.  
  171.     case CC_CLOBBER:
  172.       /* Insn clobbers CC. */
  173.       CC_STATUS_INIT;
  174.       break;
  175.  
  176.     case CC_SETS:
  177.       /* Insn sets CC to recog_operand[0], but overflow is impossible.  */
  178.       CC_STATUS_INIT;
  179.       cc_status.flags |= CC_NO_OVERFLOW;
  180.       cc_status.value1 = recog_operand[0];
  181.       break;
  182.  
  183.    case CC_COMPARE:
  184.       /* Insn is a compare which sets the CC fully.  Update CC_STATUS for this
  185.      compare and mark whether the test will be signed or unsigned.  */
  186.       {
  187.     register rtx p = PATTERN (insn);
  188.  
  189.     CC_STATUS_INIT;
  190.  
  191.     if (GET_CODE (p) == PARALLEL)
  192.       p = XVECEXP (p, 0, 0);
  193.     cc_status.value1 = SET_SRC (p);
  194.  
  195.     if (GET_CODE (SET_SRC (p)) == REG)
  196.       cc_status.flags |= CC_NO_OVERFLOW;
  197.     if (! next_insn_tests_no_unsigned (insn))
  198.       cc_status.flags |= CC_UNSIGNED;
  199.       }
  200.       break;
  201.  
  202.     case CC_TBIT:
  203.       /* Insn sets T bit if result is non-zero.  Next insn must be branch. */
  204.       CC_STATUS_INIT;
  205.       cc_status.flags = CC_IN_TB | CC_NOT_NEGATIVE;
  206.       break;
  207.  
  208.     default:
  209.       abort ();
  210.    }
  211. }
  212.  
  213. /* Return 1 if a previous compare needs to be re-issued.  This will happen
  214.    if two compares tested the same objects, but one was signed and the
  215.    other unsigned.  OP is the comparison operation being performed.  */
  216.  
  217. int
  218. restore_compare_p (op)
  219.      rtx op;
  220. {
  221.   enum rtx_code code = GET_CODE (op);
  222.  
  223.   return (((code == GEU || code == LEU || code == GTU || code == LTU)
  224.        && ! (cc_status.flags & CC_UNSIGNED))
  225.       || ((code == GE || code == LE || code == GT || code == LT)
  226.           && (cc_status.flags & CC_UNSIGNED)));
  227. }
  228.  
  229. /*  Generate the (long) string corresponding to an inline multiply insn.
  230.     Note that `r10' does not refer to the register r10, but rather to the
  231.     SCR used as the MQ.  */
  232. char *
  233. output_in_line_mul ()
  234. {
  235.   static char insns[200];
  236.   int i;
  237.  
  238.   strcpy (insns, "s %0,%0\n");
  239.   strcat (insns, "\tmts r10,%1\n");
  240.   for (i = 0; i < 16; i++)
  241.     strcat (insns, "\tm %0,%2\n");
  242.   strcat (insns, "\tmfs r10,%0");
  243.  
  244.   return insns;
  245. }
  246.  
  247. /* Returns 1 if OP is a memory reference with an offset from a register within
  248.    the range specified.  The offset must also be a multiple of the size of the
  249.    mode.  */
  250.  
  251. static int
  252. memory_offset_in_range_p (op, mode, low, high)
  253.      register rtx op;
  254.      enum machine_mode mode;
  255.      int low, high;
  256. {
  257.   int offset = 0;
  258.  
  259.   if (! memory_operand (op, mode))
  260.     return 0;
  261.  
  262.   while (GET_CODE (op) == SUBREG)
  263.     {
  264.       offset += SUBREG_WORD (op) * UNITS_PER_WORD;
  265. #if BYTES_BIG_ENDIAN
  266.       offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op)))
  267.          - min (UNITS_PER_WORD,
  268.             GET_MODE_SIZE (GET_MODE (SUBREG_REG (op)))));
  269. #endif
  270.       op = SUBREG_REG (op);
  271.     }
  272.  
  273.   /* We must now have either (mem (reg (x)), (mem (plus (reg (x)) (c))),
  274.      or a constant pool address.  */
  275.   if (GET_CODE (op) != MEM)
  276.     abort ();
  277.  
  278.   /* Now use the actual mode and get the address.  */
  279.   mode = GET_MODE (op);
  280.   op = XEXP (op, 0);
  281.   if (GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op))
  282.     offset = get_pool_offset (op) + 12;
  283.   else if (GET_CODE (op) == PLUS)
  284.     {
  285.       if (GET_CODE (XEXP (op, 1)) != CONST_INT
  286.       || ! register_operand (XEXP (op, 0), Pmode))
  287.     return 0;
  288.  
  289.       offset += INTVAL (XEXP (op, 1));
  290.     }
  291.  
  292.   else if (! register_operand (op, Pmode))
  293.     return 0;
  294.  
  295.   return (offset >= low && offset <= high
  296.       && (offset % GET_MODE_SIZE (mode) == 0));
  297. }
  298.  
  299. /* Return 1 if OP is a valid operand for a memory reference insn that can
  300.    only reference indirect through a register.   */
  301.  
  302. int
  303. zero_memory_operand (op, mode)
  304.      rtx op;
  305.      enum machine_mode mode;
  306. {
  307.   return memory_offset_in_range_p (op, mode, 0, 0);
  308. }
  309.  
  310. /* Return 1 if OP is a valid operand for a `short' memory reference insn. */
  311.  
  312. int
  313. short_memory_operand (op, mode)
  314.      rtx op;
  315.      enum machine_mode mode;
  316. {
  317.   if (mode == VOIDmode)
  318.     mode = GET_MODE (op);
  319.  
  320.   return memory_offset_in_range_p (op, mode, 0,
  321.                    15 * min (UNITS_PER_WORD,
  322.                          GET_MODE_SIZE (mode)));
  323. }
  324.  
  325. /* Returns 1 if OP is a memory referen