]> gcc.gnu.org Git - gcc.git/commitdiff
entered into RCS
authorCharles Hannum <mycroft@gnu.org>
Thu, 29 Aug 1991 23:24:57 +0000 (23:24 +0000)
committerCharles Hannum <mycroft@gnu.org>
Thu, 29 Aug 1991 23:24:57 +0000 (23:24 +0000)
From-SVN: r36

gcc/config/pyr/pyr.c [new file with mode: 0644]

diff --git a/gcc/config/pyr/pyr.c b/gcc/config/pyr/pyr.c
new file mode 100644 (file)
index 0000000..82ae9bd
--- /dev/null
@@ -0,0 +1,863 @@
+/* Subroutines for insn-output.c for Pyramid 90x, 9000, and MIServer Series.
+   Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+
+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.  */
+
+/* Some output-actions in pyr.md need these.  */
+#include <stdio.h>
+#include "config.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 "insn-attr.h"
+#include "tree.h"
+
+/*
+ * Do FUNCTION_ARG.
+ * This cannot be defined as a macro on pyramids, because Pyramid Technology's
+ * C compiler dies on (several equivalent definitions of) this macro.
+ * The only way around this cc bug was to make this a function.
+ * While it would be possible to use a macro version for gcc, it seems
+ * more reliable to have a single version of the code.
+ */
+void *
+pyr_function_arg(cum, mode, type, named)
+  CUMULATIVE_ARGS cum;
+  enum machine_mode mode;
+  tree type;
+{
+  return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named));
+}
+\f
+/* Do the hard part of PARAM_SAFE_FOR_REG_P.
+ * This cannot be defined as a macro on pyramids, because Pyramid Technology's
+ * C compiler dies on (several equivalent definitions of) this macro.
+ * The only way around this cc bug was to make this a function.
+ */
+int
+inner_param_safe_helper (type)
+    tree type;
+{
+  return (INNER_PARAM_SAFE_HELPER(type));
+}
+\f
+
+/* Return 1 if OP is a non-indexed operand of mode MODE.
+   This is either a register reference, a memory reference,
+   or a constant.  In the case of a memory reference, the address
+   is checked to make sure it isn't indexed.
+
+   Register and memory references must have mode MODE in order to be valid,
+   but some constants have no machine mode and are valid for any mode.
+
+   If MODE is VOIDmode, OP is checked for validity for whatever mode
+   it has.
+
+   The main use of this function is as a predicate in match_operand
+   expressions in the machine description.
+
+   It is  useful to compare this with general_operand().  They should
+   be identical except for one line.
+
+   This function seems necessary because of the non-orthogonality of
+   Pyramid insns.
+   For any 2-operand insn, and any combination of operand modes,
+   if indexing is valid for the isn's second operand, it is invalid
+   for the first operand to be indexed. */
+
+extern int volatile_ok;
+
+int
+nonindexed_operand (op, mode)
+    register rtx op;
+    enum machine_mode mode;
+{
+  register RTX_CODE code = GET_CODE (op);
+  int mode_altering_drug = 0;
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (op);
+
+  /* Don't accept CONST_INT or anything similar
+     if the caller wants something floating.  */
+  if (GET_MODE (op) == VOIDmode && mode != VOIDmode
+      && GET_MODE_CLASS (mode) != MODE_INT)
+    return 0;
+
+  if (CONSTANT_P (op))
+    return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode)
+           && LEGITIMATE_CONSTANT_P (op));
+
+  /* Except for certain constants with VOIDmode, already checked for,
+     OP's mode must match MODE if MODE specifies a mode.  */
+
+  if (GET_MODE (op) != mode)
+    return 0;
+
+  while (code == SUBREG)
+    {
+      op = SUBREG_REG (op);
+      code = GET_CODE (op);
+#if 0
+      /* No longer needed, since (SUBREG (MEM...))
+        will load the MEM into a reload reg in the MEM's own mode.  */
+      mode_altering_drug = 1;
+#endif
+    }
+  if (code == REG)
+    return 1;
+  if (code == CONST_DOUBLE)
+    return LEGITIMATE_CONSTANT_P (op);
+  if (code == MEM)
+    {
+      register rtx y = XEXP (op, 0);
+      if (! volatile_ok && MEM_VOLATILE_P (op))
+       return 0;
+    GO_IF_NONINDEXED_ADDRESS (y, win);
+    }
+  return 0;
+
+ win:
+  if (mode_altering_drug)
+    return ! mode_dependent_address_p (XEXP (op, 0));
+  return 1;
+}
+
+/* Return non-zero if the rtx OP has an immediate component.  An
+   immediate component or additive term equal to zero is rejected
+   due to assembler problems.  */
+
+int
+has_direct_base (op)
+     rtx op;
+{
+  if ((CONSTANT_ADDRESS_P (op)
+       && op != const0_rtx)
+      || (GET_CODE (op) == PLUS
+         && ((CONSTANT_ADDRESS_P (XEXP (op, 1))
+              && XEXP (op, 1) != const0_rtx)
+             || (CONSTANT_ADDRESS_P (XEXP (op, 0))
+                 && XEXP (op, 0) != const0_rtx))))
+    return 1;
+
+  return 0;
+}
+
+/* Return zero if the rtx OP has a (scaled) index.  */
+
+int
+has_index (op)
+     rtx op;
+{
+  if (GET_CODE (op) == PLUS
+      && (GET_CODE (XEXP (op, 0)) == MULT
+         || (GET_CODE (XEXP (op, 1)) == MULT)))
+    return 1;
+  else
+    return 0;
+}
+
+int swap_operands;
+
+/* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or
+   exchanged with xchw) with one instruction.  If the operands need to
+   be swapped, set the global variable SWAP_OPERANDS.  This function
+   silently assumes that both OP0 and OP1 are valid memory references.
+   */
+
+int
+weird_memory_memory (op0, op1)
+     rtx op0, op1;
+{
+  RTX_CODE code0, code1;
+
+  op0 = XEXP (op0, 0);
+  op1 = XEXP (op1, 0);
+  code0 = GET_CODE (op0);
+  code1 = GET_CODE (op1);
+
+  swap_operands = 0;
+
+  if (code1 == REG || code1 == SUBREG)
+    {
+      return 1;
+    }
+  if (code0 == REG || code0 == SUBREG)
+    {
+      swap_operands = 1;
+      return 1;
+    }
+  if (has_direct_base (op0) && has_direct_base (op1))
+    {
+      if (has_index (op1))
+       {
+         if (has_index (op0))
+           return 0;
+         swap_operands = 1;
+       }
+
+      return 1;
+    }
+  return 0;
+}
+
+int
+signed_comparison (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  return ! TRULY_UNSIGNED_COMPARE_P (GET_CODE (x));
+}
+
+extern rtx force_reg ();
+rtx test_op0, test_op1;
+enum machine_mode test_mode;
+
+/* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE.  */
+
+rtx
+extend_const (x, extop, from_mode, to_mode)
+    rtx x;
+    RTX_CODE extop;
+    enum machine_mode from_mode, to_mode;
+{
+  int val;
+  int negative;
+  if (from_mode == to_mode)
+    return x;
+  if (GET_CODE (x) != CONST_INT)
+    abort ();
+  val = INTVAL (x);
+  negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1));
+  if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT)
+    abort ();
+  if (negative && extop == SIGN_EXTEND)
+    val = val | ((-1) << (GET_MODE_BITSIZE (from_mode)));
+  else
+    val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode)));
+  if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT)
+    return gen_rtx (CONST_INT, VOIDmode, val);
+  return gen_rtx (CONST_INT, VOIDmode,
+                 val & ~((-1) << (GET_MODE_BITSIZE (to_mode))));
+}
+
+rtx
+ensure_extended (op, extop, from_mode)
+     rtx op;
+     RTX_CODE extop;
+     enum machine_mode from_mode;
+{
+  if (GET_CODE (op) == CONST_INT)
+    return extend_const (op, extop, from_mode, SImode);
+  else
+    return force_reg (SImode, gen_rtx (extop, SImode, op));
+}
+
+/* Emit rtl for a branch, as well as any delayed (integer) compare insns.
+   The compare insn to perform is determined by the global variables
+   test_op0 and test_op1.  */
+
+void
+extend_and_branch (extop)
+     RTX_CODE extop;
+{
+  rtx op0, op1;
+  RTX_CODE code0, code1;
+
+  op0 = test_op0, op1 = test_op1;
+  if (op0 == 0)
+    return;
+
+  code0 = GET_CODE (op0);
+  if (op1 != 0)
+    code1 = GET_CODE (op1);
+  test_op0 = test_op1 = 0;
+
+  if (op1 == 0)
+    {
+      op0 = ensure_extended (op0, extop, test_mode);
+      emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0));
+    }
+  else
+    {
+      if (CONSTANT_P (op0) && CONSTANT_P (op1))
+       {
+         op0 = ensure_extended (op0, extop, test_mode);
+         op1 = ensure_extended (op1, extop, test_mode);
+       }
+      else if (extop == ZERO_EXTEND && test_mode == HImode)
+       {
+         /* Pyramids have no unsigned "cmphi" instructions.  We need to
+            zero extend unsigned halfwords into temporary registers. */
+         op0 = ensure_extended (op0, extop, test_mode);
+         op1 = ensure_extended (op1, extop, test_mode);
+       }
+      else if (CONSTANT_P (op0))
+       {
+         op0 = ensure_extended (op0, extop, test_mode);
+         op1 = ensure_extended (op1, extop, test_mode);
+       }
+      else if (CONSTANT_P (op1))
+       {
+         op1 = ensure_extended (op1, extop, test_mode);
+         op0 = ensure_extended (op0, extop, test_mode);
+       }
+      else if ((code0 == REG || code0 == SUBREG)
+              && (code1 == REG || code1 == SUBREG))
+       {
+         /* I could do this case without extension, by using the virtual
+            register address (but that would lose for global regs).  */
+         op0 = ensure_extended (op0, extop, test_mode);
+         op1 = ensure_extended (op1, extop, test_mode);
+       }
+      else if (code0 == MEM && code1 == MEM)
+       {
+         /* Load into a reg if the address combination can't be handled
+            directly.  */
+         if (! weird_memory_memory (op0, op1))
+           op0 = force_reg (test_mode, op0);
+       }
+
+      emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
+                         gen_rtx (COMPARE, VOIDmode, op0, op1)));
+    }
+}
+
+/* Return non-zero if the two single-word moves with operands[0]
+   and operands[1] for the first single-word move, and operands[2]
+   and operands[3] for the second single-word move, is possible to
+   combine to a double word move.
+
+   The criterion is whether the operands are in consecutive memory cells,
+   registers, etc.  */
+
+int
+movdi_possible (operands)
+     rtx operands[];
+{
+  int cnst_diff0, cnst_diff1;
+  RTX_CODE code0 = GET_CODE (operands[0]);
+  RTX_CODE code1 = GET_CODE (operands[1]);
+
+  /* Don't dare to combine (possibly overlapping) memory -> memory moves.  */
+  /* It would be possible to detect the cases where we dare, by using
+     constant_diff (operands[0], operands[1])!!!  */
+  if (code0 == MEM && code1 == MEM)
+    return 0;
+
+  cnst_diff0 = consecutive_operands (operands[0], operands[2]);
+  if (cnst_diff0 == 0)
+    return 0;
+
+  cnst_diff1 = consecutive_operands (operands[1], operands[3]);
+  if (cnst_diff1 == 0)
+    return 0;
+
+  if (cnst_diff0 & cnst_diff1)
+    {
+      /* The source and destination operands are consecutive.  */
+
+      /* If the first move writes into the source of the second move,
+        we cannot combine.  */
+      if ((code0 == REG
+          && reg_overlap_mentioned_p (operands[0], operands[3]))
+         || (code0 == SUBREG
+             && subreg_overlap_mentioned_p (operands[0], operands[3])))
+         return 0;
+
+      if (cnst_diff0 & 1)
+       /* operands[0],[1] has higher addresses than operands[2],[3].  */
+       swap_operands = 0;
+      else
+       /* operands[0],[1] has lower addresses than operands[2],[3].  */
+       swap_operands = 1;
+      return 1;
+    }
+  return 0;
+}
+
+/* Like reg_overlap_mentioned_p, but accepts a subreg rtx instead
+   of a reg.  */
+
+int
+subreg_overlap_mentioned_p (subreg, x)
+     rtx subreg, x;
+{
+  rtx reg = SUBREG_REG (subreg);
+  int regno = REGNO (reg) + SUBREG_WORD (subreg);
+  int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (subreg));
+  return refers_to_regno_p (regno, endregno, x, 0);
+}
+
+/* Return 1 if OP0 is a consecutive operand to OP1, 2 if OP1 is a
+   consecutive operand to OP0.
+
+   This function is used to determine if addresses are consecutive,
+   and therefore possible to combine to fewer instructions.  */
+
+int
+consecutive_operands (op0, op1)
+     rtx op0, op1;
+{
+  RTX_CODE code0, code1;
+  int cnst_diff;
+  int regno_off0, regno_off1;
+
+  code0 = GET_CODE (op0);
+  code1 = GET_CODE (op1);
+
+  regno_off0 = 0;
+  if (code0 == SUBREG)
+    {
+      if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD)
+       return 0;
+      regno_off0 = SUBREG_WORD (op0);
+      op0 = SUBREG_REG (op0);
+      code0 = REG;
+    }
+
+  regno_off1 = 0;
+  if (code1 == SUBREG)
+    {
+      if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD)
+       return 0;
+      regno_off1 = SUBREG_WORD (op1);
+      op1 = SUBREG_REG (op1);
+      code1 = REG;
+    }
+
+  if (code0 != code1)
+    return 0;
+
+  switch (code0)
+    {
+    case CONST_INT:
+      /* Cannot permit any symbolic constants, even if the consecutive
+        operand is 0, since a movl really performs sign extension.  */
+      if (code1 != CONST_INT)
+       return 0;
+      if ((INTVAL (op0) == 0 && INTVAL (op1) == 0)
+         || (INTVAL (op0) == -1 && INTVAL (op1) == -1))
+       return 3;
+      if ((INTVAL (op0) == 0 && INTVAL (op1) > 0)
+         || (INTVAL (op0) == -1 && INTVAL (op1) < 0))
+       return 2;
+      if ((INTVAL (op1) == 0 && INTVAL (op0) > 0)
+         || (INTVAL (op1) == -1 && INTVAL (op0) < 0))
+       return 1;
+      break;
+
+    case REG:
+      regno_off0 = REGNO (op0) + regno_off0;
+      regno_off1 = REGNO (op1) + regno_off1;
+
+      cnst_diff = regno_off0 - regno_off1;
+      if (cnst_diff == 1)
+       {
+         /* movl with the highest numbered parameter (local) register as
+            source or destination, doesn't wrap to the lowest numbered local
+            (temporary) register.  */
+
+         if (regno_off0 % 16 != 0)
+           return 1;
+         else
+           return 0;
+       }
+      else if (cnst_diff == -1)
+       {
+         if (regno_off1 % 16 != 0)
+           return 2;
+         else
+           return 0;
+       }
+      break;
+
+    case MEM:
+      op0 = XEXP (op0, 0);
+      op1 = XEXP (op1, 0);
+      if (GET_CODE (op0) == CONST)
+       op0 = XEXP (op0, 0);
+      if (GET_CODE (op1) == CONST)
+       op1 = XEXP (op1, 0);
+
+      cnst_diff = constant_diff (op0, op1);
+      if (cnst_diff)
+       {
+         if (cnst_diff == 4)
+           return 1;
+         else if (cnst_diff == -4)
+           return 2;
+       }
+      break;
+    }
+  return 0;
+}
+
+/* Return the constant difference of the rtx expressions OP0 and OP1,
+   or 0 if they don't have a constant difference.
+
+   This function is used to determine if addresses are consecutive,
+   and therefore possible to combine to fewer instructions.  */
+
+int
+constant_diff (op0, op1)
+     rtx op0, op1;
+{
+  RTX_CODE code0, code1;
+  int cnst_diff;
+
+  code0 = GET_CODE (op0);
+  code1 = GET_CODE (op1);
+
+  if (code0 != code1)
+    {
+      if (code0 == PLUS)
+       {
+         if (GET_CODE (XEXP (op0, 1)) == CONST_INT
+             && rtx_equal_p (op1, XEXP (op0, 0)))
+           return INTVAL (XEXP (op0, 1));
+       }
+      else if (code1 == PLUS)
+       {
+         if (GET_CODE (XEXP (op1, 1)) == CONST_INT
+             && rtx_equal_p (op0, XEXP (op1, 0)))
+           return -INTVAL (XEXP (op1, 1));
+       }
+      return 0;
+    }
+
+  if (code0 == CONST_INT)
+    return INTVAL (op0) - INTVAL (op1);
+
+  if (code0 == PLUS)
+    {
+      cnst_diff = constant_diff (XEXP (op0, 0), XEXP (op1, 0));
+      if (cnst_diff)
+       return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
+         ? cnst_diff : 0;
+      cnst_diff = constant_diff (XEXP (op0, 1), XEXP (op1, 1));
+      if (cnst_diff)
+       return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)))
+         ? cnst_diff : 0;
+    }
+
+  return 0;
+}
+
+int
+already_sign_extended (insn, from_mode, op)
+     rtx insn;
+     enum machine_mode from_mode;
+     rtx op;
+{
+  rtx xinsn, xdest, xsrc;
+
+  for (;;)
+    {
+      insn = PREV_INSN (insn);
+      if (insn == 0)
+       return 0;
+      if (GET_CODE (insn) == NOTE || GET_CODE (insn) == JUMP_INSN)
+       continue;
+      if (GET_CODE (insn) == CALL_INSN && ! call_used_regs[REGNO (op)])
+       continue;
+      if (GET_CODE (insn) != INSN)
+       return 0;
+      xinsn = PATTERN (insn);
+
+      if (GET_CODE (xinsn) != SET)
+       return 0;
+
+      xdest = SET_DEST (xinsn);
+      xsrc = SET_SRC (xinsn);
+
+      if (GET_CODE (xdest) == SUBREG)
+       abort ();
+
+      if ( ! REG_P (xdest))
+       continue;
+
+      if (REGNO (op) == REGNO (xdest)
+         && ((GET_CODE (xsrc) == SIGN_EXTEND
+          && GET_MODE (XEXP (xsrc, 0)) == from_mode)
+         || (GET_CODE (xsrc) == MEM
+             && GET_MODE (xsrc) == from_mode)))
+       return 1;
+
+      /* The register is modified by another operation.  */
+      if (reg_overlap_mentioned_p (xdest, op))
+       return 0;
+    }
+}
+
+char *
+output_move_double (operands)
+     rtx *operands;
+{
+  if (GET_CODE (operands[1]) == CONST_DOUBLE)
+    {
+      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT)
+       {
+         /* In an integer, the low-order word is in CONST_DOUBLE_LOW.  */
+         rtx const_op = operands[1];
+         if ((CONST_DOUBLE_HIGH (const_op) == 0
+              && CONST_DOUBLE_LOW (const_op) >= 0)
+             || (CONST_DOUBLE_HIGH (const_op) == -1
+                 && CONST_DOUBLE_LOW (const_op) < 0))
+           {
+             operands[1] = gen_rtx (CONST_INT, VOIDmode,
+                                    CONST_DOUBLE_LOW (const_op));
+             return "movl %1,%0";
+           }
+         operands[1] = gen_rtx (CONST_INT, VOIDmode,
+                                CONST_DOUBLE_HIGH (const_op));
+         output_asm_insn ("movw %1,%0", operands);
+         operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+         operands[1] = gen_rtx (CONST_INT, VOIDmode,
+                                CONST_DOUBLE_LOW (const_op));
+         return "movw %1,%0";
+       }
+      else
+       {
+         /* In a real, the low-address word is in CONST_DOUBLE_LOW.  */
+         rtx const_op = operands[1];
+         if ((CONST_DOUBLE_LOW (const_op) == 0
+              && CONST_DOUBLE_HIGH (const_op) >= 0)
+             || (CONST_DOUBLE_LOW (const_op) == -1
+                 && CONST_DOUBLE_HIGH (const_op) < 0))
+           {
+             operands[1] = gen_rtx (CONST_INT, VOIDmode,
+                                    CONST_DOUBLE_HIGH (const_op));
+             return "movl %1,%0";
+           }
+         operands[1] = gen_rtx (CONST_INT, VOIDmode,
+                                CONST_DOUBLE_LOW (const_op));
+         output_asm_insn ("movw %1,%0", operands);
+         operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+         operands[1] = gen_rtx (CONST_INT, VOIDmode,
+                                CONST_DOUBLE_HIGH (const_op));
+         return "movw %1,%0";
+       }
+    }
+
+  return "movl %1,%0";
+}
+
+/* Output a shift insns, after having reduced integer arguments to
+   avoid as warnings.  */
+
+char *
+output_shift (pattern, op2, mod)
+     char *pattern;
+     rtx op2;
+     int mod;
+{
+  if (GET_CODE (op2) == CONST_INT)
+    {
+      int cnt = INTVAL (op2) % mod;
+      if (cnt == 0)
+       {
+         cc_status = cc_prev_status;
+         return "";
+       }
+      op2 = gen_rtx (CONST_INT, VOIDmode, cnt);
+    }
+  return pattern;
+}
+
+/* Return non-zero if the code of this rtx pattern is a relop.  */
+
+int
+relop (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  switch (GET_CODE (op))
+    {
+    case EQ:
+    case NE:
+    case LT:
+    case LE:
+    case GE:
+    case GT:
+    case LTU:
+    case LEU:
+    case GEU:
+    case GTU:
+      return 1;
+    }
+  return 0;
+}
+
+void
+notice_update_cc (EXP, INSN)
+     rtx EXP, INSN;
+{
+  switch (GET_CODE (EXP))
+    {
+    case SET:
+      switch (GET_CODE (SET_DEST (EXP)))
+       {
+       case CC0:
+         cc_status.mdep = 0;
+         cc_status.flags = 0;
+         cc_status.value1 = 0;
+         cc_status.value2 = SET_SRC (EXP);
+         break;
+
+       case PC:
+         break;
+
+       case REG:
+         switch (GET_CODE (SET_SRC (EXP)))
+           {
+           case CALL:
+             goto call;
+           case MEM:
+             if (GET_MODE (SET_SRC (EXP)) == QImode
+                 || GET_MODE (SET_SRC (EXP)) == HImode)
+               {
+                 cc_status.mdep = 0;
+                 cc_status.flags = CC_NO_OVERFLOW;
+                 cc_status.value1 = SET_DEST (EXP);
+                 cc_status.value2 = SET_SRC (EXP);
+                 break;
+               }
+             /* else: Fall through.  */
+           case CONST_INT:
+           case SYMBOL_REF:
+           case LABEL_REF:
+           case CONST:
+           case CONST_DOUBLE:
+           case REG:
+             if (cc_status.value1
+                 && reg_overlap_mentioned_p (SET_DEST (EXP),
+                                             cc_status.value1))
+               cc_status.value1 = 0;
+             if (cc_status.value2
+                 && reg_overlap_mentioned_p (SET_DEST (EXP),
+                                             cc_status.value2))
+               cc_status.value2 = 0;
+             break;
+
+           case UDIV:
+           case UMOD:
+             cc_status.mdep = CC_VALID_FOR_UNSIGNED;
+             cc_status.flags = CC_NO_OVERFLOW;
+             cc_status.value1 = SET_DEST (EXP);
+             cc_status.value2 = SET_SRC (EXP);
+             break;
+           default:
+             cc_status.mdep = 0;
+             cc_status.flags = CC_NO_OVERFLOW;
+             cc_status.value1 = SET_DEST (EXP);
+             cc_status.value2 = SET_SRC (EXP);
+             break;
+           }
+         break;
+
+       case MEM:
+         switch (GET_CODE (SET_SRC (EXP)))
+           {
+           case REG:
+             if (GET_MODE (SET_SRC (EXP)) == QImode
+                 || GET_MODE (SET_SRC (EXP)) == HImode)
+               {
+                 cc_status.flags = CC_NO_OVERFLOW;
+                 cc_status.value1 = SET_DEST (EXP);
+                 cc_status.value2 = SET_SRC (EXP);
+                 cc_status.mdep = 0;
+                 break;
+               }
+             /* else: Fall through.  */
+           case CONST_INT:
+           case SYMBOL_REF:
+           case LABEL_REF:
+           case CONST:
+           case CONST_DOUBLE:
+           case MEM:
+             /* Need to forget cc_status about memory positions each
+                time a memory store is made, even if the memory store
+                insns in question doesn't modify the condition codes.  */
+             if (cc_status.value1 &&
+                 GET_CODE (cc_status.value1) == MEM)
+               cc_status.value1 = 0;
+             if (cc_status.value2 &&
+                 GET_CODE (cc_status.value2) == MEM)
+               cc_status.value2 = 0;
+             break;
+           case SIGN_EXTEND:
+           case FLOAT_EXTEND:
+           case FLOAT_TRUNCATE:
+           case FLOAT:
+           case FIX:
+             cc_status.flags = CC_NO_OVERFLOW;
+             cc_status.value1 = SET_DEST (EXP);
+             cc_status.value2 = SET_SRC (EXP);
+             cc_status.mdep = 0;
+             break;
+
+           default:
+             abort ();
+           }
+         break;
+
+       default:
+         abort ();
+       }
+      break;
+
+    case CALL:
+    call:
+      CC_STATUS_INIT;
+      break;
+      /* Do calls preserve the condition codes?  (At least forget
+        cc_status expressions if they refer to registers
+        not preserved across calls.  Also forget expressions
+        about memory contents.)  */
+      if (cc_status.value1
+         && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
+                                cc_status.value1, 0)
+             || GET_CODE (cc_status.value1) == MEM))
+       cc_status.value1 = 0;
+      if (cc_status.value2
+         && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
+                                cc_status.value2, 0)
+             || GET_CODE (cc_status.value2) == MEM))
+       cc_status.value2 = 0;
+      break;
+
+    default:
+      CC_STATUS_INIT;
+    }
+}
+
+void
+forget_cc_if_dependent (op)
+     rtx op;
+{
+  cc_status = cc_prev_status;
+  if (cc_status.value1 && reg_overlap_mentioned_p (op, cc_status.value1))
+    cc_status.value1 = 0;
+  if (cc_status.value2 && reg_overlap_mentioned_p (op, cc_status.value2))
+    cc_status.value2 = 0;
+}
This page took 0.082628 seconds and 5 git commands to generate.