]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/reg-stack.c
45th Cygnus<->FSF merge
[gcc.git] / gcc / reg-stack.c
index 62a549d19a7201d2dae452ce6e276f940e41db2b..dd30344db83cdfc50853058848c86c88fd7c64c9 100644 (file)
@@ -1,5 +1,5 @@
 /* Register to Stack convert for GNU compiler.
-   Copyright (C) 1992 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -175,9 +175,11 @@ static int current_function_returns_real;
 /* This is the basic stack record.  TOP is an index into REG[] such
    that REG[TOP] is the top of stack.  If TOP is -1 the stack is empty.
 
-   If TOP is -2 the stack is not yet initialized: reg_set indicates
-   which registers are live.  Stack initialization consists of placing
-   each live reg in array `reg' and setting `top' appropriately. */
+   If TOP is -2, REG[] is not yet initialized.  Stack initialization
+   consists of placing each live reg in array `reg' and setting `top'
+   appropriately.
+
+   REG_SET indicates which registers are live.  */
 
 typedef struct stack_def
 {
@@ -214,7 +216,7 @@ static HARD_REG_SET *block_out_reg_set;
    later, but only to look up an insn that is the head or tail of some
    block.  life_analysis and the stack register conversion process can
    add insns within a block. */
-static short *block_number;
+static int *block_number;
 
 /* This is the register file for all register after conversion */
 static rtx FP_mode_reg[FIRST_PSEUDO_REGISTER][(int) MAX_MACHINE_MODE];
@@ -224,11 +226,12 @@ static rtx FP_mode_reg[FIRST_PSEUDO_REGISTER][(int) MAX_MACHINE_MODE];
 
 #define BLOCK_NUM(INSN)  \
   (((INSN_UID (INSN) > max_uid)        \
-    ? (short *)(abort() , 0)           \
+    ? (int *)(abort() , 0)             \
     : block_number)[INSN_UID (INSN)])
 
+extern rtx forced_labels;
 extern rtx gen_jump ();
-extern rtx gen_movdf ();
+extern rtx gen_movdf (), gen_movxf ();
 extern rtx find_regno_note ();
 extern rtx emit_jump_insn_before ();
 extern rtx emit_label_after ();
@@ -236,6 +239,7 @@ extern rtx emit_label_after ();
 /* Forward declarations */
 
 static void find_blocks ();
+static uses_reg_or_mem ();
 static void stack_reg_life_analysis ();
 static void change_stack ();
 static void convert_regs ();
@@ -245,7 +249,7 @@ static void dump_stack_info ();
 
 int
 stack_regs_mentioned_p (pat)
-     register rtx pat;
+     rtx pat;
 {
   register char *fmt;
   register int i;
@@ -301,7 +305,7 @@ reg_to_stack (first, file)
 
   /* Count the basic blocks.  Also find maximum insn uid.  */
   {
-    register RTX_CODE prev_code = JUMP_INSN;
+    register RTX_CODE prev_code = BARRIER;
     register RTX_CODE code;
 
     max_uid = 0;
@@ -309,7 +313,8 @@ reg_to_stack (first, file)
     for (insn = first; insn; insn = NEXT_INSN (insn))
       {
        /* Note that this loop must select the same block boundaries
-          as code in find_blocks. */
+          as code in find_blocks.  Also note that this code is not the
+          same as that used in flow.c.  */
 
        if (INSN_UID (insn) > max_uid)
          max_uid = INSN_UID (insn);
@@ -320,14 +325,13 @@ reg_to_stack (first, file)
            || (prev_code != INSN
                && prev_code != CALL_INSN
                && prev_code != CODE_LABEL
-               && (code == INSN || code == CALL_INSN || code == JUMP_INSN)))
+               && GET_RTX_CLASS (code) == 'i'))
          blocks++;
 
        /* Remember whether or not this insn mentions an FP regs.
           Check JUMP_INSNs too, in case someone creates a funny PARALLEL. */
 
-       if ((GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
-            || GET_CODE (insn) == JUMP_INSN)
+       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
            && stack_regs_mentioned_p (PATTERN (insn)))
          {
            stack_reg_seen = 1;
@@ -336,6 +340,9 @@ reg_to_stack (first, file)
        else
          PUT_MODE (insn, VOIDmode);
 
+       if (code == CODE_LABEL)
+         LABEL_REFS (insn) = insn; /* delete old chain */
+
        if (code != NOTE)
          prev_code = code;
       }
@@ -364,7 +371,7 @@ reg_to_stack (first, file)
   bzero (block_stack_in, blocks * sizeof (struct stack_def));
   bzero (block_out_reg_set, blocks * sizeof (HARD_REG_SET));
 
-  block_number = (short *) alloca ((max_uid + 1) * sizeof (short));
+  block_number = (int *) alloca ((max_uid + 1) * sizeof (int));
 
   find_blocks (first);
   stack_reg_life_analysis (first);
@@ -404,7 +411,9 @@ record_label_references (insn, pat)
 
       /* Don't make a duplicate in the code_label's chain. */
 
-      for (ref = LABEL_REFS (label); ref != label; ref = LABEL_NEXTREF (ref))
+      for (ref = LABEL_REFS (label);
+          ref && ref != label;
+          ref = LABEL_NEXTREF (ref))
        if (CONTAINING_INSN (ref) == insn)
          return;
 
@@ -440,42 +449,11 @@ get_true_reg (pat)
   while (GET_CODE (*pat) == SUBREG
         || GET_CODE (*pat) == FLOAT
         || GET_CODE (*pat) == FIX
-        || GET_CODE (*pat) == FLOAT_EXTEND
-        || GET_CODE (*pat) == FLOAT_TRUNCATE)
+        || GET_CODE (*pat) == FLOAT_EXTEND)
     pat = & XEXP (*pat, 0);
 
   return pat;
 }
