OSDN Git Service

* config/mips/predicates.md (splittable_const_int_operand): New,
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 16 Mar 2006 20:24:42 +0000 (20:24 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 16 Mar 2006 20:24:42 +0000 (20:24 +0000)
split from move_operand.
(splittable_symbolic_operand): New.
(move_operand): Add commentary.  Use splittable_const_int_operand.
Inline mips_atomic_symbolic_constant_p.
* config/mips/mips.md: Add combine splitters for handling moves
of splittable_const_int_operands and splittable_symbolic_operands.
* config/mips/mips-protos.h (mips_atomic_symbolic_constant_p): Delete.
(mips_split_symbol): Declare.
(mips_move_integer): Declare.
* config/mips/mips.c (mips_split_p): Make global.
(TARGET_MIN_ANCHOR_OFFSET): Override default.
(TARGET_MAX_ANCHOR_OFFSET): Likewise.
(TARGET_USE_BLOCKS_FOR_CONSTANT_P): Likewise.
(TARGET_USE_ANCHORS_FOR_SYMBOL_P): Likewise.
(mips_offset_within_object_p): Handle block symbols.
(mips_atomic_symbolic_constant_p): Delete.
(mips_cannot_force_const_mem): Return false for constants that
mips_legitimize_move can handle.
(mips_use_blocks_for_constant_p): New function.
(mips_split_symbol): Make global.
(mips_move_integer): Likewise.  Add a temporary register argument.
(mips_legitimize_const_move): Use splittable_const_int_operand and
splittable_symbolic_operand.
(mips_use_anchors_for_symbol_p): New function.
* config/mips/mips.h: Protect externs with !USED_FOR_TARGET.
(mips_split_p): Declare.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@112150 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/predicates.md

index 6e388d8..6175a87 100644 (file)
@@ -1,5 +1,35 @@
 2006-03-16  Richard Sandiford  <richard@codesourcery.com>
 
+       * config/mips/predicates.md (splittable_const_int_operand): New,
+       split from move_operand.
+       (splittable_symbolic_operand): New.
+       (move_operand): Add commentary.  Use splittable_const_int_operand.
+       Inline mips_atomic_symbolic_constant_p.
+       * config/mips/mips.md: Add combine splitters for handling moves
+       of splittable_const_int_operands and splittable_symbolic_operands.
+       * config/mips/mips-protos.h (mips_atomic_symbolic_constant_p): Delete.
+       (mips_split_symbol): Declare.
+       (mips_move_integer): Declare.
+       * config/mips/mips.c (mips_split_p): Make global.
+       (TARGET_MIN_ANCHOR_OFFSET): Override default.
+       (TARGET_MAX_ANCHOR_OFFSET): Likewise.
+       (TARGET_USE_BLOCKS_FOR_CONSTANT_P): Likewise.
+       (TARGET_USE_ANCHORS_FOR_SYMBOL_P): Likewise.
+       (mips_offset_within_object_p): Handle block symbols.
+       (mips_atomic_symbolic_constant_p): Delete.
+       (mips_cannot_force_const_mem): Return false for constants that
+       mips_legitimize_move can handle.
+       (mips_use_blocks_for_constant_p): New function.
+       (mips_split_symbol): Make global.
+       (mips_move_integer): Likewise.  Add a temporary register argument.
+       (mips_legitimize_const_move): Use splittable_const_int_operand and
+       splittable_symbolic_operand.
+       (mips_use_anchors_for_symbol_p): New function.
+       * config/mips/mips.h: Protect externs with !USED_FOR_TARGET.
+       (mips_split_p): Declare.  
+
+2006-03-16  Richard Sandiford  <richard@codesourcery.com>
+
        * config.gcc (mips64*-*-linux*): Keep existing tm_defines.
        (mips*-*-linux*): Likewise.
 
index 1dc31f5..b737375 100644 (file)
@@ -106,7 +106,6 @@ enum mips_symbol_type {
 #define NUM_SYMBOL_TYPES (SYMBOL_64_LOW + 1)
 
 extern bool mips_symbolic_constant_p (rtx, enum mips_symbol_type *);
-extern bool mips_atomic_symbolic_constant_p (rtx);
 extern int mips_regno_mode_ok_for_base_p (int, enum machine_mode, int);
 extern bool mips_stack_address_p (rtx, enum machine_mode);
 extern int mips_address_insns (rtx, enum machine_mode);
@@ -116,8 +115,10 @@ extern int mips_idiv_insns (void);
 extern int fp_register_operand (rtx, enum machine_mode);
 extern int lo_operand (rtx, enum machine_mode);
 extern bool mips_legitimate_address_p (enum machine_mode, rtx, int);
+extern rtx mips_split_symbol (rtx, rtx);
 extern rtx mips_unspec_address (rtx, enum mips_symbol_type);
 extern bool mips_legitimize_address (rtx *, enum machine_mode);
+extern void mips_move_integer (rtx, rtx, unsigned HOST_WIDE_INT);
 extern bool mips_legitimize_move (enum machine_mode, rtx, rtx);
 
 extern int m16_uimm3_b (rtx, enum machine_mode);
index 12394ca..f907c01 100644 (file)
@@ -274,10 +274,10 @@ static bool mips_symbolic_address_p (enum mips_symbol_type, enum machine_mode);
 static bool mips_classify_address (struct mips_address_info *, rtx,
                                   enum machine_mode, int);
 static bool mips_cannot_force_const_mem (rtx);
+static bool mips_use_blocks_for_constant_p (enum machine_mode, rtx);
 static int mips_symbol_insns (enum mips_symbol_type);
 static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx);
 static rtx mips_force_temporary (rtx, rtx);
-static rtx mips_split_symbol (rtx, rtx);
 static rtx mips_unspec_offset_high (rtx, rtx, rtx, enum mips_symbol_type);
 static rtx mips_add_offset (rtx, rtx, HOST_WIDE_INT);
 static unsigned int mips_build_shift (struct mips_integer_op *, HOST_WIDE_INT);
@@ -285,7 +285,6 @@ static unsigned int mips_build_lower (struct mips_integer_op *,
                                      unsigned HOST_WIDE_INT);
 static unsigned int mips_build_integer (struct mips_integer_op *,
                                        unsigned HOST_WIDE_INT);
-static void mips_move_integer (rtx, unsigned HOST_WIDE_INT);
 static void mips_legitimize_const_move (enum machine_mode, rtx, rtx);
 static int m16_check_op (rtx, int, int, int);
 static bool mips_rtx_costs (rtx, int, int, int *);
@@ -333,6 +332,7 @@ static section *mips_select_rtx_section (enum machine_mode, rtx,
                                         unsigned HOST_WIDE_INT);
 static section *mips_function_rodata_section (tree);
 static bool mips_in_small_data_p (tree);
+static bool mips_use_anchors_for_symbol_p (rtx);
 static int mips_fpr_return_fields (tree, tree *);
 static bool mips_return_in_msb (tree);
 static rtx mips_return_fpr_pair (enum machine_mode mode,
@@ -628,7 +628,7 @@ static GTY (()) int mips_output_filename_first_time = 1;
 
 /* mips_split_p[X] is true if symbols of type X can be split by
    mips_split_symbol().  */
-static bool mips_split_p[NUM_SYMBOL_TYPES];
+bool mips_split_p[NUM_SYMBOL_TYPES];
 
 /* mips_lo_relocs[X] is the relocation to use when a symbol of type X
    appears in a LO_SUM.  It can be null if such LO_SUMs aren't valid or
@@ -1162,6 +1162,15 @@ static struct mips_rtx_cost_data const mips_rtx_cost_data[PROCESSOR_MAX] =
 #undef TARGET_EXTRA_LIVE_ON_ENTRY
 #define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry
 
+#undef TARGET_MIN_ANCHOR_OFFSET
+#define TARGET_MIN_ANCHOR_OFFSET -32768
+#undef TARGET_MAX_ANCHOR_OFFSET
+#define TARGET_MAX_ANCHOR_OFFSET 32767
+#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
+#define TARGET_USE_BLOCKS_FOR_CONSTANT_P mips_use_blocks_for_constant_p
+#undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
+#define TARGET_USE_ANCHORS_FOR_SYMBOL_P mips_use_anchors_for_symbol_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */
@@ -1256,7 +1265,7 @@ mips_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
 
 
 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
-   to the same object as SYMBOL.  */
+   to the same object as SYMBOL, or to the same object_block.  */
 
 static bool
 mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
@@ -1274,6 +1283,13 @@ mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
       && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
     return true;
 
+  if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol)
+      && SYMBOL_REF_BLOCK (symbol)
+      && SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0
+      && ((unsigned HOST_WIDE_INT) offset + SYMBOL_REF_BLOCK_OFFSET (symbol)
+         < (unsigned HOST_WIDE_INT) SYMBOL_REF_BLOCK (symbol)->size))
+    return true;
+
   return false;
 }
 
