OSDN Git Service

* i386.c (incdec_operand): Accept only 1 and -1.
[pf3gnuchains/gcc-fork.git] / gcc / reg-stack.c
index 2edd579..2bf0fe7 100644 (file)
@@ -1,5 +1,6 @@
 /* Register to Stack convert for GNU compiler.
-   Copyright (C) 1992, 93-99, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
    This file is part of GNU CC.
 
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
-#include "insn-flags.h"
 #include "toplev.h"
 #include "recog.h"
 #include "output.h"
 #include "basic-block.h"
 #include "varray.h"
+#include "reload.h"
 
 #ifdef STACK_REGS
 
@@ -184,7 +185,7 @@ typedef struct stack_def
 {
   int top;                     /* index to top stack element */
   HARD_REG_SET reg_set;                /* set of live registers */
-  char reg[REG_STACK_SIZE];    /* register - stack mapping */
+  unsigned char reg[REG_STACK_SIZE];/* register - stack mapping */
 } *stack;
 
 /* This is used to carry information about basic blocks.  It is 
@@ -238,7 +239,8 @@ static int check_asm_stack_operands PARAMS ((rtx));
 static int get_asm_operand_n_inputs    PARAMS ((rtx));
 static rtx stack_result                        PARAMS ((tree));
 static void replace_reg                        PARAMS ((rtx *, int));
-static void remove_regno_note          PARAMS ((rtx, enum reg_note, int));
+static void remove_regno_note          PARAMS ((rtx, enum reg_note,
+                                                unsigned int));
 static int get_hard_regnum             PARAMS ((stack, rtx));
 static void delete_insn_for_stacker    PARAMS ((rtx));
 static rtx emit_pop_insn               PARAMS ((rtx, stack, rtx,
@@ -259,6 +261,8 @@ static int convert_regs_1           PARAMS ((FILE *, basic_block));
 static int convert_regs_2              PARAMS ((FILE *, basic_block));
 static int convert_regs                        PARAMS ((FILE *));
 static void print_stack                PARAMS ((FILE *, stack));
+static rtx next_flags_user             PARAMS ((rtx));
+static void record_label_references    PARAMS ((rtx, rtx));
 \f
 /* Return non-zero if any stack register is mentioned somewhere within PAT.  */
 
@@ -299,7 +303,7 @@ stack_regs_mentioned (insn)
   unsigned int uid, max;
   int test;
 
-  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+  if (! INSN_P (insn))
     return 0;
 
   uid = INSN_UID (insn);
@@ -331,23 +335,18 @@ next_flags_user (insn)
 {
   /* Search forward looking for the first use of this value. 
      Stop at block boundaries.  */
-  /* ??? This really cries for BLOCK_END!  */
 
-  while (1)
+  while (insn != current_block->end)
     {
       insn = NEXT_INSN (insn);
-      if (!insn)
-       return NULL_RTX;
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-          && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
+      if (INSN_P (insn) && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
         return insn;
 
-      if (GET_CODE (insn) == JUMP_INSN
-         || GET_CODE (insn) == CODE_LABEL
-         || GET_CODE (insn) == CALL_INSN)
+      if (GET_CODE (insn) == CALL_INSN)
        return NULL_RTX;
     }
+  return NULL_RTX;
 }
 \f
 /* Reorganise the stack into ascending numbers,
@@ -430,9 +429,9 @@ reg_to_stack (first, file)
 
   /* Ok, floating point instructions exist.  If not optimizing, 
      build the CFG and run life analysis.  */
-  find_basic_blocks (first, max_reg_num (), file, 0);
+  find_basic_blocks (first, max_reg_num (), file);
   count_or_remove_death_notes (NULL, 1);
-  life_analysis (first, max_reg_num (), file, 0);
+  life_analysis (first, file, PROP_DEATH_NOTES);
 
   /* Set up block info for each basic block.  */
   bi = (block_info) xcalloc ((n_basic_blocks + 1), sizeof (*bi));
@@ -559,7 +558,11 @@ get_true_reg (pat)
          rtx subreg;
          if (FP_REG_P (subreg = SUBREG_REG (*pat)))
            {
-             *pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat),
+             int regno_off = subreg_regno_offset (REGNO (subreg),
+                                                  GET_MODE (subreg),
+                                                  SUBREG_BYTE (*pat),
+                                                  GET_MODE (*pat));
+             *pat = FP_MODE_REG (REGNO (subreg) + regno_off,
                                  GET_MODE (subreg));
            default:
              return pat;
@@ -659,7 +662,20 @@ check_asm_stack_operands (insn)
            malformed_asm = 1;
          }
         else