-
-/* If REG is a stack register that is marked dead in REGSTACK, then
-   record that it is now live. If REG is not DEST, add a death note to
-   INSN if there isn't one already.  If DEST is not a reg, it is safe to
-   assume that it does not mention a reg anywhere within. */
-
-static void
-record_note_if_dead (insn, regstack, reg, dest)
-     rtx insn;
-     stack regstack;
-     rtx reg, dest;
-{
-  reg = * get_true_reg (& reg);
-
-  if (STACK_REG_P (reg))
-    {
-      if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (reg)))
-       {
-         if ((! REG_P (dest) || REGNO (dest) != REGNO (reg))
-             && ! find_regno_note (insn, REG_DEAD, REGNO (reg)))
-           REG_NOTES (insn) = gen_rtx (EXPR_LIST,
-                                       REG_DEAD, reg, REG_NOTES (insn));
-
-         SET_HARD_REG_BIT (regstack->reg_set, REGNO (reg));
-       }
-    }
-  else
-    if (stack_regs_mentioned_p (reg))
-      abort ();
-}
 \f
 /* Scan the OPERANDS and OPERAND_CONSTRAINTS of an asm_operands.
    N_OPERANDS is the total number of operands.  Return which alternative
@@ -561,7 +539,6 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
              case '=':
              case '+':
              case '?':
-             case '#':
              case '&':
              case '!':
              case '*':
@@ -569,6 +546,11 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
                /* Ignore these. */
                break;
 
+             case '#':
+               /* Ignore rest of this alternative. */
+               while (*p && *p != ',') p++;
+               break;
+
              case '0':
              case '1':
              case '2':
@@ -651,7 +633,7 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
                /* Match any CONST_DOUBLE, but only if
                   we can examine the bits of it reliably.  */
                if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-                    || HOST_BITS_PER_INT != BITS_PER_WORD)
+                    || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
                    && GET_CODE (op) != VOIDmode && ! flag_pretend_float)
                  break;
                if (GET_CODE (op) == CONST_DOUBLE)
@@ -792,13 +774,12 @@ record_asm_reg_life (insn, regstack, operands, constraints,
 
   rtx *clobber_reg;
 
-  /* Find out what the constraints required.  If no constraint
-     alternative matches, that is a compiler bug: we should have caught
-     such an insn during reload.  */
+  /* Find out what the constraints require.  If no constraint
+     alternative matches, this asm is malformed.  */
   i = constrain_asm_operands (n_operands, operands, constraints,
                              operand_matches, operand_class);
   if (i < 0)
-    abort ();
+    malformed_asm = 1;
 
   /* Strip SUBREGs here to make the following code simpler. */
   for (i = 0; i < n_operands; i++)
@@ -841,7 +822,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
   bzero (reg_used_as_output, sizeof (reg_used_as_output));
   for (i = 0; i < n_outputs; i++)
     if (STACK_REG_P (operands[i]))
-      if (reg_class_size[operand_class[i]] != 1)
+      if (reg_class_size[(int) operand_class[i]] != 1)
        {
          error_for_asm
            (insn, "Output constraint %d must specify a single register", i);
@@ -969,7 +950,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
 
       if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]))
          && operand_matches[i] == -1
-         && ! find_regno_note (insn, REG_DEAD, REGNO (operands[i])))
+         && find_regno_note (insn, REG_DEAD, REGNO (operands[i])) == NULL_RTX)
        REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, operands[i],
                                    REG_NOTES (insn));
 
@@ -977,103 +958,54 @@ record_asm_reg_life (insn, regstack, operands, constraints,
     }
 }
 