@@ -1357,17 +1373,6 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
 }
 
 
-/* Return true if X is a symbolic constant whose value is not split
-   into separate relocations.  */
-
-bool
-mips_atomic_symbolic_constant_p (rtx x)
-{
-  enum mips_symbol_type type;
-  return mips_symbolic_constant_p (x, &type) && !mips_split_p[type];
-}
-
-
 /* This function is used to implement REG_MODE_OK_FOR_BASE_P.  */
 
 int
@@ -1542,10 +1547,42 @@ mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
 static bool
 mips_cannot_force_const_mem (rtx x)
 {
-  if (! TARGET_HAVE_TLS)
-    return false;
+  rtx base;
+  HOST_WIDE_INT offset;
+
+  if (!TARGET_MIPS16)
+    {
+      /* As an optimization, reject constants that mips_legitimize_move
+        can expand inline.
 
-  return for_each_rtx (&x, &mips_tls_symbol_ref_1, 0);
+        Suppose we have a multi-instruction sequence that loads constant C
+        into register R.  If R does not get allocated a hard register, and
+        R is used in an operand that allows both registers and memory
+        references, reload will consider forcing C into memory and using
+        one of the instruction's memory alternatives.  Returning false
+        here will force it to use an input reload instead.  */
+      if (GET_CODE (x) == CONST_INT)
+       return true;
+
+      mips_split_const (x, &base, &offset);
+      if (symbolic_operand (base, VOIDmode) && SMALL_OPERAND (offset))
+       return true;
+    }
+
+  if (TARGET_HAVE_TLS && for_each_rtx (&x, &mips_tls_symbol_ref_1, 0))
+    return true;
+
+  return false;
+}
+
+/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P.  MIPS16 uses per-function
+   constant pools, but normal-mode code doesn't need to.  */
+
+static bool
+mips_use_blocks_for_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                               rtx x ATTRIBUTE_UNUSED)
+{
+  return !TARGET_MIPS16;
 }
 \f
 /* Return the number of instructions needed to load a symbol of the
@@ -1845,7 +1882,7 @@ mips_force_temporary (rtx dest, rtx value)
 /* Return a LO_SUM expression for ADDR.  TEMP is as for mips_force_temporary
    and is used to load the high part into a register.  */
 
-static rtx
+rtx
 mips_split_symbol (rtx temp, rtx addr)
 {
   rtx high;
@@ -2175,10 +2212,10 @@ mips_build_integer (struct mips_integer_op *codes,
 }
 
 
-/* Move VALUE into register DEST.  */
+/* Load VALUE into DEST, using TEMP as a temporary register if need be.  */
 
-static void
-mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
+void
+mips_move_integer (rtx dest, rtx temp, unsigned HOST_WIDE_INT value)
 {
   struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
   enum machine_mode mode;
@@ -2194,7 +2231,10 @@ mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
   for (i = 1; i < cost; i++)
     {
       if (no_new_pseudos)
-       emit_move_insn (dest, x), x = dest;
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, temp, x));
+         x = temp;
+       }
       else
        x = force_reg (mode, x);
       x = gen_rtx_fmt_ee (codes[i].code, mode, x, GEN_INT (codes[i].value));
@@ -2213,30 +2253,24 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
 {
   rtx base;
   HOST_WIDE_INT offset;
-  enum mips_symbol_type symbol_type;
 
-  /* Split moves of big integers into smaller pieces.  In mips16 code,
-     it's better to force the constant into memory instead.  */
-  if (GET_CODE (src) == CONST_INT && !TARGET_MIPS16)
+  /* Split moves of big integers into smaller pieces.  */
+  if (splittable_const_int_operand (src, mode))
     {
-      mips_move_integer (dest, INTVAL (src));
+      mips_move_integer (dest, dest, INTVAL (src));
       return;
     }
 
-  if (mips_tls_operand_p (src))
+  /* Split moves of symbolic constants into high/low pairs.  */
+  if (splittable_symbolic_operand (src, mode))
     {
-      emit_move_insn (dest, mips_legitimize_tls_address (src));
+      emit_insn (gen_rtx_SET (VOIDmode, dest, mips_split_symbol (dest, src)));
       return;
     }
 
-  /* See if the symbol can be split.  For mips16, this is often worse than
-     forcing it in the constant pool since it needs the single-register form
-     of addiu or daddiu.  */
-  if (!TARGET_MIPS16
-      && mips_symbolic_constant_p (src, &symbol_type)
-      && mips_split_p[symbol_type])
+  if (mips_tls_operand_p (src))
     {
-      emit_move_insn (dest, mips_split_symbol (dest, src));
+      emit_move_insn (dest, mips_legitimize_tls_address (src));
       return;
     }
 
@@ -7205,6 +7239,25 @@ mips_in_small_data_p (tree decl)
   size = int_size_in_bytes (TREE_TYPE (decl));
   return (size > 0 && size <= mips_section_threshold);
 }