-         reg_used_as_output[REGNO (recog_data.operand[i])] = 1;
+         {
+           int j;
+
+           for (j = 0; j < n_clobbers; j++)
+             if (REGNO (recog_data.operand[i]) == REGNO (clobber_reg[j]))
+               {
+                 error_for_asm (insn, "Output constraint %d cannot be specified together with \"%s\" clobber",
+                                i, reg_names [REGNO (clobber_reg[j])]);
+                 malformed_asm = 1;
+                 break;
+               }
+           if (j == n_clobbers)
+             reg_used_as_output[REGNO (recog_data.operand[i])] = 1;
+         }
       }
 
 
@@ -786,12 +802,8 @@ stack_result (decl)
   if (aggregate_value_p (DECL_RESULT (decl)))
     return 0;
 
-  result = DECL_RTL (DECL_RESULT (decl));
-  /* ?!?  What is this code supposed to do?  Can this code actually
-     trigger if we kick out aggregates above?  */
-  if (result != 0
-      && ! (GET_CODE (result) == REG
-           && REGNO (result) < FIRST_PSEUDO_REGISTER))
+  result = DECL_RTL_IF_SET (DECL_RESULT (decl));
+  if (result != 0)
     {
 #ifdef FUNCTION_OUTGOING_VALUE
       result
@@ -839,7 +851,7 @@ static void
 remove_regno_note (insn, note, regno)
      rtx insn;
      enum reg_note note;
-     int regno;
+     unsigned int regno;
 {
   register rtx *note_link, this;
 
@@ -908,6 +920,23 @@ emit_pop_insn (insn, regstack, reg, where)
   rtx pop_insn, pop_rtx;
   int hard_regno;
 
+  /* For complex types take care to pop both halves.  These may survive in
+     CLOBBER and USE expressions.  */
+  if (COMPLEX_MODE_P (GET_MODE (reg)))
+    {
+      rtx reg1 = FP_MODE_REG (REGNO (reg), DFmode);
+      rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, DFmode);
+
+      pop_insn = NULL_RTX;
+      if (get_hard_regnum (regstack, reg1) >= 0)
+         pop_insn = emit_pop_insn (insn, regstack, reg1, where);
+      if (get_hard_regnum (regstack, reg2) >= 0)
+         pop_insn = emit_pop_insn (insn, regstack, reg2, where);
+      if (!pop_insn)
+       abort ();
+      return pop_insn;
+    }
+
   hard_regno = get_hard_regnum (regstack, reg);
 
   if (hard_regno < FIRST_STACK_REG)
@@ -971,11 +1000,12 @@ emit_swap_insn (insn, regstack, reg)
   if (current_block && insn != current_block->head)
     {
       rtx tmp = PREV_INSN (insn);
-      while (tmp != current_block->head)
+      rtx limit = PREV_INSN (current_block->head);
+      while (tmp != limit)
        {
          if (GET_CODE (tmp) == CODE_LABEL
-             || (GET_CODE (tmp) == NOTE
-                 && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BASIC_BLOCK)
+             || GET_CODE (tmp) == CALL_INSN
+             || NOTE_INSN_BASIC_BLOCK_P (tmp)
              || (GET_CODE (tmp) == INSN
                  && stack_regs_mentioned (tmp)))
            {
@@ -1015,10 +1045,7 @@ emit_swap_insn (insn, regstack, reg)
   if (i1)
     emit_block_insn_after (swap_rtx, i1, current_block);
   else if (current_block)
-    {
-      i1 = emit_insn_before (swap_rtx, current_block->head);
-      current_block->head = i1;
-    }
+    emit_block_insn_before (swap_rtx, current_block->head, current_block);
   else
     emit_insn_before (swap_rtx, insn);
 }
@@ -1123,7 +1150,8 @@ 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 - 1)
+      else if ((GET_MODE (src) == XFmode || GET_MODE (src) == TFmode)
+              && regstack->top < REG_STACK_SIZE - 1)
        {
          /* A 387 cannot write an XFmode value to a MEM without
             clobbering the source reg.  The output code can handle
@@ -1133,9 +1161,12 @@ move_for_stack_reg (insn, regstack, pat)
             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, XFmode);
+         rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, GET_MODE (src));
 
-         push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
+         if (GET_MODE (src) == TFmode)
+           push_rtx = gen_movtf (top_stack_reg, top_stack_reg);
+         else
+           push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
          push_insn = emit_insn_before (push_rtx, insn);
          REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, top_stack_reg,
                                                REG_NOTES (insn));
@@ -1231,18 +1262,12 @@ swap_rtx_condition (insn)
 
       /* Search forward looking for the first use of this value. 
         Stop at block boundaries.  */
-      /* ??? This really cries for BLOCK_END!  */
-      while (1)
+      while (insn != current_block->end)
        {
          insn = NEXT_INSN (insn);
-         if (insn == NULL_RTX)
-           return 0;
-         if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-             && reg_mentioned_p (dest, insn))
+         if (INSN_P (insn) && reg_mentioned_p (dest, insn))
            break;
-         if (GET_CODE (insn) == JUMP_INSN)
-           return 0;
-         if (GET_CODE (insn) == CODE_LABEL)
+         if (GET_CODE (insn) == CALL_INSN)
            return 0;
        }
 
@@ -1263,7 +1288,28 @@ swap_rtx_condition (insn)
       pat = PATTERN (insn);
     }
 
-  return swap_rtx_condition_1 (pat);
+  if (swap_rtx_condition_1 (pat))
+    {
+      int fail = 0;
+      INSN_CODE (insn) = -1;
+      if (recog_memoized (insn) == -1)
+       fail = 1;
+      /* In case the flags don't die here, recurse to try fix
+         following user too.  */
+      else if (! dead_or_set_p (insn, ix86_flags_rtx))
+       {
+         insn = next_flags_user (insn);
+         if (!insn || !swap_rtx_condition (insn))
+           fail = 1;
+       }
+      if (fail)
+       {
+         swap_rtx_condition_1 (pat);
+         return 0;
+       }
+      return 1;
+    }
+  return 0;
 }
 
 /* Handle a comparison.  Special care needs to be taken to avoid
@@ -1436,6 +1482,15 @@ subst_stack_regs_pat (insn, regstack, pat)
                    PATTERN (insn) = pat;
                    move_for_stack_reg (insn, regstack, pat);
                  }
+               if (! note && COMPLEX_MODE_P (GET_MODE (*dest))
+                   && get_hard_regnum (regstack, FP_MODE_REG (REGNO (*dest), DFmode)) == -1)
+                 {
+                   pat = gen_rtx_SET (VOIDmode,
+                                      FP_MODE_REG (REGNO (*dest) + 1, SFmode),
+                                      nan);
+                   PATTERN (insn) = pat;
+                   move_for_stack_reg (insn, regstack, pat);
+                 }
              }
          }
        break;
@@ -1443,7 +1498,7 @@ subst_stack_regs_pat (insn, regstack, pat)
 
     case SET:
       {
-       rtx *src1 = (rtx *) NULL_PTR, *src2;
+       rtx *src1 = (rtx *) 0, *src2;
        rtx src1_note, src2_note;
        rtx pat_src;
 
@@ -1637,9 +1692,9 @@ subst_stack_regs_pat (insn, regstack, pat)
                && REG_P (*src1) && REG_P (*src2)
                && REGNO (*src1) != REGNO (*dest))
             {
-               rtx tmp = *src1;
-               *src1 = *src2;
-               *src2 = tmp;
+               int tmp = REGNO (*src1);
+               replace_reg (src1, REGNO (*src2));
+               replace_reg (src2, tmp);
             }
            break;
 
@@ -2546,10 +2601,15 @@ convert_regs_1 (file, block)
            }
        }
 
-      /* Care for EH edges specially.  The normal return path may return
-        a value in st(0), but the EH path will not, and there's no need
-        to add popping code to the edge.  */
-      if (e->flags & EDGE_EH)
+      /* Care for non-call EH edges specially.  The normal return path have
+        values in registers.  These will be popped en masse by the unwind
+        library.  */
+      if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
+       target_stack->top = -1;
+
+      /* Other calls may appear to have values live in st(0), but the
+        abnormal return path will not have actually loaded the values.  */
+      else if (e->flags & EDGE_ABNORMAL_CALL)
        {
          /* Assert that the lifetimes are as we expect -- one value
             live at st(0) on the end of the source block, and no