-/* Scan PAT, which is part of INSN, and record the life & death of
-   stack registers in REGSTACK.  If a register was dead, but is an input
-   operand in this insn, then mark the register live and record a death
-   note.
-
-   If a register is dead after this insn, but is an output operand in
-   this insn, record a REG_UNUSED note.
+/* Scan PAT, which is part of INSN, and record registers appearing in
+   a SET_DEST in DEST, and other registers in SRC.
 
    This function does not know about SET_DESTs that are both input and
    output (such as ZERO_EXTRACT) - this cannot happen on a 387. */
 
-static void
-record_reg_life_pat (insn, regstack, pat)
-     rtx insn;
-     stack regstack;
+void
+record_reg_life_pat (pat, src, dest)
      rtx pat;
+     HARD_REG_SET *src, *dest;
 {
-  rtx src, dest;
-
-  /* We should have already handled any asm.  */
-  if (GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ASM_OPERANDS)
-    abort ();
-
-  if (GET_CODE (pat) != SET)
-    return;
-
-  dest = * get_true_reg (& SET_DEST (pat));
-
-  /* The destination is dead before this insn.  If the destination is
-     not used after this insn, record this with REG_UNUSED. */
+  register char *fmt;
+  register int i;
 
-  if (STACK_REG_P (dest))
+  if (STACK_REG_P (pat))
     {
-      /* ??? This check is unnecessary. */
-
-      if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
-       abort ();
+      if (src)
+       SET_HARD_REG_BIT (*src, REGNO (pat));
 
-      if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (dest)))
-       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED, dest,
-                                   REG_NOTES (insn));
+      if (dest)
+       SET_HARD_REG_BIT (*dest, REGNO (pat));
 
-      CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+      return;
     }
-  else
-    if (dest != cc0_rtx && stack_regs_mentioned_p (dest))
-      abort ();
-
-  src = * get_true_reg (& SET_SRC (pat));
 
-  switch (GET_CODE (src))
+  if (GET_CODE (pat) == SET)
     {
-      /* ??? get_true_reg will make some of these cases redundant. */
-
-    case PLUS:
-    case MINUS:
-    case MULT:
-    case DIV:
-    case COMPARE:
-      record_note_if_dead (insn, regstack, XEXP (src, 0), dest);
-      record_note_if_dead (insn, regstack, XEXP (src, 1), dest);
-      break;
-
-    case ABS:
-    case NEG:
-    case SQRT:
-    case FLOAT_EXTEND:
-    case FLOAT_TRUNCATE:
-    case FLOAT:
-    case UNSIGNED_FLOAT:
-      record_note_if_dead (insn, regstack, XEXP (src, 0), dest);
-      break;
-
-    case UNSIGNED_FIX:
-    case FIX:
-      src = XEXP (src, 0);
-      if (GET_CODE (src) == FIX)
-       record_note_if_dead (insn, regstack, XEXP (src, 0), dest);
-      else
-       record_note_if_dead (insn, regstack, src, dest);
-      break;
-
-    case ASM_OPERANDS:
-    case ASM_INPUT:
-      abort ();  /* we should have caught this already. */
-      break;
+      record_reg_life_pat (XEXP (pat, 0), NULL_PTR, dest);
+      record_reg_life_pat (XEXP (pat, 1), src, NULL_PTR);
+      return;
+    }
 
-    case REG:
-      record_note_if_dead (insn, regstack, src, dest);
-      break;
+  /* We don't need to consider either of these cases. */
+  if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+    return;
 
-    default:
-      /* If a stack register appears in the src RTL, it is a bug, and
-        code should be added above to handle it. */
+  fmt = GET_RTX_FORMAT (GET_CODE (pat));
+  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
 
-      if (stack_regs_mentioned_p (src))
-       abort ();
+         for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+           record_reg_life_pat (XVECEXP (pat, i, j), src, dest);
+       }
+      else if (fmt[i] == 'e')
+       record_reg_life_pat (XEXP (pat, i), src, dest);
     }
 }
 \f
@@ -1156,22 +1088,40 @@ record_reg_life (insn, block, regstack)
       int n_inputs, n_outputs;
       char **constraints = (char **) alloca (n_operands * sizeof (char *));
 
-      decode_asm_operands (body, operands, 0, constraints, 0);
+      decode_asm_operands (body, operands, NULL_PTR, constraints, NULL_PTR);
       get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);
       record_asm_reg_life (insn, regstack, operands, constraints,
                           n_inputs, n_outputs);
       return;
     }
 