+
+/* Implement TARGET_USE_ANCHORS_FOR_SYMBOL_P.  We don't want to use
+   anchors for small data: the GP register acts as an anchor in that
+   case.  We also don't want to use them for PC-relative accesses,
+   where the PC acts as an anchor.  */
+
+static bool
+mips_use_anchors_for_symbol_p (rtx symbol)
+{
+  switch (mips_classify_symbol (symbol))
+    {
+    case SYMBOL_CONSTANT_POOL:
+    case SYMBOL_SMALL_DATA:
+      return false;
+
+    default:
+      return true;
+    }
+}
 \f
 /* See whether VALTYPE is a record whose fields should be returned in
    floating-point registers.  If so, return the number of fields and
index b0ae120..51d383c 100644 (file)
@@ -106,6 +106,7 @@ struct mips_cpu_info {
   int isa;
 };
 
+#ifndef USED_FOR_TARGET
 extern char mips_print_operand_punct[256]; /* print_operand punctuation chars */
 extern const char *current_function_file; /* filename current function is in */
 extern int num_source_filenames;       /* current .file # */
@@ -117,6 +118,7 @@ extern int set_noat;                        /* # of nested .set noat's  */
 extern int set_volatile;               /* # of nested .set volatile's  */
 extern int mips_branch_likely;         /* emit 'l' after br (branch likely) */
 extern int mips_dbx_regno[];           /* Map register # to debug register # */
+extern bool mips_split_p[];
 extern GTY(()) rtx cmp_operands[2];
 extern enum processor_type mips_arch;   /* which cpu to codegen for */
 extern enum processor_type mips_tune;   /* which cpu to schedule for */
@@ -127,6 +129,7 @@ extern const struct mips_cpu_info mips_cpu_info_table[];
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
 extern const struct mips_rtx_cost_data *mips_cost;
+#endif
 
 /* Macros to silence warnings about numbers being signed in traditional
    C and unsigned in ISO C when compiled on 32-bit hosts.  */
index cc327f9..ce2cce6 100644 (file)
    (set_attr "mode" "<MODE>")
    (set_attr "length" "8")])
 
