aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard@codesourcery.com>2006-03-16 20:24:42 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2006-03-16 20:24:42 +0000
commitea462dd06fa40bc09069b7d9f72951708a3700a2 (patch)
tree0d9e288be90577a8c05e18e72391446f59072ca7
parent5d2a73d520f9b0dbad52954eed380c45e72044f0 (diff)
downloadgcc-ea462dd06fa40bc09069b7d9f72951708a3700a2.zip
gcc-ea462dd06fa40bc09069b7d9f72951708a3700a2.tar.gz
gcc-ea462dd06fa40bc09069b7d9f72951708a3700a2.tar.bz2
predicates.md (splittable_const_int_operand): New, split from move_operand.
* 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. From-SVN: r112150
-rw-r--r--gcc/ChangeLog30
-rw-r--r--gcc/config/mips/mips-protos.h3
-rw-r--r--gcc/config/mips/mips.c127
-rw-r--r--gcc/config/mips/mips.h3
-rw-r--r--gcc/config/mips/mips.md22
-rw-r--r--gcc/config/mips/predicates.md83
6 files changed, 216 insertions, 52 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6e388d8..6175a87 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 1dc31f5..b737375 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -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);
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 12394ca..f907c01 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -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;
/* 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;
}
/* 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;
+ }
+}
/* See whether VALTYPE is a record whose fields should be returned in
floating-point registers. If so, return the number of fields and
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index b0ae120..51d383c 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -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. */
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index cc327f9..ce2cce6 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -3194,6 +3194,28 @@
(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
diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md
index d93621d..23e85d8 100644
--- a/gcc/config/mips/predicates.md
+++ b/gcc/config/mips/predicates.md
@@ -125,30 +125,85 @@
(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;