-  if (GET_CODE (PATTERN (insn)) == PARALLEL)
+  /* An insn referencing a stack reg has a mode of QImode. */
+  if (GET_MODE (insn) == QImode)
     {
-      register int i;
+      HARD_REG_SET src, dest;
+      int regno;
 
-      for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
-       record_reg_life_pat (insn, regstack, XVECEXP (PATTERN (insn), 0, i));
+      CLEAR_HARD_REG_SET (src);
+      CLEAR_HARD_REG_SET (dest);
+      record_reg_life_pat (PATTERN (insn), &src, &dest);
+
+      for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
+       if (! TEST_HARD_REG_BIT (regstack->reg_set, regno))
+         {
+           if (TEST_HARD_REG_BIT (src, regno)
+               && ! TEST_HARD_REG_BIT (dest, regno))
+             REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
+                                         FP_mode_reg[regno][(int) DFmode],
+                                         REG_NOTES (insn));
+           else if (TEST_HARD_REG_BIT (dest, regno))
+             REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED,
+                                         FP_mode_reg[regno][(int) DFmode],
+                                         REG_NOTES (insn));
+         }
+
+      AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
+      IOR_HARD_REG_SET (regstack->reg_set, src);
     }
-  else if (GET_MODE (insn) == QImode)
-    record_reg_life_pat (insn, regstack, PATTERN (insn));
 
   /* There might be a reg that is live after a function call.
      Initialize it to zero so that the program does not crash.  See comment
@@ -1182,8 +1132,7 @@ record_reg_life (insn, block, regstack)
       int reg = FIRST_FLOAT_REG;
 
       /* If a stack reg is mentioned in a CALL_INSN, it must be as the
-        return value; conversely, if a float is returned, a stack reg
-        must be mentioned. */
+        return value.  */
 
       if (stack_regs_mentioned_p (PATTERN (insn)))
        reg++;
@@ -1229,6 +1178,7 @@ find_blocks (first)
   register int block;
   register RTX_CODE prev_code = BARRIER;
   register RTX_CODE code;
+  rtx label_value_list = 0;
 
   /* Record where all the blocks start and end.
      Record which basic blocks control can drop in to. */
@@ -1237,7 +1187,8 @@ find_blocks (first)
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       /* Note that this loop must select the same block boundaries
-        as code in reg_to_stack. */
+        as code in reg_to_stack, but that these are not the same
+        as those selected in flow.c.  */
 
       code = GET_CODE (insn);
 
@@ -1245,19 +1196,27 @@ find_blocks (first)
          || (prev_code != INSN
              && prev_code != CALL_INSN
              && prev_code != CODE_LABEL
-             && (code == INSN || code == CALL_INSN || code == JUMP_INSN)))
+             && GET_RTX_CLASS (code) == 'i'))
        {
          block_begin[++block] = insn;
          block_end[block] = insn;
          block_drops_in[block] = prev_code != BARRIER;
        }
-      else if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
+      else if (GET_RTX_CLASS (code) == 'i')
        block_end[block] = insn;
 
-      BLOCK_NUM (insn) = block;
+      if (GET_RTX_CLASS (code) == 'i')
+       {
+         rtx note;
 
-      if (code == CODE_LABEL)
-       LABEL_REFS (insn) = insn; /* delete old chain */
+         /* Make a list of all labels referred to other than by jumps.  */
+         for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+           if (REG_NOTE_KIND (note) == REG_LABEL)
+             label_value_list = gen_rtx (EXPR_LIST, VOIDmode, XEXP (note, 0),
+                                         label_value_list);
+       }
+
+      BLOCK_NUM (insn) = block;
 
       if (code != NOTE)
        prev_code = code;
@@ -1266,15 +1225,113 @@ find_blocks (first)
   if (block + 1 != blocks)
     abort ();
 
-  /* generate all label references to the correspondending jump insn */
+  /* generate all label references to the corresponding jump insn */
   for (block = 0; block < blocks; block++)
     {
       insn = block_end[block];
 
       if (GET_CODE (insn) == JUMP_INSN)
-       record_label_references (insn, PATTERN (insn));
+       {
+         rtx pat = PATTERN (insn);
+         int computed_jump = 0;
+         rtx x;
+
+         if (GET_CODE (pat) == PARALLEL)
+           {
+             int len = XVECLEN (pat, 0);
+             int has_use_labelref = 0;
+             int i;
+
+             for (i = len - 1; i >= 0; i--)
+               if (GET_CODE (XVECEXP (pat, 0, i)) == USE
+                   && GET_CODE (XEXP (XVECEXP (pat, 0, i), 0)) == LABEL_REF)
+                 has_use_labelref = 1;
+
+             if (! has_use_labelref)
+               for (i = len - 1; i >= 0; i--)
+                 if (GET_CODE (XVECEXP (pat, 0, i)) == SET
+                     && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
+                     && uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
+                   computed_jump = 1;
+           }
+         else if (GET_CODE (pat) == SET
+                  && SET_DEST (pat) == pc_rtx
+                  && uses_reg_or_mem (SET_SRC (pat)))
+           computed_jump = 1;
+                   
+         if (computed_jump)
+           {
+             for (x = label_value_list; x; x = XEXP (x, 1))
+               record_label_references (insn,
+                                        gen_rtx (LABEL_REF, VOIDmode,
+                                                 XEXP (x, 0)));
+
+             for (x = forced_labels; x; x = XEXP (x, 1))
+               record_label_references (insn,
+                                        gen_rtx (LABEL_REF, VOIDmode,
+                                                 XEXP (x, 0)));
+           }
+
+         record_label_references (insn, pat);
+       }
     }
 }