+;; Allow combine to split complex const_int load sequences, using operand 2
+;; to store the intermediate results.  See move_operand for details.
+(define_split
+  [(set (match_operand:GPR 0 "register_operand")
+       (match_operand:GPR 1 "splittable_const_int_operand"))
+   (clobber (match_operand:GPR 2 "register_operand"))]
+  ""
+  [(const_int 0)]
+{
+  mips_move_integer (operands[0], operands[2], INTVAL (operands[1]));
+  DONE;
+})
+
+;; Likewise, for symbolic operands.
+(define_split
+  [(set (match_operand:P 0 "register_operand")
+       (match_operand:P 1 "splittable_symbolic_operand"))
+   (clobber (match_operand:P 2 "register_operand"))]
+  ""
+  [(set (match_dup 0) (match_dup 1))]
+  { operands[1] = mips_split_symbol (operands[2], operands[1]); })
+
 ;; 64-bit integer moves
 
 ;; Unlike most other insns, the move insns can't be split with
index d93621d..23e85d8 100644 (file)
   (ior (match_operand 0 "const_call_insn_operand")
        (match_operand 0 "register_operand")))
 
+;; A legitimate CONST_INT operand that takes more than one instruction
+;; to load.
+(define_predicate "splittable_const_int_operand"
+  (match_code "const_int")
+{
+  /* When generating mips16 code, LEGITIMATE_CONSTANT_P rejects
+     CONST_INTs that can't be loaded using simple insns.  */
+  if (TARGET_MIPS16)
+    return false;
+
+  /* Don't handle multi-word moves this way; we don't want to introduce
+     the individual word-mode moves until after reload.  */
+  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+    return false;
+
+  /* Otherwise check whether the constant can be loaded in a single
+     instruction.  */
+  return !LUI_INT (op) && !SMALL_INT (op) && !SMALL_INT_UNSIGNED (op);
+})
+
+;; A legitimate symbolic operand that takes more than one instruction
+;; to load.
+(define_predicate "splittable_symbolic_operand"
+  (match_code "const,symbol_ref,label_ref")
+{
+  enum mips_symbol_type symbol_type;
+  return (mips_symbolic_constant_p (op, &symbol_type)
+         && mips_split_p[symbol_type]);
+})
+
 (define_predicate "move_operand"
   (match_operand 0 "general_operand")
 {
+  enum mips_symbol_type symbol_type;
+
+  /* The thinking here is as follows:
+
+     (1) The move expanders should split complex load sequences into
+        individual instructions.  Those individual instructions can
+        then be optimized by all rtl passes.
+
+     (2) The target of pre-reload load sequences should not be used
+        to store temporary results.  If the target register is only
+        assigned one value, reload can rematerialize that value
+        on demand, rather than spill it to the stack.
+
+     (3) If we allowed pre-reload passes like combine and cse to recreate
+        complex load sequences, we would want to be able to split the
+        sequences before reload as well, so that the pre-reload scheduler
+        can see the individual instructions.  This falls foul of (2);
+        the splitter would be forced to reuse the target register for
+        intermediate results.
+
+     (4) We want to define complex load splitters for combine.  These
+        splitters can request a temporary scratch register, which avoids
+        the problem in (2).  They allow things like:
+
+             (set (reg T1) (high SYM))
+             (set (reg T2) (low (reg T1) SYM))
+             (set (reg X) (plus (reg T2) (const_int OFFSET)))
+
+        to be combined into:
+
+             (set (reg T3) (high SYM+OFFSET))
+             (set (reg X) (lo_sum (reg T3) SYM+OFFSET))
+
+        if T2 is only used this once.  */
   switch (GET_CODE (op))
     {
     case CONST_INT:
-      /* When generating mips16 code, LEGITIMATE_CONSTANT_P rejects
-        CONST_INTs that can't be loaded using simple insns.  */
-      if (TARGET_MIPS16)
-       return true;
-
-      /* When generating 32-bit code, allow DImode move_operands to
-        match arbitrary constants.  We split them after reload.  */
-      if (!TARGET_64BIT && mode == DImode)
-       return true;
-
-      /* Otherwise check whether the constant can be loaded in a single
-        instruction.  */
-      return LUI_INT (op) || SMALL_INT (op) || SMALL_INT_UNSIGNED (op);
+      return !splittable_const_int_operand (op, mode);
 
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
-      return CONST_GP_P (op) || mips_atomic_symbolic_constant_p (op);
+      if (CONST_GP_P (op))
+       return true;
+      return (mips_symbolic_constant_p (op, &symbol_type)
+             && !mips_split_p[symbol_type]);
 
     default:
       return true;