Commit ea462dd0 by Richard Sandiford Committed by Richard Sandiford

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
parent 5d2a73d5
2006-03-16 Richard Sandiford <richard@codesourcery.com> 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. * config.gcc (mips64*-*-linux*): Keep existing tm_defines.
(mips*-*-linux*): Likewise. (mips*-*-linux*): Likewise.
......
...@@ -106,7 +106,6 @@ enum mips_symbol_type { ...@@ -106,7 +106,6 @@ enum mips_symbol_type {
#define NUM_SYMBOL_TYPES (SYMBOL_64_LOW + 1) #define NUM_SYMBOL_TYPES (SYMBOL_64_LOW + 1)
extern bool mips_symbolic_constant_p (rtx, enum mips_symbol_type *); 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 int mips_regno_mode_ok_for_base_p (int, enum machine_mode, int);
extern bool mips_stack_address_p (rtx, enum machine_mode); extern bool mips_stack_address_p (rtx, enum machine_mode);
extern int mips_address_insns (rtx, enum machine_mode); extern int mips_address_insns (rtx, enum machine_mode);
...@@ -116,8 +115,10 @@ extern int mips_idiv_insns (void); ...@@ -116,8 +115,10 @@ extern int mips_idiv_insns (void);
extern int fp_register_operand (rtx, enum machine_mode); extern int fp_register_operand (rtx, enum machine_mode);
extern int lo_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 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 rtx mips_unspec_address (rtx, enum mips_symbol_type);
extern bool mips_legitimize_address (rtx *, enum machine_mode); 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 bool mips_legitimize_move (enum machine_mode, rtx, rtx);
extern int m16_uimm3_b (rtx, enum machine_mode); extern int m16_uimm3_b (rtx, enum machine_mode);
......
...@@ -274,10 +274,10 @@ static bool mips_symbolic_address_p (enum mips_symbol_type, enum machine_mode); ...@@ -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, static bool mips_classify_address (struct mips_address_info *, rtx,
enum machine_mode, int); enum machine_mode, int);
static bool mips_cannot_force_const_mem (rtx); 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 int mips_symbol_insns (enum mips_symbol_type);
static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx); static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx);
static rtx mips_force_temporary (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_unspec_offset_high (rtx, rtx, rtx, enum mips_symbol_type);
static rtx mips_add_offset (rtx, rtx, HOST_WIDE_INT); static rtx mips_add_offset (rtx, rtx, HOST_WIDE_INT);
static unsigned int mips_build_shift (struct mips_integer_op *, 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 *, ...@@ -285,7 +285,6 @@ static unsigned int mips_build_lower (struct mips_integer_op *,
unsigned HOST_WIDE_INT); unsigned HOST_WIDE_INT);
static unsigned int mips_build_integer (struct mips_integer_op *, static unsigned int mips_build_integer (struct mips_integer_op *,
unsigned HOST_WIDE_INT); 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 void mips_legitimize_const_move (enum machine_mode, rtx, rtx);
static int m16_check_op (rtx, int, int, int); static int m16_check_op (rtx, int, int, int);
static bool mips_rtx_costs (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, ...@@ -333,6 +332,7 @@ static section *mips_select_rtx_section (enum machine_mode, rtx,
unsigned HOST_WIDE_INT); unsigned HOST_WIDE_INT);
static section *mips_function_rodata_section (tree); static section *mips_function_rodata_section (tree);
static bool mips_in_small_data_p (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 int mips_fpr_return_fields (tree, tree *);
static bool mips_return_in_msb (tree); static bool mips_return_in_msb (tree);
static rtx mips_return_fpr_pair (enum machine_mode mode, static rtx mips_return_fpr_pair (enum machine_mode mode,
...@@ -628,7 +628,7 @@ static GTY (()) int mips_output_filename_first_time = 1; ...@@ -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_p[X] is true if symbols of type X can be split by
mips_split_symbol(). */ 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 /* 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 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] = ...@@ -1162,6 +1162,15 @@ static struct mips_rtx_cost_data const mips_rtx_cost_data[PROCESSOR_MAX] =
#undef TARGET_EXTRA_LIVE_ON_ENTRY #undef TARGET_EXTRA_LIVE_ON_ENTRY
#define TARGET_EXTRA_LIVE_ON_ENTRY mips_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; struct gcc_target targetm = TARGET_INITIALIZER;
/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */ /* 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) ...@@ -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 /* 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 static bool
mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset) 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) ...@@ -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)))) && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
return true; 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; return false;
} }
...@@ -1357,17 +1373,6 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type) ...@@ -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. */ /* This function is used to implement REG_MODE_OK_FOR_BASE_P. */
int int
...@@ -1542,10 +1547,42 @@ mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED) ...@@ -1542,10 +1547,42 @@ mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
static bool static bool
mips_cannot_force_const_mem (rtx x) mips_cannot_force_const_mem (rtx x)
{ {
if (! TARGET_HAVE_TLS) rtx base;
return false; 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 /* Return the number of instructions needed to load a symbol of the
...@@ -1845,7 +1882,7 @@ mips_force_temporary (rtx dest, rtx value) ...@@ -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 /* 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. */ and is used to load the high part into a register. */
static rtx rtx
mips_split_symbol (rtx temp, rtx addr) mips_split_symbol (rtx temp, rtx addr)
{ {
rtx high; rtx high;
...@@ -2175,10 +2212,10 @@ mips_build_integer (struct mips_integer_op *codes, ...@@ -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 void
mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value) mips_move_integer (rtx dest, rtx temp, unsigned HOST_WIDE_INT value)
{ {
struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS]; struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
enum machine_mode mode; enum machine_mode mode;
...@@ -2194,7 +2231,10 @@ mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value) ...@@ -2194,7 +2231,10 @@ mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
for (i = 1; i < cost; i++) for (i = 1; i < cost; i++)
{ {
if (no_new_pseudos) if (no_new_pseudos)
emit_move_insn (dest, x), x = dest; {
emit_insn (gen_rtx_SET (VOIDmode, temp, x));
x = temp;
}
else else
x = force_reg (mode, x); x = force_reg (mode, x);
x = gen_rtx_fmt_ee (codes[i].code, mode, x, GEN_INT (codes[i].value)); 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) ...@@ -2213,30 +2253,24 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
{ {
rtx base; rtx base;
HOST_WIDE_INT offset; HOST_WIDE_INT offset;
enum mips_symbol_type symbol_type;
/* Split moves of big integers into smaller pieces. In mips16 code, /* Split moves of big integers into smaller pieces. */
it's better to force the constant into memory instead. */ if (splittable_const_int_operand (src, mode))
if (GET_CODE (src) == CONST_INT && !TARGET_MIPS16)
{ {
mips_move_integer (dest, INTVAL (src)); mips_move_integer (dest, dest, INTVAL (src));
return; 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; return;
} }
/* See if the symbol can be split. For mips16, this is often worse than if (mips_tls_operand_p (src))
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])
{ {
emit_move_insn (dest, mips_split_symbol (dest, src)); emit_move_insn (dest, mips_legitimize_tls_address (src));
return; return;
} }
...@@ -7205,6 +7239,25 @@ mips_in_small_data_p (tree decl) ...@@ -7205,6 +7239,25 @@ mips_in_small_data_p (tree decl)
size = int_size_in_bytes (TREE_TYPE (decl)); size = int_size_in_bytes (TREE_TYPE (decl));
return (size > 0 && size <= mips_section_threshold); 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 /* See whether VALTYPE is a record whose fields should be returned in
floating-point registers. If so, return the number of fields and floating-point registers. If so, return the number of fields and
......
...@@ -106,6 +106,7 @@ struct mips_cpu_info { ...@@ -106,6 +106,7 @@ struct mips_cpu_info {
int isa; int isa;
}; };
#ifndef USED_FOR_TARGET
extern char mips_print_operand_punct[256]; /* print_operand punctuation chars */ extern char mips_print_operand_punct[256]; /* print_operand punctuation chars */
extern const char *current_function_file; /* filename current function is in */ extern const char *current_function_file; /* filename current function is in */
extern int num_source_filenames; /* current .file # */ extern int num_source_filenames; /* current .file # */
...@@ -117,6 +118,7 @@ extern int set_noat; /* # of nested .set noat's */ ...@@ -117,6 +118,7 @@ extern int set_noat; /* # of nested .set noat's */
extern int set_volatile; /* # of nested .set volatile's */ extern int set_volatile; /* # of nested .set volatile's */
extern int mips_branch_likely; /* emit 'l' after br (branch likely) */ extern int mips_branch_likely; /* emit 'l' after br (branch likely) */
extern int mips_dbx_regno[]; /* Map register # to debug register # */ extern int mips_dbx_regno[]; /* Map register # to debug register # */
extern bool mips_split_p[];
extern GTY(()) rtx cmp_operands[2]; extern GTY(()) rtx cmp_operands[2];
extern enum processor_type mips_arch; /* which cpu to codegen for */ extern enum processor_type mips_arch; /* which cpu to codegen for */
extern enum processor_type mips_tune; /* which cpu to schedule 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[]; ...@@ -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_arch_info;
extern const struct mips_cpu_info *mips_tune_info; extern const struct mips_cpu_info *mips_tune_info;
extern const struct mips_rtx_cost_data *mips_cost; extern const struct mips_rtx_cost_data *mips_cost;
#endif
/* Macros to silence warnings about numbers being signed in traditional /* Macros to silence warnings about numbers being signed in traditional
C and unsigned in ISO C when compiled on 32-bit hosts. */ C and unsigned in ISO C when compiled on 32-bit hosts. */
......
...@@ -3194,6 +3194,28 @@ ...@@ -3194,6 +3194,28 @@
(set_attr "mode" "<MODE>") (set_attr "mode" "<MODE>")
(set_attr "length" "8")]) (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 ;; 64-bit integer moves
;; Unlike most other insns, the move insns can't be split with ;; Unlike most other insns, the move insns can't be split with
......
...@@ -125,30 +125,85 @@ ...@@ -125,30 +125,85 @@
(ior (match_operand 0 "const_call_insn_operand") (ior (match_operand 0 "const_call_insn_operand")
(match_operand 0 "register_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" (define_predicate "move_operand"
(match_operand 0 "general_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)) switch (GET_CODE (op))
{ {
case CONST_INT: case CONST_INT:
/* When generating mips16 code, LEGITIMATE_CONSTANT_P rejects return !splittable_const_int_operand (op, mode);
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);
case CONST: case CONST:
case SYMBOL_REF: case SYMBOL_REF:
case LABEL_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: default:
return true; return true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment