]> gcc.gnu.org Git - gcc.git/commitdiff
restore portion accidentally deleted last time
authorRichard Stallman <rms@gnu.org>
Tue, 7 Jul 1992 00:51:10 +0000 (00:51 +0000)
committerRichard Stallman <rms@gnu.org>
Tue, 7 Jul 1992 00:51:10 +0000 (00:51 +0000)
(but not the two functions intentionally deleted).

From-SVN: r1485

gcc/config/i860/i860.c

index 0e071b891fb73b4ec3a64fc0efdca931ce003c47..c82c1977ced7c3e1a1744dcb9930be38fe38b53d 100644 (file)
@@ -1,3 +1,356 @@
+/* Subroutines for insn-output.c for Intel 860
+   Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+   Derived from sparc.c.
+
+   Written by Richard Stallman (rms@ai.mit.edu).
+
+   Hacked substantially by Ron Guilmette (rfg@ncd.com) to cater
+   to the whims of the System V Release 4 assembler.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#include "config.h"
+#include "flags.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "recog.h"
+#include "insn-attr.h"
+
+#include <stdio.h>
+
+static rtx find_addr_reg ();
+
+#ifndef I860_REG_PREFIX
+#define I860_REG_PREFIX ""
+#endif
+
+char *i860_reg_prefix = I860_REG_PREFIX;
+
+/* Save information from a "cmpxx" operation until the branch is emitted.  */
+
+rtx i860_compare_op0, i860_compare_op1;
+\f
+/* Return non-zero if this pattern, can be evaluated safely, even if it
+   was not asked for.  */
+int
+safe_insn_src_p (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  /* Just experimenting.  */
+
+  /* No floating point src is safe if it contains an arithmetic
+     operation, since that operation may trap.  */
+  switch (GET_CODE (op))
+    {
+    case CONST_INT:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST:
+      return 1;
+
+    case REG:
+      return 1;
+
+    case MEM:
+      return CONSTANT_ADDRESS_P (XEXP (op, 0));
+
+      /* We never need to negate or complement constants.  */
+    case NEG:
+      return (mode != SFmode && mode != DFmode);
+    case NOT:
+    case ZERO_EXTEND:
+      return 1;
+
+    case EQ:
+    case NE:
+    case LT:
+    case GT:
+    case LE:
+    case GE:
+    case LTU:
+    case GTU:
+    case LEU:
+    case GEU:
+    case MINUS:
+    case PLUS:
+      return (mode != SFmode && mode != DFmode);
+    case AND:
+    case IOR:
+    case XOR:
+    case LSHIFT:
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
+         || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
+       return 0;
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Return 1 if REG is clobbered in IN.
+   Return 2 if REG is used in IN. 
+   Return 3 if REG is both used and clobbered in IN.
+   Return 0 if neither.  */
+
+static int
+reg_clobbered_p (reg, in)
+     rtx reg;
+     rtx in;
+{
+  register enum rtx_code code;
+
+  if (in == 0)
+    return 0;
+
+  code = GET_CODE (in);
+
+  if (code == SET || code == CLOBBER)
+    {
+      rtx dest = SET_DEST (in);
+      int set = 0;
+      int used = 0;
+
+      while (GET_CODE (dest) == STRICT_LOW_PART
+            || GET_CODE (dest) == SUBREG
+            || GET_CODE (dest) == SIGN_EXTRACT
+            || GET_CODE (dest) == ZERO_EXTRACT)
+       dest = XEXP (dest, 0);
+
+      if (dest == reg)
+       set = 1;
+      else if (GET_CODE (dest) == REG
+              && refers_to_regno_p (REGNO (reg),
+                                    REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
+                                    SET_DEST (in), 0))
+       {
+         set = 1;
+         /* Anything that sets just part of the register
+            is considered using as well as setting it.
+            But note that a straight SUBREG of a single-word value
+            clobbers the entire value.   */
+         if (dest != SET_DEST (in)
+             && ! (GET_CODE (SET_DEST (in)) == SUBREG
+                   || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))
+           used = 1;
+       }
+
+      if (code == SET)
+       {
+         if (set)
+           used = refers_to_regno_p (REGNO (reg),
+                                     REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
+                                     SET_SRC (in), 0);
+         else
+           used = refers_to_regno_p (REGNO (reg),
+                                     REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
+                                     in, 0);
+       }
+
+      return set + used * 2;
+    }
+
+  if (refers_to_regno_p (REGNO (reg),
+                        REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
+                        in, 0))
+    return 2;
+  return 0;
+}
+
+/* Return non-zero if OP can be written to without screwing up
+   GCC's model of what's going on.  It is assumed that this operand
+   appears in the dest position of a SET insn in a conditional
+   branch's delay slot.  AFTER is the label to start looking from.  */
+int
+operand_clobbered_before_used_after (op, after)
+     rtx op;
+     rtx after;
+{
+  /* Just experimenting.  */
+  if (GET_CODE (op) == CC0)
+    return 1;
+  if (GET_CODE (op) == REG)
+    {
+      rtx insn;
+
+      if (op == stack_pointer_rtx)
+       return 0;
+
+      /* Scan forward from the label, to see if the value of OP
+        is clobbered before the first use.  */
+
+      for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
+       {
+         if (GET_CODE (insn) == NOTE)
+           continue;
+         if (GET_CODE (insn) == INSN
+             || GET_CODE (insn) == JUMP_INSN
+             || GET_CODE (insn) == CALL_INSN)
+           {
+             switch (reg_clobbered_p (op, PATTERN (insn)))
+               {
+               default:
+                 return 0;
+               case 1:
+                 return 1;
+               case 0:
+                 break;
+               }
+           }
+         /* If we reach another label without clobbering OP,
+            then we cannot safely write it here.  */
+         else if (GET_CODE (insn) == CODE_LABEL)
+           return 0;
+         if (GET_CODE (insn) == JUMP_INSN)
+           {
+             if (condjump_p (insn))
+               return 0;
+             /* This is a jump insn which has already
+                been mangled.  We can't tell what it does.  */
+             if (GET_CODE (PATTERN (insn)) == PARALLEL)
+               return 0;
+             if (! JUMP_LABEL (insn))
+               return 0;
+             /* Keep following jumps.  */
+             insn = JUMP_LABEL (insn);
+           }
+       }
+      return 1;
+    }
+
+  /* In both of these cases, the first insn executed
+     for this op will be a orh whatever%h,%?r0,%?r31,
+     which is tolerable.  */
+  if (GET_CODE (op) == MEM)
+    return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
+
+  return 0;
+}
+
+/* Return non-zero if this pattern, as a source to a "SET",
+   is known to yield an instruction of unit size.  */
+int
+single_insn_src_p (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  switch (GET_CODE (op))
+    {
+    case CONST_INT:
+      /* This is not always a single insn src, technically,
+        but output_delayed_branch knows how to deal with it.  */
+      return 1;
+
+    case SYMBOL_REF:
+    case CONST:
+      /* This is not a single insn src, technically,
+        but output_delayed_branch knows how to deal with it.  */
+      return 1;
+
+    case REG:
+      return 1;
+
+    case MEM:
+      return 1;
+
+      /* We never need to negate or complement constants.  */
+    case NEG:
+      return (mode != DFmode);
+    case NOT:
+    case ZERO_EXTEND:
+      return 1;
+
+    case PLUS:
+    case MINUS:
+      /* Detect cases that require multiple instructions.  */
+      if (CONSTANT_P (XEXP (op, 1))
+         && !(GET_CODE (XEXP (op, 1)) == CONST_INT
+              && SMALL_INT (XEXP (op, 1))))
+       return 0;
+    case EQ:
+    case NE:
+    case LT:
+    case GT:
+    case LE:
+    case GE:
+    case LTU:
+    case GTU:
+    case LEU:
+    case GEU:
+      /* Not doing floating point, since they probably
+        take longer than the branch slot they might fill.  */
+      return (mode != SFmode && mode != DFmode);
+
+    case AND:
+      if (GET_CODE (XEXP (op, 1)) == NOT)
+       {
+         rtx arg = XEXP (XEXP (op, 1), 0);
+         if (CONSTANT_P (arg)
+             && !(GET_CODE (arg) == CONST_INT
+                  && (SMALL_INT (arg)
+                      || INTVAL (arg) & 0xffff == 0)))
+           return 0;
+       }
+    case IOR:
+    case XOR:
+      /* Both small and round numbers take one instruction;
+        others take two.  */
+      if (CONSTANT_P (XEXP (op, 1))
+         && !(GET_CODE (XEXP (op, 1)) == CONST_INT
+              && (SMALL_INT (XEXP (op, 1))
+                  || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
+       return 0;
+
+    case LSHIFT:
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      return 1;
+
+    case SUBREG:
+      if (SUBREG_WORD (op) != 0)
+       return 0;
+      return single_insn_src_p (SUBREG_REG (op), mode);
+
+      /* Not doing floating point, since they probably
+        take longer than the branch slot they might fill.  */
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+    case FLOAT:
+    case FIX:
+    case UNSIGNED_FLOAT:
+    case UNSIGNED_FIX:
+      return 0;
+
+    default:
+      return 0;
+    }
+}
 \f
 /* Return non-zero only if OP is a register of mode MODE,
    or const0_rtx.  */
@@ -1199,7 +1552,7 @@ sfmode_constant_to_ulong (x)
    for saving all of the "preserved" registers (and use that number, i.e.
    `80', to define STARTING_FRAME_OFFSET) if we wanted to save them in
    the lower part of the frame.  That could potentially be very wasteful,
-   and that could cause serious problems when compiling for embedded
+   and that wastefulness could really hamper people compiling for embedded
    i860 targets with very tight limits on stack space.  Thus, we choose
    here to save the preserved registers in the upper part of the
    frame, so that we can decide at the very last minute how much (or how
This page took 0.06431 seconds and 5 git commands to generate.