+
+/* Return 1 if X contain a REG or MEM that is not in the constant pool.  */
+
+static int
+uses_reg_or_mem (x)
+     rtx x;
+{
+  enum rtx_code code = GET_CODE (x);
+  int i, j;
+  char *fmt;
+
+  if (code == REG
+      || (code == MEM
+         && ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+               && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))))
+    return 1;
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e'
+         && uses_reg_or_mem (XEXP (x, i)))
+       return 1;
+
+      if (fmt[i] == 'E')
+       for (j = 0; j < XVECLEN (x, i); j++)
+         if (uses_reg_or_mem (XVECEXP (x, i, j)))
+           return 1;
+    }
+
+  return 0;
+}
+
+/* If current function returns its result in an fp stack register,
+   return the register number.  Otherwise return -1.  */
+
+static int
+stack_result_p (decl)
+     tree decl;
+{
+  rtx result = DECL_RTL (DECL_RESULT (decl));
+
+  if (result != 0
+      && !(GET_CODE (result) == REG
+          && REGNO (result) < FIRST_PSEUDO_REGISTER))
+    {
+#ifdef FUNCTION_OUTGOING_VALUE
+      result
+        = FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
+#else
+      result = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
+#endif
+    }
+
+  return STACK_REG_P (result) ? REGNO (result) : -1;
+}
 \f
 /* Determine the which registers are live at the start of each basic
    block of the function whose first insn is FIRST.
@@ -1313,21 +1370,24 @@ stack_reg_life_analysis (first)
   int reg, block;
   struct stack_def regstack;
 
-  if (current_function_returns_real)
+  if (current_function_returns_real
+      && stack_result_p (current_function_decl) >= 0)
     {
       /* Find all RETURN insns and mark them. */
 
+      int value_regno = stack_result_p (current_function_decl);
+
       for (block = blocks - 1; block >= 0; block--)
        if (GET_CODE (block_end[block]) == JUMP_INSN
            && GET_CODE (PATTERN (block_end[block])) == RETURN)
-         SET_HARD_REG_BIT (block_out_reg_set[block], FIRST_STACK_REG);
+         SET_HARD_REG_BIT (block_out_reg_set[block], value_regno);
 
       /* Mark of the end of last block if we "fall off" the end of the
         function into the epilogue. */
 
       if (GET_CODE (block_end[blocks-1]) != JUMP_INSN
          || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN)
-       SET_HARD_REG_BIT (block_out_reg_set[blocks-1], FIRST_STACK_REG);
+       SET_HARD_REG_BIT (block_out_reg_set[blocks-1], value_regno);
     }
 
   /* now scan all blocks backward for stack register use */
@@ -1560,7 +1620,8 @@ emit_pop_insn (insn, regstack, reg, when)
                     FP_mode_reg[FIRST_STACK_REG][(int) DFmode]);
 
   pop_insn = (*when) (pop_rtx, insn);
