Add -march=interaptiv.
[platform/upstream/gcc.git] / gcc / reginfo.c
index 9fba9c3..9e855c2 100644 (file)
@@ -1,7 +1,5 @@
 /* Compute different info about registers.
-   Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
-   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009, 2010, 2011  Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -30,31 +28,45 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "hard-reg-set.h"
+#include "backend.h"
+#include "tree.h"
 #include "rtl.h"
+#include "df.h"
+#include "alias.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "tm_p.h"
-#include "flags.h"
-#include "basic-block.h"
 #include "regs.h"
 #include "addresses.h"
-#include "function.h"
-#include "insn-config.h"
 #include "recog.h"
 #include "reload.h"
 #include "diagnostic-core.h"
 #include "output.h"
-#include "hashtab.h"
 #include "target.h"
 #include "tree-pass.h"
-#include "df.h"
 #include "ira.h"
 
 /* Maximum register number used in this function, plus one.  */
 
 int max_regno;
 
+/* Used to cache the results of simplifiable_subregs.  SHAPE is the input
+   parameter and SIMPLIFIABLE_REGS is the result.  */
+struct simplifiable_subreg
+{
+  simplifiable_subreg (const subreg_shape &);
+
+  subreg_shape shape;
+  HARD_REG_SET simplifiable_regs;
+};
 \f
 struct target_hard_regs default_target_hard_regs;
 struct target_regs default_target_regs;
@@ -87,7 +99,7 @@ static const char initial_call_really_used_regs[] = CALL_REALLY_USED_REGISTERS;
 char global_regs[FIRST_PSEUDO_REGISTER];
 
 /* Declaration for the global register. */
-static tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER];
+tree global_regs_decl[FIRST_PSEUDO_REGISTER];
 
 /* Same information as REGS_INVALIDATED_BY_CALL but in regset form to be used
    in dataflow more conveniently.  */
@@ -254,7 +266,7 @@ static void
 init_reg_sets_1 (void)
 {
   unsigned int i, j;
-  unsigned int /* enum machine_mode */ m;
+  unsigned int /* machine_mode */ m;
 
   restore_register_info ();
 
@@ -431,14 +443,12 @@ init_reg_sets_1 (void)
        }
       else if (i == FRAME_POINTER_REGNUM)
        ;
-#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
-      else if (i == HARD_FRAME_POINTER_REGNUM)
+      else if (!HARD_FRAME_POINTER_IS_FRAME_POINTER
+              && i == HARD_FRAME_POINTER_REGNUM)
        ;
-#endif
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
-      else if (i == ARG_POINTER_REGNUM && fixed_regs[i])
+      else if (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+              && i == ARG_POINTER_REGNUM && fixed_regs[i])
        ;
-#endif
       else if (!PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
               && i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
        ;
@@ -449,7 +459,7 @@ init_reg_sets_1 (void)
         }
     }
 
-  COPY_HARD_REG_SET(call_fixed_reg_set, fixed_reg_set);
+  COPY_HARD_REG_SET (call_fixed_reg_set, fixed_reg_set);
 
   /* Preserve global registers if called more than once.  */
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -470,11 +480,11 @@ init_reg_sets_1 (void)
       HARD_REG_SET ok_regs;
       CLEAR_HARD_REG_SET (ok_regs);
       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
-       if (!fixed_regs [j] && HARD_REGNO_MODE_OK (j, (enum machine_mode) m))
+       if (!fixed_regs [j] && HARD_REGNO_MODE_OK (j, (machine_mode) m))
          SET_HARD_REG_BIT (ok_regs, j);
 
       for (i = 0; i < N_REG_CLASSES; i++)