-  PUT_MODE (pop_insn, VOIDmode);
+  /* ??? This used to be VOIDmode, but that seems wrong. */
+  PUT_MODE (pop_insn, QImode);
 
   REG_NOTES (pop_insn) = gen_rtx (EXPR_LIST, REG_DEAD,
                                  FP_mode_reg[FIRST_STACK_REG][(int) DFmode],
@@ -1583,48 +1644,75 @@ emit_pop_insn (insn, regstack, reg, when)
    If REG is already at the top of the stack, no insn is emitted. */
 
 static void
-emit_hard_swap_insn (insn, regstack, hard_regno, when)
+emit_swap_insn (insn, regstack, reg)
      rtx insn;
      stack regstack;
-     int hard_regno;
-     rtx (*when)();
+     rtx reg;
 {
+  int hard_regno;
   rtx gen_swapdf();
   rtx swap_rtx, swap_insn;
-  int tmp, other;
+  int tmp, other_reg;          /* swap regno temps */
+  rtx i1;                      /* the stack-reg insn prior to INSN */
+  rtx i1set = NULL_RTX;                /* the SET rtx within I1 */
 
+  hard_regno = get_hard_regnum (regstack, reg);
+
+  if (hard_regno < FIRST_STACK_REG)
+    abort ();
   if (hard_regno == FIRST_STACK_REG)
     return;
 
-  swap_rtx = gen_swapdf (FP_mode_reg[hard_regno][(int) DFmode],
-                        FP_mode_reg[FIRST_STACK_REG][(int) DFmode]);
-  swap_insn = (*when) (swap_rtx, insn);
-  PUT_MODE (swap_insn, VOIDmode);
-
-  other = regstack->top - (hard_regno - FIRST_STACK_REG);
+  other_reg = regstack->top - (hard_regno - FIRST_STACK_REG);
 
-  tmp = regstack->reg[other];
-  regstack->reg[other] = regstack->reg[regstack->top];
+  tmp = regstack->reg[other_reg];
+  regstack->reg[other_reg] = regstack->reg[regstack->top];
   regstack->reg[regstack->top] = tmp;
-}
 
-/* Emit an insn before or after INSN to swap virtual register REG with the
-   top of stack.  See comments before emit_hard_swap_insn. */
+  /* Find the previous insn involving stack regs, but don't go past
+     any labels, calls or jumps.  */
+  i1 = prev_nonnote_insn (insn);
+  while (i1 && GET_CODE (i1) == INSN && GET_MODE (i1) != QImode)
+    i1 = prev_nonnote_insn (i1);
 
-static void
-emit_swap_insn (insn, regstack, reg, when)
-     rtx insn;
-     stack regstack;
-     rtx reg;
-     rtx (*when)();
-{
-  int hard_regno;
+  if (i1)
+    i1set = single_set (i1);
 
-  hard_regno = get_hard_regnum (regstack, reg);
-  if (hard_regno < FIRST_STACK_REG)
-    abort ();
+  if (i1set)
+    {
+      rtx i2;                  /* the stack-reg insn prior to I1 */
+      rtx i1src = *get_true_reg (&SET_SRC (i1set));
+      rtx i1dest = *get_true_reg (&SET_DEST (i1set));
+
+      /* If the previous register stack push was from the reg we are to
+        swap with, omit the swap. */
 
-  emit_hard_swap_insn (insn, regstack, hard_regno, when);
+      if (GET_CODE (i1dest) == REG && REGNO (i1dest) == FIRST_STACK_REG
+         && GET_CODE (i1src) == REG && REGNO (i1src) == hard_regno - 1
+         && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX)
+       return;
+
+      /* If the previous insn wrote to the reg we are to swap with,
+        omit the swap.  */
+
+      if (GET_CODE (i1dest) == REG && REGNO (i1dest) == hard_regno
+         && GET_CODE (i1src) == REG && REGNO (i1src) == FIRST_STACK_REG
+         && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX)
+       return;
+    }
+
+  if (GET_RTX_CLASS (GET_CODE (i1)) == 'i' && sets_cc0_p (PATTERN (i1)))
+    {
+      i1 = next_nonnote_insn (i1);
+      if (i1 == insn)
+       abort ();
+    }
+
+  swap_rtx = gen_swapdf (FP_mode_reg[hard_regno][(int) DFmode],
+                        FP_mode_reg[FIRST_STACK_REG][(int) DFmode]);
+  swap_insn = emit_insn_after (swap_rtx, i1);
+  /* ??? This used to be VOIDmode, but that seems wrong. */
+  PUT_MODE (swap_insn, QImode);
 }
 \f
 /* Handle a move to or from a stack register in PAT, which is in INSN.
@@ -1715,7 +1803,7 @@ move_for_stack_reg (insn, regstack, pat)
         only top of stack may be saved, emit an exchange first if
         needs be. */
 
-      emit_swap_insn (insn, regstack, *src, emit_insn_before);
+      emit_swap_insn (insn, regstack, *src);
 
       note = find_regno_note (insn, REG_DEAD, REGNO (*src));
       if (note)
@@ -1724,6 +1812,24 @@ move_for_stack_reg (insn, regstack, pat)
          regstack->top--;
          CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src));
        }
+      else if (GET_MODE (*src) == XFmode && regstack->top != REG_STACK_SIZE)
+       {
+         /* A 387 cannot write an XFmode value to a MEM without
+            clobbering the source reg.  The output code can handle
+            this by reading back the value from the MEM.
+            But it is more efficient to use a temp register if one is
+            available.  Push the source value here if the register
+            stack is not full, and then write the value to memory via
+            a pop.  */
+         rtx push_rtx, push_insn;
+         rtx top_stack_reg = FP_mode_reg[FIRST_STACK_REG][(int) XFmode];
+
+         push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
+         push_insn = emit_insn_before (push_rtx, insn);
+         PUT_MODE (push_insn, QImode);
+         REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, top_stack_reg,
+                                     REG_NOTES (insn));
+       }
 
       replace_reg (src, FIRST_STACK_REG);
     }