-       if ((targetm.class_max_nregs ((reg_class_t) i, (enum machine_mode) m)
+       if ((targetm.class_max_nregs ((reg_class_t) i, (machine_mode) m)
             <= reg_class_size[i])
            && hard_reg_set_intersect_p (ok_regs, reg_class_contents[i]))
          {
@@ -497,7 +507,7 @@ init_reg_modes_target (void)
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     for (j = 0; j < MAX_MACHINE_MODE; j++)
-      hard_regno_nregs[i][j] = HARD_REGNO_NREGS(i, (enum machine_mode)j);
+      hard_regno_nregs[i][j] = HARD_REGNO_NREGS (i, (machine_mode)j);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
@@ -534,7 +544,11 @@ reinit_regs (void)
   init_regs ();
   /* caller_save needs to be re-initialized.  */
   caller_save_initialized_p = false;
-  ira_init ();
+  if (this_target_rtl->target_specific_initialized)
+    {
+      ira_init ();
+      recog_init ();
+    }
 }
 
 /* Initialize some fake stack-frame MEM references for use in
@@ -545,7 +559,7 @@ init_fake_stack_mems (void)
   int i;
 
   for (i = 0; i < MAX_MACHINE_MODE; i++)
-    top_of_stack[i] = gen_rtx_MEM ((enum machine_mode) i, stack_pointer_rtx);
+    top_of_stack[i] = gen_rtx_MEM ((machine_mode) i, stack_pointer_rtx);
 }
 
 
@@ -553,7 +567,7 @@ init_fake_stack_mems (void)
    TO, using MODE.  */
 
 int
-register_move_cost (enum machine_mode mode, reg_class_t from, reg_class_t to)
+register_move_cost (machine_mode mode, reg_class_t from, reg_class_t to)
 {
   return targetm.register_move_cost (mode, from, to);
 }
@@ -561,7 +575,7 @@ register_move_cost (enum machine_mode mode, reg_class_t from, reg_class_t to)
 /* Compute cost of moving registers to/from memory.  */
 
 int
-memory_move_cost (enum machine_mode mode, reg_class_t rclass, bool in)
+memory_move_cost (machine_mode mode, reg_class_t rclass, bool in)
 {
   return targetm.memory_move_cost (mode, rclass, in);
 }
@@ -569,7 +583,7 @@ memory_move_cost (enum machine_mode mode, reg_class_t rclass, bool in)
 /* Compute extra cost of moving registers to/from memory due to reloads.
    Only needed if secondary reloads are required for memory moves.  */
 int
-memory_move_secondary_cost (enum machine_mode mode, reg_class_t rclass,
+memory_move_secondary_cost (machine_mode mode, reg_class_t rclass,
                            bool in)
 {
   reg_class_t altclass;
@@ -606,12 +620,12 @@ memory_move_secondary_cost (enum machine_mode mode, reg_class_t rclass,
 /* Return a machine mode that is legitimate for hard reg REGNO and large
    enough to save nregs.  If we can't find one, return VOIDmode.
    If CALL_SAVED is true, only consider modes that are call saved.  */
-enum machine_mode
+machine_mode
 choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
                      unsigned int nregs, bool call_saved)
 {
-  unsigned int /* enum machine_mode */ m;
-  enum machine_mode found_mode = VOIDmode, mode;
+  unsigned int /* machine_mode */ m;
+  machine_mode found_mode = VOIDmode, mode;
 
   /* We first look for the largest integer mode that can be validly
      held in REGNO.  If none, we look for the largest floating-point mode.
@@ -622,40 +636,35 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
        && HARD_REGNO_MODE_OK (regno, mode)
-       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+       && GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
-  if (found_mode != VOIDmode)
-    return found_mode;
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
        && HARD_REGNO_MODE_OK (regno, mode)
-       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+       && GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
-  if (found_mode != VOIDmode)
-    return found_mode;
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
        && HARD_REGNO_MODE_OK (regno, mode)
-       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+       && GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
-  if (found_mode != VOIDmode)
-    return found_mode;
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
        && HARD_REGNO_MODE_OK (regno, mode)
-       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+       && GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
   if (found_mode != VOIDmode)
@@ -664,7 +673,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
   /* Iterate over all of the CCmodes.  */
   for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m)
     {
-      mode = (enum machine_mode) m;
+      mode = (machine_mode) m;
       if ((unsigned) hard_regno_nregs[regno][mode] == nregs
          && HARD_REGNO_MODE_OK (regno, mode)
          && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
@@ -967,26 +976,41 @@ reginfo_init (void)
   return 1;
 }
 
-struct rtl_opt_pass pass_reginfo_init =
+namespace {
+
+const pass_data pass_data_reginfo_init =
 {
- {
-  RTL_PASS,
-  "reginfo",                            /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  NULL,                                 /* gate */
-  reginfo_init,                         /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "reginfo", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_reginfo_init : public rtl_opt_pass
+{
+public:
+  pass_reginfo_init (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_reginfo_init, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *) { return reginfo_init (); }
+
+}; // class pass_reginfo_init
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_reginfo_init (gcc::context *ctxt)
+{
+  return new pass_reginfo_init (ctxt);
+}
+
 \f
 
 /* Set up preferred, alternate, and allocno classes for REGNO as
@@ -1009,12 +1033,12 @@ setup_reg_classes (int regno,
    again just before loop.  It finds the first and last use of each
    pseudo-register.  */
 
-static void reg_scan_mark_refs (rtx, rtx);
+static void reg_scan_mark_refs (rtx, rtx_insn *);
 
 void
-reg_scan (rtx f, unsigned int nregs ATTRIBUTE_UNUSED)
+reg_scan (rtx_insn *f, unsigned int nregs ATTRIBUTE_UNUSED)
 {
-  rtx insn;
+  rtx_insn *insn;
 
   timevar_push (TV_REG_SCAN);
 
@@ -1035,7 +1059,7 @@ reg_scan (rtx f, unsigned int nregs ATTRIBUTE_UNUSED)
    We should only record information for REGs with numbers
    greater than or equal to MIN_REGNO.  */
 static void
-reg_scan_mark_refs (rtx x, rtx insn)
+reg_scan_mark_refs (rtx x, rtx_insn *insn)
 {
   enum rtx_code code;
   rtx dest;
@@ -1065,6 +1089,7 @@ reg_scan_mark_refs (rtx x, rtx insn)
       break;
 
     case INSN_LIST:
+    case INT_LIST:
       if (XEXP (x, 1))
        reg_scan_mark_refs (XEXP (x, 1), insn);
       break;
@@ -1078,7 +1103,7 @@ reg_scan_mark_refs (rtx x, rtx insn)
       /* Count a set of the destination if it is a register.  */
       for (dest = SET_DEST (x);
           GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
-          || GET_CODE (dest) == ZERO_EXTEND;
+          || GET_CODE (dest) == ZERO_EXTRACT;
           dest = XEXP (dest, 0))
        ;
 
@@ -1179,64 +1204,102 @@ reg_classes_intersect_p (reg_class_t c1, reg_class_t c2)
 }
 
 \f
+inline hashval_t
+simplifiable_subregs_hasher::hash (const simplifiable_subreg *value)
+{
+  return value->shape.unique_id ();
+}
+
+inline bool
+simplifiable_subregs_hasher::equal (const simplifiable_subreg *value,
+                                   const subreg_shape *compare)
+{
+  return value->shape == *compare;
+}
+
+inline simplifiable_subreg::simplifiable_subreg (const subreg_shape &shape_in)
+  : shape (shape_in)
+{
+  CLEAR_HARD_REG_SET (simplifiable_regs);
+}
+
+/* Return the set of hard registers that are able to form the subreg
+   described by SHAPE.  */
+
+const HARD_REG_SET &
+simplifiable_subregs (const subreg_shape &shape)
+{
+  if (!this_target_hard_regs->x_simplifiable_subregs)
+    this_target_hard_regs->x_simplifiable_subregs
+      = new hash_table <simplifiable_subregs_hasher> (30);
+  simplifiable_subreg **slot
+    = (this_target_hard_regs->x_simplifiable_subregs
+       ->find_slot_with_hash (&shape, shape.unique_id (), INSERT));
+
+  if (!*slot)
+    {
+      simplifiable_subreg *info = new simplifiable_subreg (shape);
+      for (unsigned int i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+       if (HARD_REGNO_MODE_OK (i, shape.inner_mode)
+           && simplify_subreg_regno (i, shape.inner_mode, shape.offset,
+                                     shape.outer_mode) >= 0)
+         SET_HARD_REG_BIT (info->simplifiable_regs, i);
+      *slot = info;
+    }
+  return (*slot)->simplifiable_regs;
+}
 
 /* Passes for keeping and updating info about modes of registers
    inside subregisters.  */
 
-#ifdef CANNOT_CHANGE_MODE_CLASS
-
-static bitmap invalid_mode_changes;
+static HARD_REG_SET **valid_mode_changes;
+static obstack valid_mode_changes_obstack;
 
 static void
-record_subregs_of_mode (rtx subreg, bitmap subregs_of_mode)
+record_subregs_of_mode (rtx subreg)
 {
-  enum machine_mode mode;
   unsigned int regno;
 
   if (!REG_P (SUBREG_REG (subreg)))
     return;
 
   regno = REGNO (SUBREG_REG (subreg));
-  mode = GET_MODE (subreg);
-
   if (regno < FIRST_PSEUDO_REGISTER)
     return;
 
-  if (bitmap_set_bit (subregs_of_mode,
-                     regno * NUM_MACHINE_MODES + (unsigned int) mode))
+  if (valid_mode_changes[regno])
+    AND_HARD_REG_SET (*valid_mode_changes[regno],
+                     simplifiable_subregs (shape_of_subreg (subreg)));
+  else
     {
-      unsigned int rclass;
-      for (rclass = 0; rclass < N_REG_CLASSES; rclass++)
-       if (!bitmap_bit_p (invalid_mode_changes,
-                          regno * N_REG_CLASSES + rclass)
-           && CANNOT_CHANGE_MODE_CLASS (PSEUDO_REGNO_MODE (regno),
-                                        mode, (enum reg_class) rclass))
-         bitmap_set_bit (invalid_mode_changes,
-                         regno * N_REG_CLASSES + rclass);
+      valid_mode_changes[regno]
+       = XOBNEW (&valid_mode_changes_obstack, HARD_REG_SET);
+      COPY_HARD_REG_SET (*valid_mode_changes[regno],
+                        simplifiable_subregs (shape_of_subreg (subreg)));
     }
 }
 
 /* Call record_subregs_of_mode for all the subregs in X.  */
 static void
-find_subregs_of_mode (rtx x, bitmap subregs_of_mode)
+find_subregs_of_mode (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
   const char * const fmt = GET_RTX_FORMAT (code);
   int i;
 
   if (code == SUBREG)
-    record_subregs_of_mode (x, subregs_of_mode);
+    record_subregs_of_mode (x);
 
   /* Time for some deep diving.  */
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       find_subregs_of_mode (XEXP (x, i), subregs_of_mode);
+       find_subregs_of_mode (XEXP (x, i));
       else if (fmt[i] == 'E')
        {
          int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           find_subregs_of_mode (XVECEXP (x, i, j), subregs_of_mode);
+           find_subregs_of_mode (XVECEXP (x, i, j));
        }
     }
 }
@@ -1245,47 +1308,35 @@ void
 init_subregs_of_mode (void)
 {
   basic_block bb;
-  rtx insn;
-  bitmap_obstack srom_obstack;
-  bitmap subregs_of_mode;
+  rtx_insn *insn;
 
-  gcc_assert (invalid_mode_changes == NULL);
-  invalid_mode_changes = BITMAP_ALLOC (NULL);
-  bitmap_obstack_initialize (&srom_obstack);
-  subregs_of_mode = BITMAP_ALLOC (&srom_obstack);
+  gcc_obstack_init (&valid_mode_changes_obstack);
+  valid_mode_changes = XCNEWVEC (HARD_REG_SET *, max_reg_num ());
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     FOR_BB_INSNS (bb, insn)
       if (NONDEBUG_INSN_P (insn))
-        find_subregs_of_mode (PATTERN (insn), subregs_of_mode);
-
-  BITMAP_FREE (subregs_of_mode);
-  bitmap_obstack_release (&srom_obstack);
+        find_subregs_of_mode (PATTERN (insn));
 }
 
-/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
-   mode.  */
-bool
-invalid_mode_change_p (unsigned int regno,
-                      enum reg_class rclass)
+const HARD_REG_SET *
+valid_mode_changes_for_regno (unsigned int regno)
 {
-  return bitmap_bit_p (invalid_mode_changes,
-                      regno * N_REG_CLASSES + (unsigned) rclass);
+  return valid_mode_changes[regno];
 }
 
 void
 finish_subregs_of_mode (void)
 {
-  BITMAP_FREE (invalid_mode_changes);
-}
-#else
-void
-init_subregs_of_mode (void)
-{
+  XDELETEVEC (valid_mode_changes);
+  obstack_free (&valid_mode_changes_obstack, NULL);
 }
+
+/* Free all data attached to the structure.  This isn't a destructor because
+   we don't want to run on exit.  */
+
 void
-finish_subregs_of_mode (void)
+target_hard_regs::finalize ()
 {
+  delete x_simplifiable_subregs;
 }
-
-#endif /* CANNOT_CHANGE_MODE_CLASS */