@@ -1749,6 +1855,34 @@ move_for_stack_reg (insn, regstack, pat)
     abort ();
 }
 \f
+void
+swap_rtx_condition (pat)
+     rtx pat;
+{
+  register char *fmt;
+  register int i;
+
+  if (GET_RTX_CLASS (GET_CODE (pat)) == '<')
+    {
+      PUT_CODE (pat, swap_condition (GET_CODE (pat)));
+      return;
+    }
+
+  fmt = GET_RTX_FORMAT (GET_CODE (pat));
+  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+
+         for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+           swap_rtx_condition (XVECEXP (pat, i, j));
+       }
+      else if (fmt[i] == 'e')
+       swap_rtx_condition (XEXP (pat, i));
+    }
+}
+
 /* Handle a comparison.  Special care needs to be taken to avoid
    causing comparisons that a 387 cannot do correctly, such as EQ.
 
@@ -1769,11 +1903,29 @@ compare_for_stack_reg (insn, regstack, pat)
   src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
   src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
 
-  /* The first argument must always be a stack reg. */
-  /* ??? why? */
+  /* ??? If fxch turns out to be cheaper than fstp, give priority to
+     registers that die in this insn - move those to stack top first. */
+  if (! STACK_REG_P (*src1)
+      || (STACK_REG_P (*src2)
+         && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
+    {
+      rtx temp, next;
 
-  if (! STACK_REG_P (*src1))
-    abort ();
+      temp = XEXP (SET_SRC (pat), 0);
+      XEXP (SET_SRC (pat), 0) = XEXP (SET_SRC (pat), 1);
+      XEXP (SET_SRC (pat), 1) = temp;
+
+      src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
+      src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
+
+      next = next_cc0_user (insn);
+      if (next == NULL_RTX)
+       abort ();
+
+      swap_rtx_condition (PATTERN (next));
+      INSN_CODE (next) = -1;
+      INSN_CODE (insn) = -1;
+    }
 
   /* We will fix any death note later. */
 
@@ -1782,9 +1934,9 @@ compare_for_stack_reg (insn, regstack, pat)
   if (STACK_REG_P (*src2))
     src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
   else
-    src2_note = 0;
+    src2_note = NULL_RTX;
 
-  emit_swap_insn (insn, regstack, *src1, emit_insn_before);
+  emit_swap_insn (insn, regstack, *src1);
 
   replace_reg (src1, FIRST_STACK_REG);
 
@@ -1803,8 +1955,7 @@ compare_for_stack_reg (insn, regstack, pat)
      needed, and it was just handled. */
 
   if (src2_note
-      && ! (STACK_REG_P (*src1)
-           && STACK_REG_P (*src2)
+      && ! (STACK_REG_P (*src1) && STACK_REG_P (*src2)
            && REGNO (*src1) == REGNO (*src2)))
     {
       /* As a special case, two regs may die in this insn if src2 is
@@ -1825,6 +1976,8 @@ compare_for_stack_reg (insn, regstack, pat)
             the case handled above.  In all other cases, emit a separate
             pop and remove the death note from here. */
 
+         link_cc0_insns (insn);
+
          remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
 
          emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
@@ -1843,7 +1996,7 @@ subst_stack_regs_pat (insn, regstack, pat)
      rtx pat;
 {
   rtx *dest, *src;
-  rtx *src1 = 0, *src2;
+  rtx *src1 = (rtx *) NULL_PTR, *src2;
   rtx src1_note, src2_note;
 
   if (GET_CODE (pat) != SET)
@@ -1882,6 +2035,7 @@ subst_stack_regs_pat (insn, regstack, pat)
 
        /* Fall through. */
 
+      case FLOAT_TRUNCATE:
       case SQRT:
       case ABS:
       case NEG:
@@ -1893,7 +2047,7 @@ subst_stack_regs_pat (insn, regstack, pat)
        if (src1 == 0)
          src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
 
-       emit_swap_insn (insn, regstack, *src1, emit_insn_before);
+       emit_swap_insn (insn, regstack, *src1);
 
        src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
 
@@ -1931,26 +2085,22 @@ subst_stack_regs_pat (insn, regstack, pat)
        if (STACK_REG_P (*src1))
          src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
        else
-         src1_note = 0;
+         src1_note = NULL_RTX;
        if (STACK_REG_P (*src2))
          src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
        else
-         src2_note = 0;
+         src2_note = NULL_RTX;
 
        /* If either operand is not a stack register, then the dest
           must be top of stack. */
 
        if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2))
-         emit_swap_insn (insn, regstack, *dest, emit_insn_before);
+         emit_swap_insn (insn, regstack, *dest);
        else
          {
            /* Both operands are REG.  If neither operand is already
               at the top of stack, choose to make the one that is the dest
-              the new top of stack.
-
-              ??? A later optimization here would be to look forward
-              in the insns and see which source reg will be needed at top
-              of stack soonest. */
+              the new top of stack.  */
 
            int src1_hard_regnum, src2_hard_regnum;
 
@@ -1961,7 +2111,7 @@ subst_stack_regs_pat (insn, regstack, pat)
 
            if (src1_hard_regnum != FIRST_STACK_REG
                && src2_hard_regnum != FIRST_STACK_REG)
-             emit_swap_insn (insn, regstack, *dest, emit_insn_before);
+             emit_swap_insn (insn, regstack, *dest);
          }
 
        if (STACK_REG_P (*src1))
@@ -2029,6 +2179,38 @@ subst_stack_regs_pat (insn, regstack, pat)
 
        break;
 
+      case UNSPEC:
+       switch (XINT (SET_SRC (pat), 1))
+         {
+         case 1: /* sin */
+         case 2: /* cos */
+           /* These insns only operate on the top of the stack.  */
+
+           src1 = get_true_reg (&XVECEXP (SET_SRC (pat), 0, 0));
+
+           emit_swap_insn (insn, regstack, *src1);
+
+           src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+           if (STACK_REG_P (*dest))
+             replace_reg (dest, FIRST_STACK_REG);
+
+           if (src1_note)
+             {
+               replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+               regstack->top--;
+               CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
+             }
+
+           replace_reg (src1, FIRST_STACK_REG);
+
+           break;
+
+         default:
+           abort ();
+         }
+       break;
+
       default:
        abort ();
       }
@@ -2036,12 +2218,12 @@ subst_stack_regs_pat (insn, regstack, pat)
 \f
 /* Substitute hard regnums for any stack regs in INSN, which has
    N_INPUTS inputs and N_OUTPUTS outputs.  REGSTACK is the stack info
-   before the insn, and is updated with changes made here.  CONSTAINTS is
+   before the insn, and is updated with changes made here.  CONSTRAINTS is
    an array of the constraint strings used in the asm statement.
 
    OPERANDS is an array of the operands, and OPERANDS_LOC is a
    parallel array of where the operands were found.  The output operands
-   all preceed the input operands.
+   all precede the input operands.
 
    There are several requirements and assumptions about the use of
    stack-like regs in asm statements.  These rules are enforced by
@@ -2377,7 +2559,8 @@ subst_stack_regs (insn, regstack)
          char **constraints
            = (char **) alloca (n_operands * sizeof (char *));
 
-         decode_asm_operands (body, operands, operands_loc, constraints, 0);
+         decode_asm_operands (body, operands, operands_loc,
+                              constraints, NULL_PTR);
          get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);
          subst_asm_stack_regs (insn, regstack, operands, operands_loc,
                                constraints, n_inputs, n_outputs);
@@ -2385,7 +2568,7 @@ subst_stack_regs (insn, regstack)
        }
 
       if (GET_CODE (PATTERN (insn)) == PARALLEL)
-       for (i = 0; i < XVECLEN (PATTERN (insn) , 0); i++)
+       for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
          {
            if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i)))
              subst_stack_regs_pat (insn, regstack,
@@ -2499,8 +2682,7 @@ change_stack (insn, old, new, when)
                abort ();
 
              emit_swap_insn (insn, old,
-                             FP_mode_reg[old->reg[reg]][(int) DFmode],
-                             emit_insn_before);
+                             FP_mode_reg[old->reg[reg]][(int) DFmode]);
            }
 
          /* See if any regs remain incorrect.  If so, bring an
@@ -2511,8 +2693,7 @@ change_stack (insn, old, new, when)
            if (new->reg[reg] != old->reg[reg])
              {
                emit_swap_insn (insn, old,
-                               FP_mode_reg[old->reg[reg]][(int) DFmode],
-                               emit_insn_before);
+                               FP_mode_reg[old->reg[reg]][(int) DFmode]);
                break;
              }
        } while (reg >= 0);
@@ -2569,6 +2750,8 @@ goto_block_pat (insn, regstack, pat)
     abort ();
 
   /* First, see if in fact anything needs to be done to the stack at all. */
+  if (INSN_UID (label) <= 0)
+    return;
 
   label_stack = &block_stack_in[BLOCK_NUM (label)];
 
This page took 0.054079 seconds and 5 git commands to generate.