aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@redhat.com>2003-01-09 17:45:55 +0000
committerRichard Sandiford <rsandifo@redhat.com>2003-01-09 17:45:55 +0000
commit26f7aa5bc1e2d1f18cf4e60a66a94ee82c4c3e45 (patch)
treec95f9e21012fc06a3fc1524d82ac04f02982eb0f
parentaa97f4c1014244e5a5bbbd3c08ce67537a286e02 (diff)
* config/mips/mips-protos.h (mips16_constant_after_function_p,
mips_address_cost, mips_check_split, double_memory_operand, mips16_gp_offset, mips16_gp_offset_p, mips16_constant, pic_address_needs_scratch, symbolic_operand): Remove declarations. (mips_legitimate_address_p): Return bool. (mips_address_insns, mips_fetch_insns, mips_const_insns, mips_legitimize_address, mips_legitimize_move, mips_expand_call): Declare. (mips_return_addr): Move outside #ifdef RTX_CODE. * config/mips/mips.h (ABI_HAS_64BIT_SYMBOLS): New macro. (PIC_FN_ADDR_REG): New reg_class. (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Add corresponding entries. (GR_REG_CLASS_P): True for PIC_FN_ADDR_REG. (SMALL_OPERAND, SMALL_OPERAND_UNSIGNED, LUI_OPERAND, CONST_HIGH_PART, CONST_LOW_PART, LUI_INT): New macros. (SMALL_INT, SMALL_INT_UNSIGNED, CONST_OK_FOR_LETTER_P): Use new macros. (EXTRA_CONSTRAINTS): Give new meanings to Q, R and S. (CONSTANT_ADDRESS_P): Use mips_legitimate_address_p. (LEGITIMATE_PIC_OPERAND): Undefine. (LEGITIMATE_CONSTANT_P): Use mips_const_insns. (LEGITIMIZE_ADDRESS): Use mips_legitimize_address. (CONSTANT_AFTER_FUNCTION_P): Remove definition in #if 0 block. (FUNCTION_MODE): Change to SImode. (CONST_COSTS): Use mips_const_insns to calculate the cost of most constants. Treat const_artih_operands specially if they occur in a PLUS or MINUS. (CONSTANT_POOL_COST): New macro. (RTX_COSTS): Use mips_address_insns for MEMs, with a base cost of 2. Add LO_SUM handling. (ADDRESS_COST): Undefine. (PREDICATE_CODES): Add symbolic_operand and const_arith_operand. Add CONST to the list of codes for arith_operand. Add LABEL_REF to call_insn_operand and remove CONST_INT. * config/mips/mips.c: Include integrate.h. (SINGLE_WORD_MODE_P): New macro. (mips_constant_type, mips_symbol_type, mips_address_type): New enums. (mips_constant_info, mips_address_info): New structs. (mips_regno_to_class): Map $25 to PIC_FN_ADDR_REG. (mips_classify_constant, mips_classify_symbol, mips_valid_base_register_p, mips_symbolic_address_p, mips_classify_address, mips_symbol_insns, mips16_unextended_reference_p, mips_address_insns, mips_const_insns, mips_fetch_insns, mips_force_temporary, mips_add_offset, mips_legitimize_symbol, mips_legitimize_address, mips_legitimize_move, mips_print_relocation): New functions. (const_arith_operand): New operand predicate. (arith_operand): Use it. (mips_const_double_ok, mips16_simple_memory_operand, simple_memory_operand, double_memory_operand, mips_check_split, mips_address_cost, pic_address_needs_scratch, mips16_gp_offset, mips16_gp_offset_p, mips16_output_gp_offset, mips16_constant_after_function_p, mips16_constant): Remove. (call_insn_operand): Be more fussy about symbolic constants. Use register_operand. (move_operand): Use mips_symbolic_address_p to check symbolic operands and general_operand to check the rest. (symbolic_operand): Use mips_classify_constant. (mips_legitimate_address_p): Use mips_classify_address. (mips_move_1word): Combine handling of symbolic addresses. Remove special treatment of gp-relative loads for TARGET_MIPS16. (move_move_2words): Likewise. Assume addresses are offsettable if they need to refer to more than one word. Add HIGH handling. (mips_restore_gp): Use ptr_mode for the GP save slot. (mips_expand_call): New function, combining the old mips.md call and call_internal define_expands. If the address isn't a call_insn_operand, force it into a register. For SVR4 PIC, emit an exception_receiver instruction after the call. (override_options): Only override flag_pic for TARGET_ABICALLS if it is currently zero. Allow mips_split_addresses when Pmode == DImode too, except when ABI_HAS_64BIT_SYMBOLS. Add new register class letter, 'c'. (print_operand): Use mips_classify_constant for constant operands. (print_operand_address): Use mips_classify_address. (mips_output_function_prologue): Don't use .cprestore. (mips_expand_epilogue): For TARGET_MIPS16, only adjust the stack via the frame pointer if current_function_calls_eh_return. (mips_encode_section_info): For TARGET_ABICALLS, use SYMBOL_REF_FLAG to mark whether a symbol is local or global. (build_mips16_call_stub): Expect the address of the function rather than a MEM reference to it. Update call generation sequences. (mips16_optimize_gp): Remove Pmode checks. Temporarily disable small-data adjustments. * config/mips/mips.md: Remove 'R'/'m' memory distinction. Use default length for loads and stores. (UNSPEC_CPADD, UNSPEC_RELOC_GPREL16): New constants. (define_attr type): Add const and prefetch. (define_attr length): Use mips_const_insns for const instructions. Use mips_fetch_insns for load and store instructions. (define_attr single_insn): New. (define_attr can_delay): Use it. (define_attr abicalls): Remove. (define_delay): Use can_delay. Always allow calls to have delay slots. (addsi3_internal_2): Add 'Q' constraint. (movsi_ulw, movsi_usw, movdi_uld, movdi_usd): Set length to 8. (high): Remove. (lowsi): Renamed from low. (lowdi): New pattern. (movdi, movsi): Use mips_legitimize_move. Remove define_split. (lwxc1, ldxc1, swxc1, sdxc1): Set length to 4. (loadgp): Change operand 0 to an immediate_operand. (tablejump): Use the same patterns for SVR4 PIC but emit a cpadd beforehand. (cpaddsi, cpadddi): New patterns. (tablejump_internal3, tablejump_internal4): Remove define_expands and associated define_splits. (call, call_value): Use mips_expand_call. (call_internal): New, replacing all existing call_internal* insns. (call_value_internal): Likewise call_value_internal*. (call_value_multiple_internal): Likewise call_value_multiple_internal*. (untyped_call): Remove if (operands[0]) magic. (prefetch_si_address, prefetch_si): Change type to "prefetch". (prefetch_di_address, prefetch_di): Likewise. (leasi, leadi): Remove. (reloc_gprel16): New. * config/mips/5400.md (ir_vr54_hilo): Include const type. * config/mips/5500.md (ir_vr55_hilo): Likewise. * config/mips/sr71k.md (ir_sr70_hilo): Likewise. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/mips-3_4-rewrite-branch@61120 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog.rewrite124
-rw-r--r--gcc/config/mips/5400.md2
-rw-r--r--gcc/config/mips/5500.md2
-rw-r--r--gcc/config/mips/mips-protos.h22
-rw-r--r--gcc/config/mips/mips.c2027
-rw-r--r--gcc/config/mips/mips.h394
-rw-r--r--gcc/config/mips/mips.md1315
-rw-r--r--gcc/config/mips/sr71k.md2
8 files changed, 1572 insertions, 2316 deletions
diff --git a/gcc/ChangeLog.rewrite b/gcc/ChangeLog.rewrite
index 34962bf9a56..9af3427bdac 100644
--- a/gcc/ChangeLog.rewrite
+++ b/gcc/ChangeLog.rewrite
@@ -1,3 +1,127 @@
+2003-01-09 Richard Sandiford <rsandifo@redhat.com>
+
+ * config/mips/mips-protos.h (mips16_constant_after_function_p,
+ mips_address_cost, mips_check_split, double_memory_operand,
+ mips16_gp_offset, mips16_gp_offset_p, mips16_constant,
+ pic_address_needs_scratch, symbolic_operand): Remove declarations.
+ (mips_legitimate_address_p): Return bool.
+ (mips_address_insns, mips_fetch_insns, mips_const_insns,
+ mips_legitimize_address, mips_legitimize_move,
+ mips_expand_call): Declare.
+ (mips_return_addr): Move outside #ifdef RTX_CODE.
+
+ * config/mips/mips.h (ABI_HAS_64BIT_SYMBOLS): New macro.
+ (PIC_FN_ADDR_REG): New reg_class.
+ (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Add corresponding entries.
+ (GR_REG_CLASS_P): True for PIC_FN_ADDR_REG.
+ (SMALL_OPERAND, SMALL_OPERAND_UNSIGNED, LUI_OPERAND,
+ CONST_HIGH_PART, CONST_LOW_PART, LUI_INT): New macros.
+ (SMALL_INT, SMALL_INT_UNSIGNED, CONST_OK_FOR_LETTER_P): Use new macros.
+ (EXTRA_CONSTRAINTS): Give new meanings to Q, R and S.
+ (CONSTANT_ADDRESS_P): Use mips_legitimate_address_p.
+ (LEGITIMATE_PIC_OPERAND): Undefine.
+ (LEGITIMATE_CONSTANT_P): Use mips_const_insns.
+ (LEGITIMIZE_ADDRESS): Use mips_legitimize_address.
+ (CONSTANT_AFTER_FUNCTION_P): Remove definition in #if 0 block.
+ (FUNCTION_MODE): Change to SImode.
+ (CONST_COSTS): Use mips_const_insns to calculate the cost of
+ most constants. Treat const_artih_operands specially if they
+ occur in a PLUS or MINUS.
+ (CONSTANT_POOL_COST): New macro.
+ (RTX_COSTS): Use mips_address_insns for MEMs, with a base cost of 2.
+ Add LO_SUM handling.
+ (ADDRESS_COST): Undefine.
+ (PREDICATE_CODES): Add symbolic_operand and const_arith_operand.
+ Add CONST to the list of codes for arith_operand. Add LABEL_REF
+ to call_insn_operand and remove CONST_INT.
+
+ * config/mips/mips.c: Include integrate.h.
+ (SINGLE_WORD_MODE_P): New macro.
+ (mips_constant_type, mips_symbol_type, mips_address_type): New enums.
+ (mips_constant_info, mips_address_info): New structs.
+ (mips_regno_to_class): Map $25 to PIC_FN_ADDR_REG.
+ (mips_classify_constant, mips_classify_symbol,
+ mips_valid_base_register_p, mips_symbolic_address_p,
+ mips_classify_address, mips_symbol_insns,
+ mips16_unextended_reference_p, mips_address_insns, mips_const_insns,
+ mips_fetch_insns, mips_force_temporary, mips_add_offset,
+ mips_legitimize_symbol, mips_legitimize_address, mips_legitimize_move,
+ mips_print_relocation): New functions.
+ (const_arith_operand): New operand predicate.
+ (arith_operand): Use it.
+ (mips_const_double_ok, mips16_simple_memory_operand,
+ simple_memory_operand, double_memory_operand, mips_check_split,
+ mips_address_cost, pic_address_needs_scratch, mips16_gp_offset,
+ mips16_gp_offset_p, mips16_output_gp_offset,
+ mips16_constant_after_function_p, mips16_constant): Remove.
+ (call_insn_operand): Be more fussy about symbolic constants.
+ Use register_operand.
+ (move_operand): Use mips_symbolic_address_p to check symbolic
+ operands and general_operand to check the rest.
+ (symbolic_operand): Use mips_classify_constant.
+ (mips_legitimate_address_p): Use mips_classify_address.
+ (mips_move_1word): Combine handling of symbolic addresses.
+ Remove special treatment of gp-relative loads for TARGET_MIPS16.
+ (move_move_2words): Likewise. Assume addresses are offsettable
+ if they need to refer to more than one word. Add HIGH handling.
+ (mips_restore_gp): Use ptr_mode for the GP save slot.
+ (mips_expand_call): New function, combining the old mips.md
+ call and call_internal define_expands. If the address isn't
+ a call_insn_operand, force it into a register. For SVR4 PIC,
+ emit an exception_receiver instruction after the call.
+ (override_options): Only override flag_pic for TARGET_ABICALLS
+ if it is currently zero. Allow mips_split_addresses when
+ Pmode == DImode too, except when ABI_HAS_64BIT_SYMBOLS.
+ Add new register class letter, 'c'.
+ (print_operand): Use mips_classify_constant for constant operands.
+ (print_operand_address): Use mips_classify_address.
+ (mips_output_function_prologue): Don't use .cprestore.
+ (mips_expand_epilogue): For TARGET_MIPS16, only adjust the stack
+ via the frame pointer if current_function_calls_eh_return.
+ (mips_encode_section_info): For TARGET_ABICALLS, use SYMBOL_REF_FLAG
+ to mark whether a symbol is local or global.
+ (build_mips16_call_stub): Expect the address of the function rather
+ than a MEM reference to it. Update call generation sequences.
+ (mips16_optimize_gp): Remove Pmode checks. Temporarily disable
+ small-data adjustments.
+
+ * config/mips/mips.md: Remove 'R'/'m' memory distinction. Use default
+ length for loads and stores.
+ (UNSPEC_CPADD, UNSPEC_RELOC_GPREL16): New constants.
+ (define_attr type): Add const and prefetch.
+ (define_attr length): Use mips_const_insns for const instructions.
+ Use mips_fetch_insns for load and store instructions.
+ (define_attr single_insn): New.
+ (define_attr can_delay): Use it.
+ (define_attr abicalls): Remove.
+ (define_delay): Use can_delay. Always allow calls to have delay slots.
+ (addsi3_internal_2): Add 'Q' constraint.
+ (movsi_ulw, movsi_usw, movdi_uld, movdi_usd): Set length to 8.
+ (high): Remove.
+ (lowsi): Renamed from low.
+ (lowdi): New pattern.
+ (movdi, movsi): Use mips_legitimize_move. Remove define_split.
+ (lwxc1, ldxc1, swxc1, sdxc1): Set length to 4.
+ (loadgp): Change operand 0 to an immediate_operand.
+ (tablejump): Use the same patterns for SVR4 PIC but emit a cpadd
+ beforehand.
+ (cpaddsi, cpadddi): New patterns.
+ (tablejump_internal3, tablejump_internal4): Remove define_expands
+ and associated define_splits.
+ (call, call_value): Use mips_expand_call.
+ (call_internal): New, replacing all existing call_internal* insns.
+ (call_value_internal): Likewise call_value_internal*.
+ (call_value_multiple_internal): Likewise call_value_multiple_internal*.
+ (untyped_call): Remove if (operands[0]) magic.
+ (prefetch_si_address, prefetch_si): Change type to "prefetch".
+ (prefetch_di_address, prefetch_di): Likewise.
+ (leasi, leadi): Remove.
+ (reloc_gprel16): New.
+
+ * config/mips/5400.md (ir_vr54_hilo): Include const type.
+ * config/mips/5500.md (ir_vr55_hilo): Likewise.
+ * config/mips/sr71k.md (ir_sr70_hilo): Likewise.
+
2003-01-08 Eric Christopher <echristo@redhat.com>
* config.gcc (mipsisa32*): Change ABI_MEABI to ABI_EABI.
diff --git a/gcc/config/mips/5400.md b/gcc/config/mips/5400.md
index 3b8002cb285..6934b7433df 100644
--- a/gcc/config/mips/5400.md
+++ b/gcc/config/mips/5400.md
@@ -64,7 +64,7 @@
(define_insn_reservation "ir_vr54_arith" 1
(and (eq_attr "cpu" "r5400")
- (eq_attr "type" "arith,darith,icmp,nop"))
+ (eq_attr "type" "arith,darith,const,icmp,nop"))
"vr54_dp0|vr54_dp1")
(define_insn_reservation "ir_vr54_imul_si" 3
diff --git a/gcc/config/mips/5500.md b/gcc/config/mips/5500.md
index 8023b9a6064..dc85356d98b 100644
--- a/gcc/config/mips/5500.md
+++ b/gcc/config/mips/5500.md
@@ -57,7 +57,7 @@
(define_insn_reservation "ir_vr55_arith" 1
(and (eq_attr "cpu" "r5500")
- (eq_attr "type" "arith,darith,icmp,nop"))
+ (eq_attr "type" "arith,darith,const,icmp,nop"))
"vr55_dp0|vr55_dp1")
(define_insn_reservation "ir_vr55_imul_si" 3
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 3badb808824..a746c0d1a00 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -74,7 +74,6 @@ extern int mips_setup_incoming_varargs
extern int function_arg_pass_by_reference
PARAMS ((const CUMULATIVE_ARGS *,
enum machine_mode, tree, int));
-extern int mips16_constant_after_function_p PARAMS ((tree));
extern int mips_output_external PARAMS ((FILE *, tree,
const char *));
extern tree mips_build_va_list PARAMS ((void));
@@ -90,10 +89,8 @@ extern void mips_gen_conditional_trap PARAMS ((rtx *));
extern void mips_emit_fcc_reload PARAMS ((rtx, rtx, rtx));
extern void mips_set_return_address PARAMS ((rtx, rtx));
extern void machine_dependent_reorg PARAMS ((rtx));
-extern int mips_address_cost PARAMS ((rtx));
extern void mips_count_memory_refs PARAMS ((rtx, int));
extern HOST_WIDE_INT mips_debugger_offset PARAMS ((rtx, HOST_WIDE_INT));
-extern int mips_check_split PARAMS ((rtx, enum machine_mode));
extern const char *mips_fill_delay_slot PARAMS ((const char *,
enum delay_type, rtx *,
rtx));
@@ -108,12 +105,7 @@ extern void override_options PARAMS ((void));
extern void mips_conditional_register_usage PARAMS ((void));
extern void print_operand_address PARAMS ((FILE *, rtx));
extern void print_operand PARAMS ((FILE *, rtx, int));
-extern int double_memory_operand PARAMS ((rtx,enum machine_mode));
extern struct rtx_def * embedded_pic_offset PARAMS ((rtx));
-extern struct rtx_def * mips16_gp_offset PARAMS ((rtx));
-extern int mips16_gp_offset_p PARAMS ((rtx));
-extern int mips16_constant PARAMS ((rtx, enum machine_mode,
- int, int));
extern int build_mips16_call_stub PARAMS ((rtx, rtx, rtx, int));
extern const char *mips_output_conditional_branch PARAMS ((rtx, rtx *,
int, int, int,
@@ -130,13 +122,19 @@ extern int mips_register_move_cost PARAMS ((enum machine_mode,
enum reg_class,
enum reg_class));
-extern int pic_address_needs_scratch PARAMS ((rtx));
extern int se_arith_operand PARAMS ((rtx, enum machine_mode));
extern int coprocessor_operand PARAMS ((rtx, enum machine_mode));
extern int coprocessor2_operand PARAMS ((rtx, enum machine_mode));
-extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
-extern int mips_legitimate_address_p PARAMS ((enum machine_mode,
+extern int mips_address_insns PARAMS ((rtx, enum machine_mode));
+extern int mips_fetch_insns PARAMS ((rtx));
+extern int mips_const_insns PARAMS ((rtx));
+extern bool mips_legitimate_address_p PARAMS ((enum machine_mode,
rtx, int));
+extern bool mips_legitimize_address PARAMS ((rtx *,
+ enum machine_mode));
+extern bool mips_legitimize_move PARAMS ((enum machine_mode,
+ rtx, rtx));
+extern void mips_expand_call PARAMS ((rtx, rtx, rtx, rtx));
extern int mips_reg_mode_ok_for_base_p PARAMS ((rtx,
enum machine_mode,
int));
@@ -165,7 +163,7 @@ extern int m16_usym5_4 PARAMS ((rtx, enum machine_mode));
extern rtx gen_int_relational PARAMS ((enum rtx_code, rtx, rtx,
rtx,int *));
extern void gen_conditional_branch PARAMS ((rtx *, enum rtx_code));
-extern rtx mips_return_addr PARAMS ((int, rtx));
#endif
+extern rtx mips_return_addr PARAMS ((int, rtx));
#endif /* ! GCC_MIPS_PROTOS_H */
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 3712e0797c9..791ce013ead 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -55,6 +55,7 @@ Boston, MA 02111-1307, USA. */
#include "debug.h"
#include "target.h"
#include "target-def.h"
+#include "integrate.h"
#ifdef __GNU_STAB__
#define STAB_CODE_TYPE enum __stab_debug_code
@@ -82,14 +83,126 @@ enum internal_test {
ITEST_MAX
};
+/* Return true if it is likely that the given mode will be accessed
+ using only a single instruction. */
+#define SINGLE_WORD_MODE_P(MODE) \
+ ((MODE) != BLKmode && GET_MODE_SIZE (MODE) <= UNITS_PER_WORD)
+
+
+/* Classifies a non-literal integer constant.
+
+ CONSTANT_NONE
+ Not one of the constants below.
+
+ CONSTANT_GP
+ The global pointer, treated as a constant when TARGET_MIPS16.
+ The rtx has the form:
+
+ (const (reg $gp)).
+
+ CONSTANT_RELOC
+ A signed 16-bit relocation against either a symbol
+ or a symbol plus an offset. The relocation has the form:
+
+ (unspec [(SYMBOL) ...] RELOC)
+
+ Any offset is added outside the unspec, such as:
+
+ (plus (unspec [(SYMBOL) ...] RELOC) (const_int OFFSET))
+
+ In either case, the whole expression is wrapped in a (const ...).
+
+ CONSTANT_SYMBOLIC
+ A reference to a symbol, possibly with an offset. */
+enum mips_constant_type {
+ CONSTANT_NONE,
+ CONSTANT_GP,
+ CONSTANT_RELOC,
+ CONSTANT_SYMBOLIC
+};
+
+
+/* Classifies a SYMBOL_REF or LABEL_REF.
+
+ SYMBOL_GENERAL
+ Used when none of the below apply.
+
+ SYMBOL_SMALL_DATA
+ The symbol refers to something in a small data section.
+
+ SYMBOL_CONSTANT_POOL
+ The symbol refers to something in the mips16 constant pool.
+
+ SYMBOL_GOT_LOCAL
+ The symbol refers to local data that will be found using
+ the global offset table.
+
+ SYMBOL_GOT_GLOBAL
+ Likewise non-local data. */
+enum mips_symbol_type {
+ SYMBOL_GENERAL,
+ SYMBOL_SMALL_DATA,
+ SYMBOL_CONSTANT_POOL,
+ SYMBOL_GOT_LOCAL,
+ SYMBOL_GOT_GLOBAL
+};
+
+
+/* Classifies an address.
+
+ ADDRESS_INVALID
+ The address should be rejected as invalid.
+
+ ADDRESS_REG
+ A natural register + offset address. The register satisfies
+ mips_valid_base_register_p and the offset is a const_arith_operand.
+
+ ADDRESS_LO_SUM
+ A LO_SUM rtx. The first operand is a valid base register and
+ the second operand is a symbolic address.
+
+ ADDRESS_CONST_INT
+ A signed 16-bit constant address.
+
+ ADDRESS_SYMBOLIC:
+ A constant symbolic address (equivalent to CONSTANT_SYMBOLIC). */
+enum mips_address_type {
+ ADDRESS_INVALID,
+ ADDRESS_REG,
+ ADDRESS_LO_SUM,
+ ADDRESS_CONST_INT,
+ ADDRESS_SYMBOLIC
+};
+
struct constant;
struct mips_arg_info;
+struct mips_constant_info;
+struct mips_address_info;
+static enum mips_constant_type mips_classify_constant
+ PARAMS ((struct mips_constant_info *, rtx));
+static enum mips_symbol_type mips_classify_symbol
+ PARAMS ((rtx));
+static bool mips_valid_base_register_p
+ PARAMS ((rtx, enum machine_mode, int));
+static bool mips_symbolic_address_p
+ PARAMS ((rtx, HOST_WIDE_INT,
+ enum machine_mode, int));
+static enum mips_address_type mips_classify_address
+ PARAMS ((struct mips_address_info *,
+ rtx, enum machine_mode, int, int));
static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code));
static void get_float_compare_codes PARAMS ((enum rtx_code, enum rtx_code *,
enum rtx_code *));
-static int mips16_simple_memory_operand PARAMS ((rtx, rtx,
- enum machine_mode));
+static void mips_print_relocation PARAMS ((FILE *, rtx, int));
+static int mips_symbol_insns PARAMS ((enum mips_symbol_type));
+static bool mips16_unextended_reference_p
+ PARAMS ((enum machine_mode mode,
+ rtx, rtx));
+static rtx mips_force_temporary PARAMS ((enum machine_mode mode,
+ rtx, rtx));
+static rtx mips_add_offset PARAMS ((rtx, HOST_WIDE_INT));
+static bool mips_legitimize_symbol PARAMS ((rtx, rtx *, int));
static int m16_check_op PARAMS ((rtx, int, int, int));
static void block_move_loop PARAMS ((rtx, rtx,
unsigned int,
@@ -107,7 +220,6 @@ static rtx mips_frame_set PARAMS ((enum machine_mode,
static void mips_emit_frame_related_store PARAMS ((rtx, rtx,
HOST_WIDE_INT));
static void save_restore_insns PARAMS ((int, rtx, long));
-static void mips16_output_gp_offset PARAMS ((FILE *, rtx));
static void mips16_fp_args PARAMS ((FILE *, int, int));
static void build_mips16_function_stub PARAMS ((FILE *));
static void mips16_optimize_gp PARAMS ((rtx));
@@ -224,6 +336,51 @@ struct mips_arg_info
unsigned int stack_offset;
};
+
+/* Struct for recording constants. The meaning of the fields depends
+ on a mips_constant_type:
+
+ CONSTANT_NONE
+ CONSTANT_GP
+ No fields are valid.
+
+ CONSTANT_RELOC
+ SYMBOL is the relocation UNSPEC and OFFSET is the offset applied
+ to the symbol.
+
+ CONSTANT_SYMBOLIC
+ SYMBOL is the referenced symbol and OFFSET is the constant offset. */
+struct mips_constant_info
+{
+ rtx symbol;
+ HOST_WIDE_INT offset;
+};
+
+
+/* Information about an address described by mips_address_type.
+
+ ADDRESS_INVALID
+ ADDRESS_CONST_INT
+ No fields are used.
+
+ ADDRESS_REG
+ REG is the base register and OFFSET is the constant offset.
+
+ ADDRESS_LO_SUM
+ REG is the register that contains the high part of the address,
+ OFFSET is the symbolic address being referenced, and C contains
+ the individual components of the symbolic address.
+
+ ADDRESS_SYMBOLIC
+ C contains the symbol and offset. */
+struct mips_address_info
+{
+ rtx reg;
+ rtx offset;
+ struct mips_constant_info c;
+};
+
+
/* Global variables for machine-dependent things. */
/* Threshold for data being put into the small data/bss area, instead
@@ -462,7 +619,7 @@ const enum reg_class mips_regno_to_class[] =
GR_REGS, GR_REGS, GR_REGS, GR_REGS,
M16_NA_REGS, M16_NA_REGS, GR_REGS, GR_REGS,
GR_REGS, GR_REGS, GR_REGS, GR_REGS,
- T_REG, GR_REGS, GR_REGS, GR_REGS,
+ T_REG, PIC_FN_ADDR_REG, GR_REGS, GR_REGS,
GR_REGS, GR_REGS, GR_REGS, GR_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
@@ -672,6 +829,457 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
struct gcc_target targetm = TARGET_INITIALIZER;
+/* If X is one of the constants described by mips_constant_type,
+ store its components in INFO and return its type. */
+
+static enum mips_constant_type
+mips_classify_constant (info, x)
+ struct mips_constant_info *info;
+ rtx x;
+{
+ info->offset = 0;
+ info->symbol = x;
+ if (GET_CODE (x) == CONST)
+ {
+ x = XEXP (x, 0);
+
+ if (GET_CODE (x) == REG && REGNO (x) == GP_REG_FIRST + 28)
+ return CONSTANT_GP;
+
+ while (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ info->offset += INTVAL (XEXP (x, 1));
+ x = XEXP (x, 0);
+ }
+ info->symbol = x;
+ if (GET_CODE (x) == UNSPEC)
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_RELOC_GPREL16:
+ return CONSTANT_RELOC;
+ }
+ }
+ if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
+ return CONSTANT_SYMBOLIC;
+ return CONSTANT_NONE;
+}
+
+
+/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
+
+static enum mips_symbol_type
+mips_classify_symbol (x)
+ rtx x;
+{
+ if (GET_CODE (x) == LABEL_REF)
+ return (TARGET_ABICALLS ? SYMBOL_GOT_LOCAL : SYMBOL_GENERAL);
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ abort ();
+
+ if (CONSTANT_POOL_ADDRESS_P (x))
+ {
+ if (TARGET_MIPS16)
+ return SYMBOL_CONSTANT_POOL;
+
+ if (TARGET_ABICALLS)
+ return SYMBOL_GOT_LOCAL;
+
+ if (GET_MODE_SIZE (get_pool_mode (x)) <= mips_section_threshold)
+ return SYMBOL_SMALL_DATA;
+
+ return SYMBOL_GENERAL;
+ }
+
+ /* SYMBOL_REF_FLAG is overloaded for mips16 code: it can indicate a
+ string constant or a GP-relative access. Check for strings here. */
+ if (TARGET_MIPS16
+ && SYMBOL_REF_FLAG (x)
+ && XSTR (x, 0)[0] == '*'
+ && strncmp (XSTR (x, 0) + 1, LOCAL_LABEL_PREFIX,
+ sizeof LOCAL_LABEL_PREFIX - 1) == 0)
+ return SYMBOL_CONSTANT_POOL;
+
+ if (TARGET_ABICALLS)
+ return (SYMBOL_REF_FLAG (x) ? SYMBOL_GOT_GLOBAL : SYMBOL_GOT_LOCAL);
+
+ return (SYMBOL_REF_FLAG (x) ? SYMBOL_SMALL_DATA : SYMBOL_GENERAL);
+}
+
+
+/* This function is used to implement REG_MODE_OK_FOR_BASE_P. */
+
+int
+mips_reg_mode_ok_for_base_p (reg, mode, strict)
+ rtx reg;
+ enum machine_mode mode;
+ int strict;
+{
+ return (strict
+ ? REGNO_MODE_OK_FOR_BASE_P (REGNO (reg), mode)
+ : GP_REG_OR_PSEUDO_NONSTRICT_P (REGNO (reg), mode));
+}
+
+
+/* Return true if X is a valid base register for the given mode.
+ Allow only hard registers if STRICT. */
+
+static bool
+mips_valid_base_register_p (x, mode, strict)
+ rtx x;
+ enum machine_mode mode;
+ int strict;
+{
+ if (!strict && GET_CODE (x) == SUBREG)
+ x = SUBREG_REG (x);
+
+ return (GET_CODE (x) == REG
+ && mips_reg_mode_ok_for_base_p (x, mode, strict));
+}
+
+
+/* Return true if SYMBOL + OFFSET should be considered a legitimate
+ address. LEA_P is true and MODE is word_mode if the address
+ will be used in an LA or DLA macro. Otherwise MODE is the
+ mode of the value being accessed.
+
+ Some guiding principles:
+
+ - Allow a nonzero offset when it takes no additional instructions.
+ Ask for other offsets to be added separately.
+
+ - Only allow multi-instruction load or store macros when MODE is
+ word-sized or smaller. For other modes (including BLKmode)
+ it is better to move the address into a register first.
+
+ Note: the first rule means we sometimes split:
+
+ la <reg>, symbol + offset
+
+ into:
+
+ la <reg>, symbol
+ add offset to <reg>
+
+ even if the assembler could handle the original form using
+ fewer instructions. We do this to encourage better scheduling
+ and CSE. */
+
+static bool
+mips_symbolic_address_p (symbol, offset, mode, lea_p)
+ rtx symbol;
+ HOST_WIDE_INT offset;
+ enum machine_mode mode;
+ int lea_p;
+{
+ switch (mips_classify_symbol (symbol))
+ {
+ case SYMBOL_GENERAL:
+ /* General symbols aren't valid addresses in mips16 code:
+ they have to go into the constant pool. */
+ return (!TARGET_MIPS16
+ && !mips_split_addresses
+ && SINGLE_WORD_MODE_P (mode));
+
+ case SYMBOL_SMALL_DATA:
+ /* Small data references are normally OK for any address.
+ But for mips16 code, we need to use a pseudo register
+ instead of $gp as the base register. */
+ return !TARGET_MIPS16;
+
+ case SYMBOL_CONSTANT_POOL:
+ /* PC-relative addressing is only available for lw, sw, ld and sd.
+ There's also a PC-relative add instruction. */
+ return lea_p || GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8;
+
+ case SYMBOL_GOT_GLOBAL:
+ /* The address of the symbol is stored in the GOT. We can load
+ it using an LA or DLA instruction, but any offset is added
+ afterwards. */
+ return lea_p && offset == 0;
+
+ case SYMBOL_GOT_LOCAL:
+ /* The symbol is part of a block of local memory. We fetch the
+ address of the local memory from the GOT and then add the
+ offset for this symbol. This addition can take the form of an
+ offset(base) address, so the symbol is a legitimate address. */
+ return SINGLE_WORD_MODE_P (mode) && offset == 0;
+ }
+ abort ();
+}
+
+
+/* If X is a valid address, describe it in INFO and return its type.
+ STRICT says to only allow hard registers. MODE and LEA_P are
+ the same as for mips_symbolic_address_p. */
+
+static enum mips_address_type
+mips_classify_address (info, x, mode, strict, lea_p)
+ struct mips_address_info *info;
+ rtx x;
+ enum machine_mode mode;
+ int strict, lea_p;
+{
+ switch (GET_CODE (x))
+ {
+ case REG:
+ case SUBREG:
+ if (mips_valid_base_register_p (x, mode, strict))
+ {
+ info->reg = x;
+ info->offset = const0_rtx;
+ return ADDRESS_REG;
+ }
+ return ADDRESS_INVALID;
+
+ case PLUS:
+ if (mips_valid_base_register_p (XEXP (x, 0), mode, strict)
+ && const_arith_operand (XEXP (x, 1), VOIDmode))
+ {
+ info->reg = XEXP (x, 0);
+ info->offset = XEXP (x, 1);
+ return ADDRESS_REG;
+ }
+ return ADDRESS_INVALID;
+
+ case LO_SUM:
+ if (SINGLE_WORD_MODE_P (mode)
+ && mips_valid_base_register_p (XEXP (x, 0), mode, strict)
+ && mips_classify_constant (&info->c, XEXP (x, 1)) == CONSTANT_SYMBOLIC
+ && mips_classify_symbol (info->c.symbol) == SYMBOL_GENERAL)
+ {
+ info->reg = XEXP (x, 0);
+ info->offset = XEXP (x, 1);
+ return ADDRESS_LO_SUM;
+ }
+ return ADDRESS_INVALID;
+
+ case CONST_INT:
+ /* Small-integer addressses don't occur very often, but they
+ are legitimate if $0 is a valid base register. */
+ if (!TARGET_MIPS16 && SMALL_INT (x))
+ return ADDRESS_CONST_INT;
+ return ADDRESS_INVALID;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ if (mips_classify_constant (&info->c, x) == CONSTANT_SYMBOLIC
+ && mips_symbolic_address_p (info->c.symbol, info->c.offset,
+ mode, lea_p))
+ return ADDRESS_SYMBOLIC;
+ return ADDRESS_INVALID;
+
+ default:
+ return ADDRESS_INVALID;
+ }
+}
+
+/* Return the number of instructions needed to load a symbol of the
+ given type into a register. If valid in an address, the same number
+ of instructions are needed for loads and stores. Treat extended
+ mips16 instructions as two instructions. */
+
+static int
+mips_symbol_insns (type)
+ enum mips_symbol_type type;
+{
+ switch (type)
+ {
+ case SYMBOL_GENERAL:
+ /* When using 64-bit symbols, we need 5 preparatory instructions,
+ such as:
+
+ lui $at,%highest(symbol)
+ daddiu $at,$at,%higher(symbol)
+ dsll $at,$at,16
+ daddiu $at,$at,%hi(symbol)
+ dsll $at,$at,16
+
+ The final address is then $at + %lo(symbol). With 32-bit
+ symbols we just need a preparatory lui. */
+ return (ABI_HAS_64BIT_SYMBOLS ? 6 : 2);
+
+ case SYMBOL_SMALL_DATA:
+ return 1;
+
+ case SYMBOL_CONSTANT_POOL:
+ /* This case is for mips16 only. Assume we'll need an
+ extended instruction. */
+ return 2;
+
+ case SYMBOL_GOT_GLOBAL:
+ /* When using a small GOT, we just fetch the address using
+ a gp-relative load. For a big GOT, we need a sequence
+ such as:
+
+ lui $at,%got_hi(symbol)
+ daddu $at,$at,$gp
+
+ and the final address is $at + %got_lo(symbol). */
+ return (flag_pic == 1 ? 1 : 3);
+
+ case SYMBOL_GOT_LOCAL:
+ /* For o32 and o64, the sequence is:
+
+ lw $at,%got(symbol)
+ nop
+
+ and the final address is $at + %lo(symbol). A load/add
+ sequence is also needed for n32 and n64. Some versions
+ of GAS insert a nop in the n32/n64 sequences too so, for
+ simplicity, use the worst case of 3 instructions. */
+ return 3;
+ }
+ abort ();
+}
+
+
+/* Return true if a value at OFFSET bytes from BASE can be accessed
+ using an unextended mips16 instruction. MODE is the mode of the
+ value. */
+
+static bool
+mips16_unextended_reference_p (mode, base, offset)
+ enum machine_mode mode;
+ rtx base, offset;
+{
+ if (TARGET_MIPS16 && GET_CODE (offset) == CONST_INT)
+ {
+ int range;
+
+ if (GET_MODE_SIZE (mode) == 4 && base == stack_pointer_rtx)
+ range = 256;
+ else
+ range = 32;
+
+ if (GET_MODE_SIZE (mode) > 1)
+ range *= 2;
+ if (GET_MODE_SIZE (mode) > 2)
+ range *= 2;
+ if (GET_MODE_SIZE (mode) > 4)
+ range *= 2;
+
+ return (INTVAL (offset) >= 0 && INTVAL (offset) < range);
+ }
+ return false;
+}
+
+
+/* Return the number of instructions needed to load or store a value
+ of mode MODE at X. Return 0 if X isn't valid for MODE.
+
+ For mips16 code, count extended instructions as two instructions. */
+
+int
+mips_address_insns (x, mode)
+ rtx x;
+ enum machine_mode mode;
+{
+ struct mips_address_info addr;
+ int factor;
+
+ /* Each word of a multi-word value will be accessed individually. */
+ factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ switch (mips_classify_address (&addr, x, mode, 0, 0))
+ {
+ case ADDRESS_INVALID:
+ return 0;
+
+ case ADDRESS_REG:
+ if (TARGET_MIPS16
+ && !mips16_unextended_reference_p (mode, addr.reg, addr.offset))
+ return factor * 2;
+ return factor;
+
+ case ADDRESS_LO_SUM:
+ case ADDRESS_CONST_INT:
+ return factor;
+
+ case ADDRESS_SYMBOLIC:
+ return factor * mips_symbol_insns (mips_classify_symbol (addr.c.symbol));
+ }
+ abort ();
+}
+
+
+/* Likewise for constant X. */
+
+int
+mips_const_insns (x)
+ rtx x;
+{
+ struct mips_constant_info c;
+
+ switch (GET_CODE (x))
+ {
+ case CONSTANT_P_RTX:
+ return 1;
+
+ case HIGH:
+ return (mips_split_addresses ? 1 : 0);
+
+ case CONST_INT:
+ if (TARGET_MIPS16)
+ /* Unsigned 8-bit constants can be loaded using an unextended
+ LI instruction. Unsigned 16-bit constants can be loaded
+ using an extended LI. Negative constants must be loaded
+ using LI and then negated. */
+ return (INTVAL (x) >= 0 && INTVAL (x) < 256 ? 1
+ : SMALL_OPERAND_UNSIGNED (INTVAL (x)) ? 2
+ : INTVAL (x) > -256 && INTVAL (x) < 0 ? 2
+ : SMALL_OPERAND_UNSIGNED (-INTVAL (x)) ? 3
+ : 0);
+
+ /* Return 1 for constants that can be loaded using ORI, ADDIU,
+ or LUI. Return 2 for constants that can be loaded using
+ LUI followed by ORI. Assume the worst case for all others.
+ (The worst case is: LUI, ORI, SLL, ORI, SLL, ORI.) */
+ return (SMALL_OPERAND (INTVAL (x)) ? 1
+ : SMALL_OPERAND_UNSIGNED (INTVAL (x)) ? 1
+ : LUI_OPERAND (INTVAL (x)) ? 1
+ : LUI_OPERAND (INTVAL (x) & ~(unsigned HOST_WIDE_INT) 0xffff) ? 2
+ : 6);
+
+ case CONST_DOUBLE:
+ return (!TARGET_MIPS16 && x == CONST0_RTX (GET_MODE (x)) ? 1 : 0);
+
+ default:
+ switch (mips_classify_constant (&c, x))
+ {
+ case CONSTANT_NONE:
+ return 0;
+
+ case CONSTANT_GP:
+ return 1;
+
+ case CONSTANT_RELOC:
+ /* When generating mips16 code, we need to set the destination to
+ $0 and then add in the signed offset. See mips_move_1word. */
+ return (TARGET_MIPS16 ? 3 : 1);
+
+ case CONSTANT_SYMBOLIC:
+ return mips_symbol_insns (mips_classify_symbol (c.symbol));
+ }
+ abort ();
+ }
+}
+
+
+/* Return the number of instructions needed for memory reference X.
+ Count extended mips16 instructions as two instructions. */
+
+int
+mips_fetch_insns (x)
+ rtx x;
+{
+ if (GET_CODE (x) != MEM)
+ abort ();
+
+ return mips_address_insns (XEXP (x, 0), GET_MODE (x));
+}
+
+
/* Return truth value of whether OP can be used as an operands
where a register or 16 bit unsigned integer is needed. */
@@ -686,6 +1294,21 @@ uns_arith_operand (op, mode)
return register_operand (op, mode);
}
+
+/* True if OP can be treated as a signed 16-bit constant. */
+
+int
+const_arith_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ struct mips_constant_info c;
+
+ return ((GET_CODE (op) == CONST_INT && SMALL_INT (op))
+ || mips_classify_constant (&c, op) == CONSTANT_RELOC);
+}
+
+
/* Return truth value of whether OP can be used as an operands
where a 16 bit integer is needed */
@@ -694,14 +1317,7 @@ arith_operand (op, mode)
rtx op;
enum machine_mode mode;
{
- if (GET_CODE (op) == CONST_INT && SMALL_INT (op))
- return 1;
-
- /* On the mips16, a GP relative value is a signed 16 bit offset. */
- if (TARGET_MIPS16 && GET_CODE (op) == CONST && mips16_gp_offset_p (op))
- return 1;
-
- return register_operand (op, mode);
+ return const_arith_operand (op, mode) || register_operand (op, mode);
}
/* Return truth value of whether OP can be used as an operand in a two
@@ -817,32 +1433,6 @@ true_reg_or_0_operand (op, mode)
return 0;
}
-/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
-
-int
-mips_const_double_ok (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- if (GET_CODE (op) != CONST_DOUBLE)
- return 0;
-
- if (mode == VOIDmode)
- return 1;
-
- /* We've no zero register in mips16 mode. */
- if (TARGET_MIPS16)
- return 0;
-
- if (mode != SFmode && mode != DFmode)
- return 0;
-
- if (op == CONST0_RTX (mode))
- return 1;
-
- return 0;
-}
-
/* Accept the floating point constant 1 in the appropriate mode. */
int
@@ -862,275 +1452,6 @@ const_float_1_operand (op, mode)
return REAL_VALUES_EQUAL (d, dconst1);
}
-/* Return true if a memory load or store of REG plus OFFSET in MODE
- can be represented in a single word on the mips16. */
-
-static int
-mips16_simple_memory_operand (reg, offset, mode)
- rtx reg;
- rtx offset;
- enum machine_mode mode;
-{
- unsigned int size;
- int off;
-
- if (mode == BLKmode)
- {
- /* We can't tell, because we don't know how the value will
- eventually be accessed. Returning 0 here does no great
- harm; it just prevents some possible instruction scheduling. */
- return 0;
- }
-
- size = GET_MODE_SIZE (mode);
-
- if (INTVAL (offset) % size != 0)
- return 0;
- if (REGNO (reg) == STACK_POINTER_REGNUM && GET_MODE_SIZE (mode) == 4)
- off = 0x100;
- else
- off = 0x20;
- if (INTVAL (offset) >= 0 && INTVAL (offset) < (HOST_WIDE_INT)(off * size))
- return 1;
- return 0;
-}
-
-/* Return truth value if a memory operand fits in a single instruction
- (ie, register + small offset). */
-
-int
-simple_memory_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- rtx addr, plus0, plus1;
-
- /* Eliminate non-memory operations */
- if (GET_CODE (op) != MEM)
- return 0;
-
- /* dword operations really put out 2 instructions, so eliminate them. */
- /* ??? This isn't strictly correct. It is OK to accept multiword modes
- here, since the length attributes are being set correctly, but only
- if the address is offsettable. LO_SUM is not offsettable. */
- if (GET_MODE_SIZE (GET_MODE (op)) > (unsigned) UNITS_PER_WORD)
- return 0;
-
- /* Decode the address now. */
- addr = XEXP (op, 0);
- switch (GET_CODE (addr))
- {
- case REG:
- case LO_SUM:
- return 1;
-
- case CONST_INT:
- if (TARGET_MIPS16)
- return 0;
- return SMALL_INT (addr);
-
- case PLUS:
- plus0 = XEXP (addr, 0);
- plus1 = XEXP (addr, 1);
- if (GET_CODE (plus0) == REG
- && GET_CODE (plus1) == CONST_INT && SMALL_INT (plus1)
- && (! TARGET_MIPS16
- || mips16_simple_memory_operand (plus0, plus1, mode)))
- return 1;
-
- else if (GET_CODE (plus1) == REG
- && GET_CODE (plus0) == CONST_INT && SMALL_INT (plus0)
- && (! TARGET_MIPS16
- || mips16_simple_memory_operand (plus1, plus0, mode)))
- return 1;
-
- else
- return 0;
-
-#if 0
- /* We used to allow small symbol refs here (ie, stuff in .sdata
- or .sbss), but this causes some bugs in G++. Also, it won't
- interfere if the MIPS linker rewrites the store instruction
- because the function is PIC. */
-
- case LABEL_REF: /* never gp relative */
- break;
-
- case CONST:
- /* If -G 0, we can never have a GP relative memory operation.
- Also, save some time if not optimizing. */
- if (!TARGET_GP_OPT)
- return 0;
-
- {
- rtx offset = const0_rtx;
- addr = eliminate_constant_term (XEXP (addr, 0), &offset);
- if (GET_CODE (op) != SYMBOL_REF)
- return 0;
-
- /* let's be paranoid.... */
- if (! SMALL_INT (offset))
- return 0;
- }
-
- /* fall through */
-
- case SYMBOL_REF:
- return SYMBOL_REF_FLAG (addr);
-#endif
-
- /* This SYMBOL_REF case is for the mips16. If the above case is
- reenabled, this one should be merged in. */
- case SYMBOL_REF:
- /* References to the constant pool on the mips16 use a small
- offset if the function is small. The only time we care about
- getting this right is during delayed branch scheduling, so
- don't need to check until then. The machine_dependent_reorg
- function will set the total length of the instructions used
- in the function (cfun->machine->insns_len). If that is small
- enough, we know for sure that this is a small offset. It
- would be better if we could take into account the location of
- the instruction within the function, but we can't, because we
- don't know where we are. */
- if (TARGET_MIPS16
- && CONSTANT_POOL_ADDRESS_P (addr)
- && cfun->machine->insns_len > 0)
- {
- long size;
-
- size = cfun->machine->insns_len + get_pool_size ();
- if (GET_MODE_SIZE (mode) == 4)
- return size < 4 * 0x100;
- else if (GET_MODE_SIZE (mode) == 8)
- return size < 8 * 0x20;
- else
- return 0;
- }
-
- return 0;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/* Return nonzero for a memory address that can be used to load or store
- a doubleword. */
-
-int
-double_memory_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- if (GET_CODE (op) != MEM
- || ! memory_operand (op, mode))
- {
- /* During reload, we accept a pseudo register if it has an
- appropriate memory address. If we don't do this, we will
- wind up reloading into a register, and then reloading that
- register from memory, when we could just reload directly from
- memory. */
- if (reload_in_progress
- && GET_CODE (op) == REG
- && REGNO (op) >= FIRST_PSEUDO_REGISTER
- && reg_renumber[REGNO (op)] < 0
- && reg_equiv_mem[REGNO (op)] != 0
- && double_memory_operand (reg_equiv_mem[REGNO (op)], mode))
- return 1;
-
- /* All reloaded addresses are valid in TARGET_64BIT mode. This is
- the same test performed for 'm' in find_reloads. */
-
- if (reload_in_progress
- && TARGET_64BIT
- && (GET_CODE (op) == MEM
- || (GET_CODE (op) == REG
- && REGNO (op) >= FIRST_PSEUDO_REGISTER
- && reg_renumber[REGNO (op)] < 0)))
- return 1;
-
- if (reload_in_progress
- && TARGET_MIPS16
- && GET_CODE (op) == MEM)
- {
- rtx addr;
-
- addr = XEXP (op, 0);
-
- /* During reload on the mips16, we accept a large offset
- from the frame pointer or the stack pointer. This large
- address will get reloaded anyhow. */
- if (GET_CODE (addr) == PLUS
- && GET_CODE (XEXP (addr, 0)) == REG
- && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
- || REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
- && ((GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ! SMALL_INT (XEXP (addr, 1)))
- || (GET_CODE (XEXP (addr, 1)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (addr, 1)))))
- return 1;
-
- /* Similarly, we accept a case where the memory address is
- itself on the stack, and will be reloaded. */
- if (GET_CODE (addr) == MEM)
- {
- rtx maddr;
-
- maddr = XEXP (addr, 0);
- if (GET_CODE (maddr) == PLUS
- && GET_CODE (XEXP (maddr, 0)) == REG
- && (REGNO (XEXP (maddr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
- || REGNO (XEXP (maddr, 0)) == STACK_POINTER_REGNUM)
- && ((GET_CODE (XEXP (maddr, 1)) == CONST_INT
- && ! SMALL_INT (XEXP (maddr, 1)))
- || (GET_CODE (XEXP (maddr, 1)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (maddr, 1)))))
- return 1;
- }
-
- /* We also accept the same case when we have a 16 bit signed
- offset mixed in as well. The large address will get
- reloaded, and the 16 bit offset will be OK. */
- if (GET_CODE (addr) == PLUS
- && GET_CODE (XEXP (addr, 0)) == MEM
- && GET_CODE (XEXP (addr, 1)) == CONST_INT
- && SMALL_INT (XEXP (addr, 1)))
- {
- addr = XEXP (XEXP (addr, 0), 0);
- if (GET_CODE (addr) == PLUS
- && GET_CODE (XEXP (addr, 0)) == REG
- && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
- || REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
- && ((GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ! SMALL_INT (XEXP (addr, 1)))
- || (GET_CODE (XEXP (addr, 1)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (addr, 1)))))
- return 1;
- }
- }
-
- return 0;
- }
-
- if (TARGET_64BIT)
- {
- /* In this case we can use an instruction like sd. */
- return 1;
- }
-
- /* Make sure that 4 added to the address is a valid memory address.
- This essentially just checks for overflow in an added constant. */
-
- if (CONSTANT_ADDRESS_P (XEXP (op, 0)))
- return 1;
-
- op = adjust_address_nv (op, GET_MODE_CLASS (mode) == MODE_INT
- ? SImode : SFmode, 4);
- return memory_address_p (GET_MODE (op), XEXP (op, 0));
-}
-
/* Return nonzero if the code of this rtx pattern is EQ or NE. */
int
@@ -1201,23 +1522,38 @@ pc_or_label_operand (op, mode)
return 0;
}
-/* Test for a valid operand for a call instruction.
- Don't allow the arg pointer register or virtual regs
- since they may change into reg + const, which the patterns
- can't handle yet. */
+/* Test for a valid call address. */
int
call_insn_operand (op, mode)
rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode;
{
- return (CONSTANT_ADDRESS_P (op)
- || (GET_CODE (op) == REG && op != arg_pointer_rtx
- && ! (REGNO (op) >= FIRST_PSEUDO_REGISTER
- && REGNO (op) <= LAST_VIRTUAL_REGISTER)));
+ struct mips_constant_info c;
+
+ if (mips_classify_constant (&c, op) == CONSTANT_SYMBOLIC)
+ switch (mips_classify_symbol (c.symbol))
+ {
+ case SYMBOL_GENERAL:
+ /* If -mlong-calls, force all calls to use register addressing. */
+ return !TARGET_LONG_CALLS;
+
+ case SYMBOL_GOT_GLOBAL:
+ /* Calls to global symbols should use R_MIPS_CALL* relocations
+ where possible. By keeping the address with the call, we
+ force reload to put it directly into $25, which in turn
+ causes GAS to use R_MIPS_CALL16 relocs. */
+ /* ??? The SGI o32 assembler doesn't seem to work like this. */
+ return c.offset == 0;
+
+ default:
+ return false;
+ }
+ return register_operand (op, mode);
}
-/* Return nonzero if OPERAND is valid as a source operand for a move
+
+/* Return nonzero if OP is valid as a source operand for a move
instruction. */
int
@@ -1225,17 +1561,14 @@ move_operand (op, mode)
rtx op;
enum machine_mode mode;
{
- /* Accept any general operand after reload has started; doing so
- avoids losing if reload does an in-place replacement of a register
- with a SYMBOL_REF or CONST. */
- return (general_operand (op, mode)
- && (! (mips_split_addresses && mips_check_split (op, mode))
- || reload_in_progress || reload_completed)
- && ! (TARGET_MIPS16
- && GET_CODE (op) == SYMBOL_REF
- && ! mips16_constant (op, mode, 1, 0)));
+ struct mips_constant_info c;
+
+ if (mips_classify_constant (&c, op) == CONSTANT_SYMBOLIC)
+ return mips_symbolic_address_p (c.symbol, c.offset, word_mode, 1);
+ return general_operand (op, mode);
}
+
/* Accept any operand that can appear in a mips16 constant table
instruction. We can't use any of the standard operand functions
because for these instructions we accept values that are not
@@ -1277,194 +1610,191 @@ coprocessor2_operand (op, mode)
int
symbolic_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
- if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
- return 0;
- if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
- return 1;
- if (GET_CODE (op) == CONST
- && GET_CODE (XEXP (op,0)) == PLUS
- && GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT)
- return 1;
- return 0;
-}
+ struct mips_constant_info c;
-/* Return nonzero if we split the address into high and low parts. */
+ return mips_classify_constant (&c, op) == CONSTANT_SYMBOLIC;
+}
-/* ??? We should also handle reg+array somewhere. We get four
- instructions currently, lui %hi/addui %lo/addui reg/lw. Better is
- lui %hi/addui reg/lw %lo. Fixing GO_IF_LEGITIMATE_ADDRESS to accept
- (plus (reg) (symbol_ref)) doesn't work because the SYMBOL_REF is broken
- out of the address, then we have 4 instructions to combine. Perhaps
- add a 3->2 define_split for combine. */
-/* ??? We could also split a CONST_INT here if it is a large_int().
- However, it doesn't seem to be very useful to have %hi(constant).
- We would be better off by doing the masking ourselves and then putting
- the explicit high part of the constant in the RTL. This will give better
- optimization. Also, %hi(constant) needs assembler changes to work.
- There is already a define_split that does this. */
+/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
+ returns a nonzero value if X is a legitimate address for a memory
+ operand of the indicated MODE. STRICT is nonzero if this function
+ is called during reload. */
-int
-mips_check_split (address, mode)
- rtx address;
+bool
+mips_legitimate_address_p (mode, x, strict)
enum machine_mode mode;
+ rtx x;
+ int strict;
{
- /* ??? This is the same check used in simple_memory_operand.
- We use it here because LO_SUM is not offsettable. */
- if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD)
- return 0;
+ struct mips_address_info addr;
- if ((GET_CODE (address) == SYMBOL_REF && ! SYMBOL_REF_FLAG (address))
- || (GET_CODE (address) == CONST
- && GET_CODE (XEXP (XEXP (address, 0), 0)) == SYMBOL_REF
- && ! SYMBOL_REF_FLAG (XEXP (XEXP (address, 0), 0)))
- || GET_CODE (address) == LABEL_REF)
- return 1;
+ return mips_classify_address (&addr, x, mode, strict, 0) != ADDRESS_INVALID;
+}
- return 0;
+
+/* Copy VALUE to a register and return that register. Use DEST as the
+ register if non-null, otherwise create a new one. MODE is the mode
+ of VALUE. */
+
+static rtx
+mips_force_temporary (mode, dest, value)
+ enum machine_mode mode;
+ rtx dest, value;
+{
+ if (dest != 0)
+ {
+ emit_move_insn (copy_rtx (dest), value);
+ return dest;
+ }
+ return force_reg (mode, value);
}
-/* This function is used to implement REG_MODE_OK_FOR_BASE_P. */
-int
-mips_reg_mode_ok_for_base_p (reg, mode, strict)
+/* Return a legitimate address for REG + OFFSET. This function will
+ create a temporary register if OFFSET is not a SMALL_OPERAND. */
+
+static rtx
+mips_add_offset (reg, offset)
rtx reg;
- enum machine_mode mode;
- int strict;
+ HOST_WIDE_INT offset;
{
- return (strict
- ? REGNO_MODE_OK_FOR_BASE_P (REGNO (reg), mode)
- : GP_REG_OR_PSEUDO_NONSTRICT_P (REGNO (reg), mode));
+ if (!SMALL_OPERAND (offset))
+ reg = expand_simple_binop (GET_MODE (reg), PLUS,
+ GEN_INT (CONST_HIGH_PART (offset)),
+ reg, NULL, 0, OPTAB_WIDEN);
+
+ return plus_constant (reg, CONST_LOW_PART (offset));
}
-/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
- returns a nonzero value if XINSN is a legitimate address for a
- memory operand of the indicated MODE. STRICT is nonzero if this
- function is called during reload. */
-int
-mips_legitimate_address_p (mode, xinsn, strict)
+/* See if *XLOC is a symbolic constant that can be reduced in some way.
+ If it is, set *XLOC to the reduced expression and return true.
+ The new expression will be both a legitimate address and a legitimate
+ source operand for a mips.md SET pattern. If OFFSETABLE_P, the
+ address will be offsetable.
+
+ DEST is a register to use a temporary, or null if new registers
+ can be created at will. */
+
+static bool
+mips_legitimize_symbol (dest, xloc, offsetable_p)
+ rtx dest, *xloc;
+ int offsetable_p;
+{
+ struct mips_constant_info c;
+ enum mips_symbol_type symbol_type;
+ enum machine_mode mode;
+
+ if (mips_classify_constant (&c, *xloc) != CONSTANT_SYMBOLIC)
+ return false;
+
+ mode = GET_MODE (c.symbol);
+ symbol_type = mips_classify_symbol (c.symbol);
+
+ /* Convert a mips16 reference to the small data section into
+ an address of the form:
+
+ (plus BASE (const (plus (unspec [SYMBOL] UNSPEC_GPREL) OFFSET)))
+
+ BASE is the pseudo created by mips16_gp_pseudo_reg.
+ The (const ...) may include an offset. */
+ if (TARGET_MIPS16
+ && symbol_type == SYMBOL_SMALL_DATA
+ && !no_new_pseudos)
+ {
+ *xloc = gen_rtx_PLUS (mode, gen_lowpart (mode, mips16_gp_pseudo_reg ()),
+ plus_constant (gen_reloc_gprel16 (c.symbol),
+ c.offset));
+ return true;
+ }
+
+ /* If a non-offsetable address is OK, convert general symbols into
+ a HIGH/LO_SUM pair. */
+ if (mips_split_addresses
+ && symbol_type == SYMBOL_GENERAL
+ && !offsetable_p)
+ {
+ rtx high;
+
+ high = mips_force_temporary (mode, dest, gen_rtx_HIGH (mode, *xloc));
+ *xloc = gen_rtx_LO_SUM (mode, high, copy_rtx (*xloc));
+ return true;
+ }
+
+ /* See if the symbol has an offset that must be added separately.
+ Adding large constants needs a temporary register. */
+ if (!move_operand (*xloc, mode)
+ && move_operand (c.symbol, mode)
+ && (SMALL_OPERAND (c.offset) || dest == 0))
+ {
+ *xloc = mips_add_offset (mips_force_temporary (mode, dest, c.symbol),
+ c.offset);
+ return true;
+ }
+ return false;
+}
+
+
+/* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
+ be legitimized in a way that the generic machinery might not expect,
+ put the new address in *XLOC and return true. MODE is the mode of
+ the memory being accessed. */
+
+bool
+mips_legitimize_address (xloc, mode)
+ rtx *xloc;
enum machine_mode mode;
- rtx xinsn;
- int strict;
{
- if (TARGET_DEBUG_B_MODE)
+ if (mips_legitimize_symbol (0, xloc, !SINGLE_WORD_MODE_P (mode)))
+ return true;
+
+ if (GET_CODE (*xloc) == PLUS && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
{
- GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
- strict ? "" : "not ");
- GO_DEBUG_RTX (xinsn);
+ /* Handle REG + CONSTANT using mips_add_offset. */
+ rtx reg;
+
+ reg = XEXP (*xloc, 0);
+ if (!mips_valid_base_register_p (reg, mode, 0))
+ reg = copy_to_mode_reg (Pmode, reg);
+ *xloc = mips_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
+ return true;
}
- /* Check for constant before stripping off SUBREG, so that we don't
- accept (subreg (const_int)) which will fail to reload. */
- if (CONSTANT_ADDRESS_P (xinsn)
- && ! (mips_split_addresses && mips_check_split (xinsn, mode))
- && (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0)))
- return 1;
+ return false;
+}
- while (GET_CODE (xinsn) == SUBREG)
- xinsn = SUBREG_REG (xinsn);
- /* The mips16 can only use the stack pointer as a base register when
- loading SImode or DImode values. */
- if (GET_CODE (xinsn) == REG
- && mips_reg_mode_ok_for_base_p (xinsn, mode, strict))
- return 1;
+/* If (set DEST SRC) is not a valid instruction, emit an equivalent
+ sequence that is valid. */
- if (GET_CODE (xinsn) == LO_SUM && mips_split_addresses)
- {
- register rtx xlow0 = XEXP (xinsn, 0);
- register rtx xlow1 = XEXP (xinsn, 1);
-
- while (GET_CODE (xlow0) == SUBREG)
- xlow0 = SUBREG_REG (xlow0);
- if (GET_CODE (xlow0) == REG
- && mips_reg_mode_ok_for_base_p (xlow0, mode, strict)
- && mips_check_split (xlow1, mode))
- return 1;
- }
-
- if (GET_CODE (xinsn) == PLUS)
- {
- register rtx xplus0 = XEXP (xinsn, 0);
- register rtx xplus1 = XEXP (xinsn, 1);
- register enum rtx_code code0;
- register enum rtx_code code1;
-
- while (GET_CODE (xplus0) == SUBREG)
- xplus0 = SUBREG_REG (xplus0);
- code0 = GET_CODE (xplus0);
-
- while (GET_CODE (xplus1) == SUBREG)
- xplus1 = SUBREG_REG (xplus1);
- code1 = GET_CODE (xplus1);
-
- /* The mips16 can only use the stack pointer as a base register
- when loading SImode or DImode values. */
- if (code0 == REG
- && mips_reg_mode_ok_for_base_p (xplus0, mode, strict))
- {
- if (code1 == CONST_INT && SMALL_INT (xplus1))
- return 1;
-
- /* On the mips16, we represent GP relative offsets in RTL.
- These are 16 bit signed values, and can serve as register
- offsets. */
- if (TARGET_MIPS16
- && mips16_gp_offset_p (xplus1))
- return 1;
-
- /* For some code sequences, you actually get better code by
- pretending that the MIPS supports an address mode of a
- constant address + a register, even though the real
- machine doesn't support it. This is because the
- assembler can use $r1 to load just the high 16 bits, add
- in the register, and fold the low 16 bits into the memory
- reference, whereas the compiler generates a 4 instruction
- sequence. On the other hand, CSE is not as effective.
- It would be a win to generate the lui directly, but the
- MIPS assembler does not have syntax to generate the
- appropriate relocation. */
-
- /* Also accept CONST_INT addresses here, so no else. */
- /* Reject combining an embedded PIC text segment reference
- with a register. That requires an additional
- instruction. */
- /* ??? Reject combining an address with a register for the MIPS
- 64 bit ABI, because the SGI assembler can not handle this. */
- if (!TARGET_DEBUG_A_MODE
- && (mips_abi == ABI_32
- || mips_abi == ABI_O64
- || mips_abi == ABI_EABI)
- && CONSTANT_ADDRESS_P (xplus1)
- && ! mips_split_addresses
- && (!TARGET_EMBEDDED_PIC
- || code1 != CONST
- || GET_CODE (XEXP (xplus1, 0)) != MINUS)
- /* When assembling for machines with 64 bit registers,
- the assembler will sign-extend the constant "foo"
- in "la x, foo(x)" yielding the wrong result for:
- (set (blah:DI) (plus x y)). */
- && (!TARGET_64BIT
- || (code1 == CONST_INT
- && trunc_int_for_mode (INTVAL (xplus1),
- SImode) == INTVAL (xplus1)))
- && !TARGET_MIPS16)
- return 1;
- }
+bool
+mips_legitimize_move (mode, dest, src)
+ enum machine_mode mode;
+ rtx dest, src;
+{
+ if (!register_operand (dest, mode) && !reg_or_0_operand (src, mode))
+ {
+ emit_move_insn (dest, force_reg (mode, src));
+ return true;
}
- if (TARGET_DEBUG_B_MODE)
- GO_PRINTF ("Not a legitimate address\n");
+ if (mips_legitimize_symbol (no_new_pseudos ? dest : 0, &src, false))
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, dest, src));
+ return true;
+ }
- /* The address was not legitimate. */
- return 0;
+ if (CONSTANT_P (src) && !move_operand (src, mode))
+ {
+ emit_move_insn (dest, force_const_mem (mode, src));
+ return true;
+ }
+ return false;
}
-
/* We need a lot of little routines to check constant values on the
mips16. These are used to figure out how long the instruction will
@@ -1613,8 +1943,7 @@ m16_nsimm8_8 (op, mode)
}
/* References to the string table on the mips16 only use a small
- offset if the function is small. See the comment in the SYMBOL_REF
- case in simple_memory_operand. We can't check for LABEL_REF here,
+ offset if the function is small. We can't check for LABEL_REF here,
because the offset is always large if the label is before the
referencing instruction. */
@@ -1943,6 +2272,7 @@ mips_move_1word (operands, insn, unsignedp)
int subreg_offset0 = 0;
int subreg_offset1 = 0;
enum delay_type delay = DELAY_NONE;
+ struct mips_constant_info c;
while (code0 == SUBREG)
{
@@ -2189,46 +2519,6 @@ mips_move_1word (operands, insn, unsignedp)
}
}
- else if (code1 == LABEL_REF)
- {
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 1);
-
- ret = "la\t%0,%a1";
- }
-
- else if (code1 == SYMBOL_REF || code1 == CONST)
- {
- if (TARGET_MIPS16
- && code1 == CONST
- && GET_CODE (XEXP (op1, 0)) == REG
- && REGNO (XEXP (op1, 0)) == GP_REG_FIRST + 28)
- {
- /* This case arises on the mips16; see
- mips16_gp_pseudo_reg. */
- ret = "move\t%0,%+";
- }
- else if (TARGET_MIPS16
- && code1 == SYMBOL_REF
- && SYMBOL_REF_FLAG (op1)
- && (XSTR (op1, 0)[0] != '*'
- || strncmp (XSTR (op1, 0) + 1,
- LOCAL_LABEL_PREFIX,
- sizeof LOCAL_LABEL_PREFIX - 1) != 0))
- {
- /* This can occur when reloading the address of a GP
- relative symbol on the mips16. */
- ret = "move\t%0,%+\n\taddu\t%0,%%gprel(%a1)";
- }
- else
- {
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 1);
-
- ret = "la\t%0,%a1";
- }
- }
-
else if (code1 == PLUS)
{
rtx add_op0 = XEXP (op1, 0);
@@ -2248,6 +2538,27 @@ mips_move_1word (operands, insn, unsignedp)
operands[1] = XEXP (op1, 0);
ret = "lui\t%0,%%hi(%1)";
}
+
+ else
+ switch (mips_classify_constant (&c, op1))
+ {
+ case CONSTANT_NONE:
+ break;
+
+ case CONSTANT_GP:
+ ret = "move\t%0,%1";
+ break;
+
+ case CONSTANT_RELOC:
+ ret = (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
+ break;
+
+ case CONSTANT_SYMBOLIC:
+ if (TARGET_STATS)
+ mips_count_memory_refs (op1, 1);
+ ret = "la\t%0,%a1";
+ break;
+ }
}
else if (code0 == MEM)
@@ -2349,7 +2660,7 @@ mips_restore_gp (operands, insn)
else
loc = stack_pointer_rtx;
loc = plus_constant (loc, cfun->machine->frame.args_size);
- operands[1] = gen_rtx_MEM (Pmode, loc);
+ operands[1] = gen_rtx_MEM (ptr_mode, loc);
return mips_move_1word (operands, insn, 0);
}
@@ -2396,6 +2707,7 @@ mips_move_2words (operands, insn)
int subreg_offset0 = 0;
int subreg_offset1 = 0;
enum delay_type delay = DELAY_NONE;
+ struct mips_constant_info c;
if (code1 == SIGN_EXTEND)
return mips_sign_extend (insn, op0, XEXP (op1, 0));
@@ -2722,15 +3034,13 @@ mips_move_2words (operands, insn)
#ifdef TARGET_FP_CALL_32
if (FP_CALL_GP_REG_P (regno0))
- ret = (double_memory_operand (op1, GET_MODE (op1))
- ? "lwu\t%0,%1\n\tlwu\t%D0,4+%1"
- : "ld\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32");
+ ret = "lwu\t%0,%1\n\tlwu\t%D0,4+%1";
else
#endif
ret = "ld\t%0,%1";
}
- else if (double_memory_operand (op1, GET_MODE (op1)))
+ else
ret = (reg_mentioned_p (op0, op1)
? "lw\t%D0,%D1\n\tlw\t%0,%1"
: "lw\t%0,%1\n\tlw\t%D0,%D1");
@@ -2746,59 +3056,31 @@ mips_move_2words (operands, insn)
ret = volatile_buffer;
}
}
-
- else if (code1 == LABEL_REF)
+ else if (code1 == HIGH)
{
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 2);
+ operands[1] = XEXP (op1, 0);
+ ret = "lui\t%0,%%hi(%1)";
+ }
+ else
+ switch (mips_classify_constant (&c, op1))
+ {
+ case CONSTANT_NONE:
+ break;
- if (GET_CODE (operands[1]) == SIGN_EXTEND)
- /* We deliberately remove the 'a' from '%1', so that we don't
- have to add SIGN_EXTEND support to print_operand_address.
- print_operand will just call print_operand_address in this
- case, so there is no problem. */
- ret = "la\t%0,%1";
- else
+ case CONSTANT_GP:
+ ret = "move\t%0,%1";
+ break;
+
+ case CONSTANT_RELOC:
+ ret = (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
+ break;
+
+ case CONSTANT_SYMBOLIC:
+ if (TARGET_STATS)
+ mips_count_memory_refs (op1, 2);
ret = "dla\t%0,%a1";
- }
- else if (code1 == SYMBOL_REF || code1 == CONST)
- {
- if (TARGET_MIPS16
- && code1 == CONST
- && GET_CODE (XEXP (op1, 0)) == REG
- && REGNO (XEXP (op1, 0)) == GP_REG_FIRST + 28)
- {
- /* This case arises on the mips16; see
- mips16_gp_pseudo_reg. */
- ret = "move\t%0,%+";
- }
- else if (TARGET_MIPS16
- && code1 == SYMBOL_REF
- && SYMBOL_REF_FLAG (op1)
- && (XSTR (op1, 0)[0] != '*'
- || strncmp (XSTR (op1, 0) + 1,
- LOCAL_LABEL_PREFIX,
- sizeof LOCAL_LABEL_PREFIX - 1) != 0))
- {
- /* This can occur when reloading the address of a GP
- relative symbol on the mips16. */
- ret = "move\t%0,%+\n\taddu\t%0,%%gprel(%a1)";
- }
- else
- {
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 2);
-
- if (GET_CODE (operands[1]) == SIGN_EXTEND)
- /* We deliberately remove the 'a' from '%1', so that we don't
- have to add SIGN_EXTEND support to print_operand_address.
- print_operand will just call print_operand_address in this
- case, so there is no problem. */
- ret = "la\t%0,%1";
- else
- ret = "dla\t%0,%a1";
- }
- }
+ break;
+ }
}
else if (code0 == MEM)
@@ -2828,15 +3110,13 @@ mips_move_2words (operands, insn)
ret = "sd\t%1,%0";
}
- else if (double_memory_operand (op0, GET_MODE (op0)))
+ else
ret = "sw\t%1,%0\n\tsw\t%D1,%D0";
}
else if (((code1 == CONST_INT && INTVAL (op1) == 0)
|| (code1 == CONST_DOUBLE
- && op1 == CONST0_RTX (GET_MODE (op1))))
- && (TARGET_64BIT
- || double_memory_operand (op0, GET_MODE (op0))))
+ && op1 == CONST0_RTX (GET_MODE (op1)))))
{
if (TARGET_64BIT)
ret = "sd\t%.,%0";
@@ -2871,92 +3151,6 @@ mips_move_2words (operands, insn)
return ret;
}
-/* Provide the costs of an addressing mode that contains ADDR.
- If ADDR is not a valid address, its cost is irrelevant. */
-
-int
-mips_address_cost (addr)
- rtx addr;
-{
- switch (GET_CODE (addr))
- {
- case LO_SUM:
- return 1;
-
- case LABEL_REF:
- return 2;
-
- case CONST:
- {
- rtx offset = const0_rtx;
- addr = eliminate_constant_term (XEXP (addr, 0), &offset);
- if (GET_CODE (addr) == LABEL_REF)
- return 2;
-
- if (GET_CODE (addr) != SYMBOL_REF)
- return 4;
-
- if (! SMALL_INT (offset))
- return 2;
- }
-
- /* ... fall through ... */
-
- case SYMBOL_REF:
- return SYMBOL_REF_FLAG (addr) ? 1 : 2;
-
- case PLUS:
- {
- register rtx plus0 = XEXP (addr, 0);
- register rtx plus1 = XEXP (addr, 1);
-
- if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)
- plus0 = XEXP (addr, 1), plus1 = XEXP (addr, 0);
-
- if (GET_CODE (plus0) != REG)
- break;
-
- switch (GET_CODE (plus1))
- {
- case CONST_INT:
- return SMALL_INT (plus1) ? 1 : 2;
-
- case CONST:
- case SYMBOL_REF:
- case LABEL_REF:
- case HIGH:
- case LO_SUM:
- return mips_address_cost (plus1) + 1;
-
- default:
- break;
- }
- }
-
- default:
- break;
- }
-
- return 4;
-}
-
-/* Return nonzero if X is an address which needs a temporary register when
- reloaded while generating PIC code. */
-
-int
-pic_address_needs_scratch (x)
- rtx x;
-{
- /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
- if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
- return 1;
-
- return 0;
-}
-
/* Make normal rtx_code into something we can index from an array */
static enum internal_test
@@ -3434,6 +3628,54 @@ mips_gen_conditional_trap (operands)
operands[1]));
}
+/* Expand a call or call_value instruction. RESULT is where the
+ result will go (null for calls), ADDR is the address of the
+ function, ARGS_SIZE is the size of the arguments and AUX is
+ the value passed to us by mips_function_arg. */
+
+void
+mips_expand_call (result, addr, args_size, aux)
+ rtx result, addr, args_size, aux;
+{
+ int i;
+
+ if (!call_insn_operand (addr, VOIDmode))
+ addr = force_reg (Pmode, addr);
+
+ /* In order to pass small structures by value in registers
+ compatibly with the MIPS compiler, we need to shift the value
+ into the high part of the register. Function_arg has encoded
+ a PARALLEL rtx, holding a vector of adjustments to be made
+ as the next_arg_reg variable, so we split up the insns,
+ and emit them separately. */
+ if (aux != 0 && GET_CODE (aux) == PARALLEL)
+ for (i = 0; i < XVECLEN (aux, 0); i++)
+ emit_insn (XVECEXP (aux, 0, i));
+
+ if (TARGET_MIPS16
+ && mips16_hard_float
+ && build_mips16_call_stub (result, addr, args_size,
+ aux == 0 ? 0 : (int) GET_MODE (aux)))
+ /* Nothing more to do */;
+ else if (result == 0)
+ emit_call_insn (gen_call_internal (addr, args_size));
+ else if (GET_CODE (result) == PARALLEL && XVECLEN (result, 0) == 2)
+ {
+ rtx reg1, reg2;
+
+ reg1 = XEXP (XVECEXP (result, 0, 0), 0);
+ reg2 = XEXP (XVECEXP (result, 0, 1), 0);
+ emit_call_insn (gen_call_value_multiple_internal (reg1, addr,
+ args_size, reg2));
+ }
+ else
+ emit_call_insn (gen_call_value_internal (result, addr, args_size));
+
+ /* ??? Should represent what this instruction does in rtl. */
+ if (TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64))
+ emit_insn (gen_exception_receiver ());
+}
+
/* Return true if operand OP is a condition code register.
Only for use during or after reload. */
@@ -5127,7 +5369,8 @@ override_options ()
if (TARGET_ABICALLS)
{
mips_abicalls = MIPS_ABICALLS_YES;
- flag_pic = 1;
+ if (flag_pic == 0)
+ flag_pic = 1;
if (mips_section_threshold > 0)
warning ("-G is incompatible with PIC code which is the default");
}
@@ -5165,8 +5408,9 @@ override_options ()
standard linker for this configuration. */
/* ??? This does not work when target addresses are DImode.
This is because we are missing DImode high/lo_sum patterns. */
- if (TARGET_GAS && ! TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES && optimize && ! flag_pic
- && Pmode == SImode)
+ if (TARGET_GAS && ! TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES
+ && optimize && ! flag_pic
+ && !ABI_HAS_64BIT_SYMBOLS)
mips_split_addresses = 1;
else
mips_split_addresses = 0;
@@ -5243,6 +5487,9 @@ override_options ()
mips_char_to_class['a'] = HILO_REG;
mips_char_to_class['x'] = MD_REGS;
mips_char_to_class['b'] = ALL_REGS;
+ mips_char_to_class['c'] = (TARGET_ABICALLS ? PIC_FN_ADDR_REG :
+ TARGET_MIPS16 ? M16_NA_REGS :
+ GR_REGS);
mips_char_to_class['y'] = GR_REGS;
mips_char_to_class['z'] = ST_REGS;
mips_char_to_class['B'] = COP0_REGS;
@@ -5534,6 +5781,7 @@ print_operand (file, op, letter)
int letter; /* %<letter> or 0 */
{
register enum rtx_code code;
+ struct mips_constant_info c;
if (PRINT_OPERAND_PUNCT_VALID_P (letter))
{
@@ -5805,119 +6053,75 @@ print_operand (file, op, letter)
else if (letter == 't')
fputs (code == EQ ? "t" : "f", file);
- else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
- {
- /* This case arises on the mips16; see mips16_gp_pseudo_reg. */
- print_operand (file, XEXP (op, 0), letter);
- }
-
- else if (TARGET_MIPS16 && code == CONST && mips16_gp_offset_p (op))
- {
- fputs ("%gprel(", file);
- mips16_output_gp_offset (file, op);
- fputs (")", file);
- }
-
- else
- output_addr_const (file, op);
-}
-
-/* A C compound statement to output to stdio stream STREAM the
- assembler syntax for an instruction operand that is a memory
- reference whose address is ADDR. ADDR is an RTL expression. */
-
-void
-print_operand_address (file, addr)
- FILE *file;
- rtx addr;
-{
- if (!addr)
- error ("PRINT_OPERAND_ADDRESS, null pointer");
-
else
- switch (GET_CODE (addr))
+ switch (mips_classify_constant (&c, op))
{
- case REG:
- if (! TARGET_MIPS16 && REGNO (addr) == ARG_POINTER_REGNUM)
- abort_with_insn (addr, "arg pointer not eliminated");
-
- fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
+ case CONSTANT_NONE:
+ case CONSTANT_SYMBOLIC:
+ output_addr_const (file, op);
break;
- case LO_SUM:
- {
- register rtx arg0 = XEXP (addr, 0);
- register rtx arg1 = XEXP (addr, 1);
-
- if (! mips_split_addresses)
- abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, Spurious LO_SUM");
-
- if (GET_CODE (arg0) != REG)
- abort_with_insn (addr,
- "PRINT_OPERAND_ADDRESS, LO_SUM with #1 not REG");
+ case CONSTANT_GP:
+ fputs (reg_names[GP_REG_FIRST + 28], file);
+ break;
- fprintf (file, "%%lo(");
- print_operand_address (file, arg1);
- fprintf (file, ")(%s)", reg_names [REGNO (arg0)]);
- }
+ case CONSTANT_RELOC:
+ mips_print_relocation (file, c.symbol, c.offset);
break;
+ }
+}
+
+static void
+mips_print_relocation (file, symbol, offset)
+ FILE *file;
+ rtx symbol;
+ int offset;
+{
+ switch (XINT (symbol, 1))
+ {
+ case UNSPEC_RELOC_GPREL16:
+ fputs ("%gprel(", file);
+ break;
- case PLUS:
- {
- register rtx reg = 0;
- register rtx offset = 0;
- register rtx arg0 = XEXP (addr, 0);
- register rtx arg1 = XEXP (addr, 1);
+ default:
+ abort ();
+ }
+ output_addr_const (file, plus_constant (XVECEXP (symbol, 0, 0), offset));
+ fputc (')', file);
+}
- if (GET_CODE (arg0) == REG)
- {
- reg = arg0;
- offset = arg1;
- if (GET_CODE (offset) == REG)
- abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs");
- }
- else if (GET_CODE (arg1) == REG)
- reg = arg1, offset = arg0;
- else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
- {
- output_addr_const (file, addr);
- break;
- }
- else
- abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs");
+/* Output address operand X to FILE. */
- if (! CONSTANT_P (offset))
- abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #2");
+void
+print_operand_address (file, x)
+ FILE *file;
+ rtx x;
+{
+ struct mips_address_info addr;
- if (REGNO (reg) == ARG_POINTER_REGNUM)
- abort_with_insn (addr, "arg pointer not eliminated");
+ switch (mips_classify_address (&addr, x, word_mode, 1, 1))
+ {
+ case ADDRESS_INVALID:
+ abort ();
- if (TARGET_MIPS16
- && GET_CODE (offset) == CONST
- && mips16_gp_offset_p (offset))
- {
- fputs ("%gprel(", file);
- mips16_output_gp_offset (file, offset);
- fputs (")", file);
- }
- else
- output_addr_const (file, offset);
- fprintf (file, "(%s)", reg_names [REGNO (reg)]);
- }
- break;
+ case ADDRESS_REG:
+ print_operand (file, addr.offset, 0);
+ fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]);
+ return;
- case LABEL_REF:
- case SYMBOL_REF:
- case CONST_INT:
- case CONST:
- output_addr_const (file, addr);
- break;
+ case ADDRESS_LO_SUM:
+ fputs ("%lo(", file);
+ output_addr_const (file, addr.offset);
+ fprintf (file, ")(%s)", reg_names[REGNO (addr.reg)]);
+ return;
- default:
- abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #1");
- break;
+ case ADDRESS_CONST_INT:
+ case ADDRESS_SYMBOLIC:
+ output_addr_const (file, x);
+ return;
}
+ abort ();
}
/* Target hook for assembling integer objects. It appears that the Irix
@@ -7190,10 +7394,15 @@ mips_output_function_prologue (file, size)
reg_names[PIC_FUNCTION_ADDR_REGNUM]);
if (tsize > 0)
{
+ /* ??? No longer needed here, but clean it up in a
+ separate patch. */
fprintf (file, "\t%s\t%s,%s,%ld\n",
- (Pmode == DImode ? "dsubu" : "subu"),
+ (ptr_mode == DImode ? "dsubu" : "subu"),
sp_str, sp_str, (long) tsize);
- fprintf (file, "\t.cprestore %ld\n", cfun->machine->frame.args_size);
+ fprintf (file, "\t%s\t%s,%d(%s)\n",
+ (ptr_mode == DImode ? "sd" : "sw"),
+ reg_names[PIC_OFFSET_TABLE_REGNUM],
+ (int) cfun->machine->frame.args_size, sp_str);
}
if (dwarf2out_do_frame ())
@@ -7764,7 +7973,7 @@ mips_expand_epilogue ()
if (tsize != 0 || current_function_calls_eh_return)
{
- if (!TARGET_MIPS16)
+ if (!TARGET_MIPS16 || !current_function_calls_eh_return)
{
if (Pmode == DImode)
emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
@@ -8062,6 +8271,13 @@ mips_encode_section_info (decl, first)
SYMBOL_REF_FLAG (XEXP (TREE_CST_RTL (decl), 0)) = 1;
}
+ else if (TARGET_ABICALLS)
+ {
+ /* Mark the symbol if it is not local to this compilation unit. */
+ if (DECL_P (decl))
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = TREE_PUBLIC (decl);
+ }
+
else if (TREE_CODE (decl) == VAR_DECL
&& DECL_SECTION_NAME (decl) != NULL_TREE
&& (0 == strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
@@ -8514,205 +8730,6 @@ mips16_gp_pseudo_reg ()
return cfun->machine->mips16_gp_pseudo_rtx;
}
-/* Return an RTX which represents the signed 16 bit offset from the
- $gp register for the given symbol. This is only used on the
- mips16. */
-
-rtx
-mips16_gp_offset (sym)
- rtx sym;
-{
- tree gp;
-
- if (GET_CODE (sym) != SYMBOL_REF
- || ! SYMBOL_REF_FLAG (sym))
- abort ();
-
- /* We use a special identifier to represent the value of the gp
- register. */
- gp = get_identifier ("__mips16_gp_value");
-
- return gen_rtx (CONST, Pmode,
- gen_rtx (MINUS, Pmode, sym,
- gen_rtx (SYMBOL_REF, Pmode,
- IDENTIFIER_POINTER (gp))));
-}
-
-/* Return nonzero if the given RTX represents a signed 16 bit offset
- from the $gp register. */
-
-int
-mips16_gp_offset_p (x)
- rtx x;
-{
- if (GET_CODE (x) == CONST)
- x = XEXP (x, 0);
-
- /* It's OK to add a small integer value to a gp offset. */
- if (GET_CODE (x) == PLUS)
- {
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
- && SMALL_INT (XEXP (x, 1)))
- return mips16_gp_offset_p (XEXP (x, 0));
- if (GET_CODE (XEXP (x, 0)) == CONST_INT
- && SMALL_INT (XEXP (x, 0)))
- return mips16_gp_offset_p (XEXP (x, 1));
- return 0;
- }
-
- /* Make sure it is in the form SYM - __mips16_gp_value. */
- return (GET_CODE (x) == MINUS
- && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
- && SYMBOL_REF_FLAG (XEXP (x, 0))
- && GET_CODE (XEXP (x, 1)) == SYMBOL_REF
- && strcmp (XSTR (XEXP (x, 1), 0), "__mips16_gp_value") == 0);
-}
-
-/* Output a GP offset. We don't want to print the subtraction of
- __mips16_gp_value; it is implicitly represented by the %gprel which
- should have been printed by the caller. */
-
-static void
-mips16_output_gp_offset (file, x)
- FILE *file;
- rtx x;
-{
- if (GET_CODE (x) == CONST)
- x = XEXP (x, 0);
-
- if (GET_CODE (x) == PLUS)
- {
- mips16_output_gp_offset (file, XEXP (x, 0));
- fputs ("+", file);
- mips16_output_gp_offset (file, XEXP (x, 1));
- return;
- }
-
- if (GET_CODE (x) == MINUS
- && GET_CODE (XEXP (x, 1)) == SYMBOL_REF
- && strcmp (XSTR (XEXP (x, 1), 0), "__mips16_gp_value") == 0)
- {
- mips16_output_gp_offset (file, XEXP (x, 0));
- return;
- }
-
- output_addr_const (file, x);
-}
-
-/* Return nonzero if a constant should not be output until after the
- function. This is true of most string constants, so that we can
- use a more efficient PC relative reference. However, a static
- inline function may never call assemble_function_end to write out
- the constant pool, so don't try to postpone the constant in that
- case.
-
- ??? It's really a bug that a static inline function can put stuff
- in the constant pool even if the function itself is not output.
-
- We record which string constants we've seen, so that we know which
- ones might use the more efficient reference. */
-
-int
-mips16_constant_after_function_p (x)
- tree x;
-{
- if (TREE_CODE (x) == STRING_CST
- && ! flag_writable_strings
- && current_function_decl != 0
- && ! DECL_DEFER_OUTPUT (current_function_decl)
- && ! (DECL_INLINE (current_function_decl)
- && ((! TREE_PUBLIC (current_function_decl)
- && ! TREE_ADDRESSABLE (current_function_decl)
- && ! flag_keep_inline_functions)
- || DECL_EXTERNAL (current_function_decl))))
- {
- struct string_constant *n;
-
- n = (struct string_constant *) xmalloc (sizeof *n);
- n->label = XSTR (XEXP (TREE_CST_RTL (x), 0), 0);
- n->next = string_constants;
- string_constants = n;
-
- return 1;
- }
-
- return 0;
-}
-
-/* Validate a constant for the mips16. This rejects general symbolic
- addresses, which must be loaded from memory. If ADDR is nonzero,
- this should reject anything which is not a legal address. If
- ADDEND is nonzero, this is being added to something else. */
-
-int
-mips16_constant (x, mode, addr, addend)
- rtx x;
- enum machine_mode mode;
- int addr;
- int addend;
-{
- while (GET_CODE (x) == CONST)
- x = XEXP (x, 0);
-
- switch (GET_CODE (x))
- {
- default:
- return 0;
-
- case PLUS:
- return (mips16_constant (XEXP (x, 0), mode, addr, 1)
- && mips16_constant (XEXP (x, 1), mode, addr, 1));
-
- case SYMBOL_REF:
- if (addr && GET_MODE_SIZE (mode) != 4 && GET_MODE_SIZE (mode) != 8)
- return 0;
- if (CONSTANT_POOL_ADDRESS_P (x))
- return 1;
-
- /* If we aren't looking for a memory address, we can accept a GP
- relative symbol, which will have SYMBOL_REF_FLAG set; movsi
- knows how to handle this. We can always accept a string
- constant, which is the other case in which SYMBOL_REF_FLAG
- will be set. */
- if (! addr
- && ! addend
- && SYMBOL_REF_FLAG (x)
- && mode == (enum machine_mode) Pmode)
- return 1;
-
- /* We can accept a string constant, which will have
- SYMBOL_REF_FLAG set but must be recognized by name to
- distinguish from a GP accessible symbol. The name of a
- string constant will have been generated by
- ASM_GENERATE_INTERNAL_LABEL as called by output_constant_def. */
- if (SYMBOL_REF_FLAG (x))
- {
- const char *name = XSTR (x, 0);
-
- return (name[0] == '*'
- && strncmp (name + 1, LOCAL_LABEL_PREFIX,
- sizeof LOCAL_LABEL_PREFIX - 1) == 0);
- }
-
- return 0;
-
- case LABEL_REF:
- if (addr && GET_MODE_SIZE (mode) != 4 && GET_MODE_SIZE (mode) != 8)
- return 0;
- return 1;
-
- case CONST_INT:
- if (addr && ! addend)
- return 0;
- return INTVAL (x) > - 0x10000 && INTVAL (x) <= 0xffff;
-
- case REG:
- /* We need to treat $gp as a legitimate constant, because
- mips16_gp_pseudo_reg assumes that. */
- return REGNO (x) == GP_REG_FIRST + 28;
- }
-}
-
/* Write out code to move floating point arguments in or out of
general registers. Output the instructions to FILE. FP_CODE is
the code describing which arguments are present (see the comment at
@@ -8884,20 +8901,20 @@ static struct mips16_stub *mips16_stubs;
Similarly, we need a stub if the return value might come back in a
floating point register.
- RETVAL, FNMEM, and ARG_SIZE are the values passed to the call insn
- (RETVAL is NULL if this is call rather than call_value). FP_CODE
+ RETVAL is the location of the return value, or null if this is
+ a call rather than a call_value. FN is the address of the
+ function and ARG_SIZE is the size of the arguments. FP_CODE
is the code built by function_arg. This function returns a nonzero
value if it builds the call instruction itself. */
int
-build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
+build_mips16_call_stub (retval, fn, arg_size, fp_code)
rtx retval;
- rtx fnmem;
+ rtx fn;
rtx arg_size;
int fp_code;
{
int fpret;
- rtx fn;
const char *fnname;
char *secname, *stubname;
struct mips16_stub *l;
@@ -8922,10 +8939,6 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
if (fp_code == 0 && ! fpret)
return 0;
- if (GET_CODE (fnmem) != MEM)
- abort ();
- fn = XEXP (fnmem, 0);
-
/* We don't need to do anything if this is a call to a special
mips16 support function. */
if (GET_CODE (fn) == SYMBOL_REF
@@ -8951,7 +8964,7 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
{
char buf[30];
tree id;
- rtx stub_fn, stub_mem, insn;
+ rtx stub_fn, insn;
/* ??? If this code is modified to support other ABI's, we need
to handle PARALLEL return values here. */
@@ -8963,18 +8976,13 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
fp_code);
id = get_identifier (buf);
stub_fn = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (id));
- stub_mem = gen_rtx (MEM, Pmode, stub_fn);
emit_move_insn (gen_rtx (REG, Pmode, 2), fn);
if (retval == NULL_RTX)
- insn = gen_call_internal0 (stub_mem, arg_size,
- gen_rtx (REG, SImode,
- GP_REG_FIRST + 31));
+ insn = gen_call_internal (stub_fn, arg_size);
else
- insn = gen_call_value_internal0 (retval, stub_mem, arg_size,
- gen_rtx (REG, SImode,
- GP_REG_FIRST + 31));
+ insn = gen_call_value_internal (retval, stub_fn, arg_size);
insn = emit_call_insn (insn);
/* Put the register usage information on the CALL. */
@@ -9172,13 +9180,9 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
rtx insn;
if (retval == NULL_RTX)
- insn = gen_call_internal0 (fnmem, arg_size,
- gen_rtx (REG, SImode,
- GP_REG_FIRST + 31));
+ insn = gen_call_internal (fn, arg_size);
else
- insn = gen_call_value_internal0 (retval, fnmem, arg_size,
- gen_rtx (REG, SImode,
- GP_REG_FIRST + 31));
+ insn = gen_call_value_internal (retval, fn, arg_size);
insn = emit_call_insn (insn);
if (GET_CODE (insn) != CALL_INSN)
@@ -9246,15 +9250,13 @@ mips16_optimize_gp (first)
&& GET_CODE (SET_SRC (set)) == CONST
&& GET_CODE (XEXP (SET_SRC (set), 0)) == REG
&& REGNO (XEXP (SET_SRC (set), 0)) == GP_REG_FIRST + 28
- && GET_CODE (SET_DEST (set)) == REG
- && GET_MODE (SET_DEST (set)) == (unsigned) Pmode)
+ && GET_CODE (SET_DEST (set)) == REG)
gpcopy = SET_DEST (set);
else if (slot == NULL_RTX
&& gpcopy != NULL_RTX
&& GET_CODE (SET_DEST (set)) == MEM
&& GET_CODE (SET_SRC (set)) == REG
- && REGNO (SET_SRC (set)) == REGNO (gpcopy)
- && GET_MODE (SET_DEST (set)) == (unsigned) Pmode)
+ && REGNO (SET_SRC (set)) == REGNO (gpcopy))
{
rtx base, offset;
@@ -9271,7 +9273,6 @@ mips16_optimize_gp (first)
&& reg_overlap_mentioned_p (SET_DEST (set), gpcopy)
&& (GET_CODE (SET_DEST (set)) != REG
|| REGNO (SET_DEST (set)) != REGNO (gpcopy)
- || GET_MODE (SET_DEST (set)) != (unsigned) Pmode
|| ((GET_CODE (SET_SRC (set)) != CONST
|| GET_CODE (XEXP (SET_SRC (set), 0)) != REG
|| (REGNO (XEXP (SET_SRC (set), 0))
@@ -9304,13 +9305,17 @@ mips16_optimize_gp (first)
if (insn != NULL_RTX || gpcopy == NULL_RTX || slot == NULL_RTX)
{
+#if 0
+ /* Used below in #if 0 area. */
rtx next;
-
+#endif
/* This optimization is only reasonable if the constant table
entries are only 4 bytes. */
if (Pmode != SImode)
return;
+#if 0
+ /* ??? FIXME. Rewrite for new UNSPEC_RELOC stuff. */
for (insn = first; insn != NULL_RTX; insn = next)
{
rtx set1, set2;
@@ -9373,10 +9378,10 @@ mips16_optimize_gp (first)
NOTE_SOURCE_FILE (next) = 0;
}
}
+#endif
return;
}
-
/* We can safely remove all assignments to SLOT from GPCOPY, and
replace all assignments from SLOT to GPCOPY with assignments from
$28. */
@@ -9389,8 +9394,7 @@ mips16_optimize_gp (first)
continue;
set = PATTERN (insn);
- if (GET_CODE (set) != SET
- || GET_MODE (SET_DEST (set)) != (unsigned) Pmode)
+ if (GET_CODE (set) != SET)
continue;
if (GET_CODE (SET_DEST (set)) == MEM
@@ -9407,9 +9411,12 @@ mips16_optimize_gp (first)
&& GET_CODE (SET_SRC (set)) == MEM
&& rtx_equal_p (SET_SRC (set), slot))
{
- emit_insn_after (gen_rtx (SET, Pmode, SET_DEST (set),
- gen_rtx (CONST, Pmode,
- gen_rtx (REG, Pmode,
+ enum machine_mode mode;
+
+ mode = GET_MODE (SET_DEST (set));
+ emit_insn_after (gen_rtx (SET, VOIDmode, SET_DEST (set),
+ gen_rtx (CONST, mode,
+ gen_rtx (REG, mode,
GP_REG_FIRST + 28))),
insn);
PUT_CODE (insn, NOTE);
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index a04bef94ed8..4cd11379737 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -779,6 +779,10 @@ extern void sbss_section PARAMS ((void));
/* Likewise for 32-bit regs. */
#define ABI_NEEDS_32BIT_REGS (mips_abi == ABI_32)
+/* True if symbols are 64 bits wide. At present, n64 is the only
+ ABI for which this is true. */
+#define ABI_HAS_64BIT_SYMBOLS (mips_abi == ABI_64)
+
/* ISA has instructions for managing 64 bit fp and gp regs (eg. mips3). */
#define ISA_HAS_64BIT_REGS (ISA_MIPS3 \
|| ISA_MIPS4 \
@@ -1978,6 +1982,7 @@ enum reg_class
M16_REGS, /* mips16 directly accessible registers */
T_REG, /* mips16 T register ($24) */
M16_T_REGS, /* mips16 registers plus T register */
+ PIC_FN_ADDR_REG, /* SVR4 PIC function address register */
GR_REGS, /* integer registers */
FP_REGS, /* floating point registers */
HI_REG, /* hi register */
@@ -2016,6 +2021,7 @@ enum reg_class
"M16_REGS", \
"T_REG", \
"M16_T_REGS", \
+ "PIC_FN_ADDR_REG", \
"GR_REGS", \
"FP_REGS", \
"HI_REG", \
@@ -2057,6 +2063,7 @@ enum reg_class
{ 0x000300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* mips16 registers */ \
{ 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* mips16 T register */ \
{ 0x010300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* mips16 and T regs */ \
+ { 0x02000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* SVR4 PIC function address register */ \
{ 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* integer registers */ \
{ 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* floating registers*/ \
{ 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 }, /* hi register */ \
@@ -2113,7 +2120,8 @@ extern const enum reg_class mips_regno_to_class[];
/* This macro is used later on in the file. */
#define GR_REG_CLASS_P(CLASS) \
((CLASS) == GR_REGS || (CLASS) == M16_REGS || (CLASS) == T_REG \
- || (CLASS) == M16_T_REGS || (CLASS) == M16_NA_REGS)
+ || (CLASS) == M16_T_REGS || (CLASS) == M16_NA_REGS \
+ || (CLASS) == PIC_FN_ADDR_REG)
/* This macro is also used later on in the file. */
#define COP_REG_CLASS_P(CLASS) \
@@ -2172,6 +2180,35 @@ extern enum reg_class mips_char_to_class[256];
#define REG_CLASS_FROM_LETTER(C) mips_char_to_class[(unsigned char)(C)]
+/* True if VALUE is a signed 16-bit number. */
+
+#define SMALL_OPERAND(VALUE) \
+ ((unsigned HOST_WIDE_INT) (VALUE) + 0x8000 < 0x10000)
+
+/* True if VALUE is an unsigned 16-bit number. */
+
+#define SMALL_OPERAND_UNSIGNED(VALUE) \
+ (((VALUE) & ~(unsigned HOST_WIDE_INT) 0xffff) == 0)
+
+/* True if VALUE can be loaded into a register using LUI. */
+
+#define LUI_OPERAND(VALUE) \
+ (((VALUE) | 0x7fff0000) == 0x7fff0000 \
+ || ((VALUE) | 0x7fff0000) + 0x10000 == 0)
+
+/* Return a value X with the low 16 bits clear, and such that
+ VALUE - X is a signed 16-bit value. */
+
+#define CONST_HIGH_PART(VALUE) \
+ (((VALUE) + 0x8000) & ~(unsigned HOST_WIDE_INT) 0xffff)
+
+#define CONST_LOW_PART(VALUE) \
+ ((VALUE) - CONST_HIGH_PART (VALUE))
+
+#define SMALL_INT(X) SMALL_OPERAND (INTVAL (X))
+#define SMALL_INT_UNSIGNED(X) SMALL_OPERAND_UNSIGNED (INTVAL (X))
+#define LUI_INT(X) LUI_OPERAND (INTVAL (X))
+
/* The letters I, J, K, L, M, N, O, and P in a register constraint
string can be used to stand for particular ranges of immediate
operands. This macro defines what the ranges are. C is the
@@ -2200,21 +2237,14 @@ extern enum reg_class mips_char_to_class[256];
`P' is used for positive 16 bit constants. */
-#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) (INTVAL (X) + 0x8000) < 0x10000)
-#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (INTVAL (X)) < 0x10000)
-
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'I' ? ((unsigned HOST_WIDE_INT) ((VALUE) + 0x8000) < 0x10000) \
+ ((C) == 'I' ? SMALL_OPERAND (VALUE) \
: (C) == 'J' ? ((VALUE) == 0) \
- : (C) == 'K' ? ((unsigned HOST_WIDE_INT) (VALUE) < 0x10000) \
- : (C) == 'L' ? (((VALUE) & 0x0000ffff) == 0 \
- && (((VALUE) & ~2147483647) == 0 \
- || ((VALUE) & ~2147483647) == ~2147483647)) \
- : (C) == 'M' ? ((((VALUE) & ~0x0000ffff) != 0) \
- && (((VALUE) & ~0x0000ffff) != ~0x0000ffff) \
- && (((VALUE) & 0x0000ffff) != 0 \
- || (((VALUE) & ~2147483647) != 0 \
- && ((VALUE) & ~2147483647) != ~2147483647))) \
+ : (C) == 'K' ? SMALL_OPERAND_UNSIGNED (VALUE) \
+ : (C) == 'L' ? LUI_OPERAND (VALUE) \
+ : (C) == 'M' ? (!SMALL_OPERAND (VALUE) \
+ && !SMALL_OPERAND_UNSIGNED (VALUE) \
+ && !LUI_OPERAND (VALUE)) \
: (C) == 'N' ? ((unsigned HOST_WIDE_INT) ((VALUE) + 0xffff) < 0xffff) \
: (C) == 'O' ? ((unsigned HOST_WIDE_INT) ((VALUE) + 0x4000) < 0x8000) \
: (C) == 'P' ? ((VALUE) != 0 && (((VALUE) & ~0x0000ffff) == 0)) \
@@ -2237,16 +2267,15 @@ extern enum reg_class mips_char_to_class[256];
operand as its first argument and the constraint letter as its
second operand.
- `Q' is for mips16 GP relative constants
- `R' is for memory references which take 1 word for the instruction.
- `T' is for memory addresses that can be used to load two words. */
+ `Q' is for signed 16-bit constants.
+ `R' is for constant move_operands.
+ `S' is for legitimate constant call addresses. */
#define EXTRA_CONSTRAINT(OP,CODE) \
- (((CODE) == 'T') ? double_memory_operand (OP, GET_MODE (OP)) \
- : ((CODE) == 'Q') ? (GET_CODE (OP) == CONST \
- && mips16_gp_offset_p (OP)) \
- : (GET_CODE (OP) != MEM) ? FALSE \
- : ((CODE) == 'R') ? simple_memory_operand (OP, GET_MODE (OP)) \
+ (((CODE) == 'Q') ? const_arith_operand (OP, VOIDmode) \
+ : ((CODE) == 'R') ? (CONSTANT_P (OP) && move_operand (OP, VOIDmode)) \
+ : ((CODE) == 'S') ? (CONSTANT_P (OP) && !TARGET_ABICALLS \
+ && call_insn_operand (OP, VOIDmode)) \
: FALSE)
/* Given an rtx X being reloaded into a reg required to be
@@ -3015,32 +3044,12 @@ typedef struct mips_args {
}
#endif
-/* A C expression that is 1 if the RTX X is a constant which is a
- valid address. This is defined to be the same as `CONSTANT_P (X)',
- but rejecting CONST_DOUBLE. */
-/* When pic, we must reject addresses of the form symbol+large int.
- This is because an instruction `sw $4,s+70000' needs to be converted
- by the assembler to `lw $at,s($gp);sw $4,70000($at)'. Normally the
- assembler would use $at as a temp to load in the large offset. In this
- case $at is already in use. We convert such problem addresses to
- `la $5,s;sw $4,70000($5)' via LEGITIMIZE_ADDRESS. */
-/* ??? SGI Irix 6 assembler fails for CONST address, so reject them
- when !TARGET_GAS. */
-/* We should be rejecting everything but const addresses. */
-#define CONSTANT_ADDRESS_P(X) \
- (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
- || GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \
- || (GET_CODE (X) == CONST \
- && ! (flag_pic && pic_address_needs_scratch (X)) \
- && (TARGET_GAS) \
- && (mips_abi != ABI_N32 \
- && mips_abi != ABI_64)))
-
-
-/* Define this, so that when PIC, reload won't try to reload invalid
- addresses which require two reload registers. */
-
-#define LEGITIMATE_PIC_OPERAND_P(X) (! pic_address_needs_scratch (X))
+/* Check for constness inline but use mips_legitimate_address_p
+ to check whether a constant really is an address. */
+
+#define CONSTANT_ADDRESS_P(X) \
+ (CONSTANT_P (X) && mips_legitimate_address_p (SImode, X, 0))
+
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.
@@ -3055,130 +3064,13 @@ typedef struct mips_args {
gp pseudo reg (see mips16_gp_pseudo_reg) deciding it is not
a LEGITIMATE_CONSTANT. If we ever want mips16 and ABI_N32 or
ABI_64 to work together, we'll need to fix this. */
-#define LEGITIMATE_CONSTANT_P(X) \
- ((GET_CODE (X) != CONST_DOUBLE \
- || mips_const_double_ok (X, GET_MODE (X))) \
- && ! (GET_CODE (X) == CONST \
- && ! TARGET_GAS \
- && (mips_abi == ABI_N32 \
- || mips_abi == ABI_64)) \
- && (! TARGET_MIPS16 || mips16_constant (X, GET_MODE (X), 0, 0)))
-
-/* A C compound statement that attempts to replace X with a valid
- memory address for an operand of mode MODE. WIN will be a C
- statement label elsewhere in the code; the macro definition may
- use
-
- GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
-
- to avoid further processing if the address has become legitimate.
-
- X will always be the result of a call to `break_out_memory_refs',
- and OLDX will be the operand that was given to that function to
- produce X.
-
- The code generated by this macro should not alter the
- substructure of X. If it transforms X into a more legitimate
- form, it should assign X (which will always be a C variable) a
- new value.
-
- It is not necessary for this macro to come up with a legitimate
- address. The compiler has standard ways of doing so in all
- cases. In fact, it is safe for this macro to do nothing. But
- often a machine-dependent strategy can generate better code.
-
- For the MIPS, transform:
-
- memory(X + <large int>)
-
- into:
-
- Y = <large int> & ~0x7fff;
- Z = X + Y
- memory (Z + (<large int> & 0x7fff));
-
- This is for CSE to find several similar references, and only use one Z.
+#define LEGITIMATE_CONSTANT_P(X) (mips_const_insns (X) > 0)
- When PIC, convert addresses of the form memory (symbol+large int) to
- memory (reg+large int). */
-
-
-#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
-{ \
- register rtx xinsn = (X); \
- \
- if (TARGET_DEBUG_B_MODE) \
- { \
- GO_PRINTF ("\n========== LEGITIMIZE_ADDRESS\n"); \
- GO_DEBUG_RTX (xinsn); \
- } \
- \
- if (mips_split_addresses && mips_check_split (X, MODE)) \
- { \
- /* ??? Is this ever executed? */ \
- X = gen_rtx_LO_SUM (Pmode, \
- copy_to_mode_reg (Pmode, \
- gen_rtx (HIGH, Pmode, X)), \
- X); \
- goto WIN; \
- } \
- \
- if (GET_CODE (xinsn) == CONST \
- && ((flag_pic && pic_address_needs_scratch (xinsn)) \
- /* ??? SGI's Irix 6 assembler can't handle CONST. */ \
- || (!TARGET_GAS \
- && (mips_abi == ABI_N32 \
- || mips_abi == ABI_64)))) \
- { \
- rtx ptr_reg = gen_reg_rtx (Pmode); \
- rtx constant = XEXP (XEXP (xinsn, 0), 1); \
- \
- emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0)); \
- \
- X = gen_rtx_PLUS (Pmode, ptr_reg, constant); \
- if (SMALL_INT (constant)) \
- goto WIN; \
- /* Otherwise we fall through so the code below will fix the \
- constant. */ \
- xinsn = X; \
- } \
- \
- if (GET_CODE (xinsn) == PLUS) \
- { \
- register rtx xplus0 = XEXP (xinsn, 0); \
- register rtx xplus1 = XEXP (xinsn, 1); \
- register enum rtx_code code0 = GET_CODE (xplus0); \
- register enum rtx_code code1 = GET_CODE (xplus1); \
- \
- if (code0 != REG && code1 == REG) \
- { \
- xplus0 = XEXP (xinsn, 1); \
- xplus1 = XEXP (xinsn, 0); \
- code0 = GET_CODE (xplus0); \
- code1 = GET_CODE (xplus1); \
- } \
- \
- if (code0 == REG && REG_MODE_OK_FOR_BASE_P (xplus0, MODE) \
- && code1 == CONST_INT && !SMALL_INT (xplus1)) \
- { \
- rtx int_reg = gen_reg_rtx (Pmode); \
- rtx ptr_reg = gen_reg_rtx (Pmode); \
- \
- emit_move_insn (int_reg, \
- GEN_INT (INTVAL (xplus1) & ~ 0x7fff)); \
- \
- emit_insn (gen_rtx_SET (VOIDmode, \
- ptr_reg, \
- gen_rtx_PLUS (Pmode, xplus0, int_reg))); \
- \
- X = plus_constant (ptr_reg, INTVAL (xplus1) & 0x7fff); \
- goto WIN; \
- } \
- } \
- \
- if (TARGET_DEBUG_B_MODE) \
- GO_PRINTF ("LEGITIMIZE_ADDRESS could not fix.\n"); \
-}
+#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
+ do { \
+ if (mips_legitimize_address (&(X), MODE)) \
+ goto WIN; \
+ } while (0)
/* A C statement or compound statement with a conditional `goto
@@ -3213,12 +3105,6 @@ typedef struct mips_args {
#define ASM_OUTPUT_POOL_EPILOGUE(FILE, FNNAME, FNDECL, SIZE) \
mips_string_length = 0;
-
-#if 0
-/* In mips16 mode, put most string constants after the function. */
-#define CONSTANT_AFTER_FUNCTION_P(tree) \
- (TARGET_MIPS16 && mips16_constant_after_function_p (tree))
-#endif
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction.
@@ -3277,11 +3163,10 @@ typedef struct mips_args {
#define Pmode (TARGET_64BIT ? DImode : SImode)
#endif
-/* A function address in a call instruction
- is a word address (for indexing purposes)
- so give the MEM rtx a words's mode. */
+/* Give call MEMs SImode since it is the "most permissive" mode
+ for both 32-bit and 64-bit targets. */
-#define FUNCTION_MODE Pmode
+#define FUNCTION_MODE SImode
/* A part of a C `switch' statement that describes the relative
@@ -3305,22 +3190,6 @@ typedef struct mips_args {
Kenner */ \
return 0; \
} \
- if ((OUTER_CODE) == SET) \
- { \
- if (INTVAL (X) >= 0 && INTVAL (X) < 0x100) \
- return 0; \
- else if ((INTVAL (X) >= 0 && INTVAL (X) < 0x10000) \
- || (INTVAL (X) < 0 && INTVAL (X) > -0x100)) \
- return COSTS_N_INSNS (1); \
- else \
- return COSTS_N_INSNS (2); \
- } \
- /* A PLUS could be an address. We don't want to force an address \
- to use a register, so accept any signed 16 bit value without \
- complaint. */ \
- if ((OUTER_CODE) == PLUS \
- && INTVAL (X) >= -0x8000 && INTVAL (X) < 0x8000) \
- return 0; \
/* A number between 1 and 8 inclusive is efficient for a shift. \
Otherwise, we will need an extended instruction. */ \
if ((OUTER_CODE) == ASHIFT || (OUTER_CODE) == ASHIFTRT \
@@ -3348,61 +3217,26 @@ typedef struct mips_args {
&& INTVAL (X) == 0) \
return 0; \
\
- /* Otherwise, work out the cost to load the value into a \
- register. */ \
- if (INTVAL (X) >= 0 && INTVAL (X) < 0x100) \
- return COSTS_N_INSNS (1); \
- else if ((INTVAL (X) >= 0 && INTVAL (X) < 0x10000) \
- || (INTVAL (X) < 0 && INTVAL (X) > -0x100)) \
- return COSTS_N_INSNS (2); \
- else \
- return COSTS_N_INSNS (3); \
- \
- case LABEL_REF: \
- return COSTS_N_INSNS (2); \
+ /* Otherwise fall through to the handling below. */ \
\
case CONST: \
- { \
- rtx offset = const0_rtx; \
- rtx symref = eliminate_constant_term (XEXP (X, 0), &offset); \
- \
- if (TARGET_MIPS16 && mips16_gp_offset_p (X)) \
- { \
- /* Treat this like a signed 16 bit CONST_INT. */ \
- if ((OUTER_CODE) == PLUS) \
- return 0; \
- else if ((OUTER_CODE) == SET) \
- return COSTS_N_INSNS (1); \
- else \
- return COSTS_N_INSNS (2); \
- } \
- \
- if (GET_CODE (symref) == LABEL_REF) \
- return COSTS_N_INSNS (2); \
- \
- if (GET_CODE (symref) != SYMBOL_REF) \
- return COSTS_N_INSNS (4); \
- \
- /* let's be paranoid.... */ \
- if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767) \
- return COSTS_N_INSNS (2); \
- \
- return COSTS_N_INSNS (SYMBOL_REF_FLAG (symref) ? 1 : 2); \
- } \
- \
case SYMBOL_REF: \
- return COSTS_N_INSNS (SYMBOL_REF_FLAG (X) ? 1 : 2); \
- \
+ case LABEL_REF: \
case CONST_DOUBLE: \
- { \
- rtx high, low; \
- if (TARGET_MIPS16) \
- return COSTS_N_INSNS (4); \
- split_double (X, &high, &low); \
- return COSTS_N_INSNS ((high == CONST0_RTX (GET_MODE (high)) \
- || low == CONST0_RTX (GET_MODE (low))) \
- ? 2 : 4); \
- }
+ if (((OUTER_CODE) == PLUS || (OUTER_CODE) == MINUS) \
+ && const_arith_operand (X, VOIDmode)) \
+ return 0; \
+ else \
+ { \
+ int n = mips_const_insns (X); \
+ return (n == 0 ? CONSTANT_POOL_COST : COSTS_N_INSNS (n)); \
+ }
+
+/* The cost of loading values from the constant pool. It should be
+ larger than the cost of any constant we want to synthesise in-line. */
+
+#define CONSTANT_POOL_COST COSTS_N_INSNS (8)
+
/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
This can be used, for example, to indicate how costly a multiply
@@ -3421,11 +3255,12 @@ typedef struct mips_args {
#define RTX_COSTS(X,CODE,OUTER_CODE) \
case MEM: \
{ \
- int num_words = (GET_MODE_SIZE (GET_MODE (X)) > UNITS_PER_WORD) ? 2 : 1; \
- if (simple_memory_operand (X, GET_MODE (X))) \
- return COSTS_N_INSNS (num_words); \
- \
- return COSTS_N_INSNS (2*num_words); \
+ /* If the address is legitimate, return the number of \
+ instructions it needs, otherwise use the default handling. */ \
+ int n = mips_address_insns (XEXP (X, 0), GET_MODE (X)); \
+ if (n > 0) \
+ return COSTS_N_INSNS (1 + n); \
+ break; \
} \
\
case FFS: \
@@ -3459,6 +3294,9 @@ typedef struct mips_args {
return COSTS_N_INSNS (4); \
} \
\
+ case LO_SUM: \
+ return COSTS_N_INSNS (1); \
+ \
case PLUS: \
case MINUS: \
{ \
@@ -3594,50 +3432,6 @@ typedef struct mips_args {
else \
return COSTS_N_INSNS (1);
-/* An expression giving the cost of an addressing mode that
- contains ADDRESS. If not defined, the cost is computed from the
- form of the ADDRESS expression and the `CONST_COSTS' values.
-
- For most CISC machines, the default cost is a good approximation
- of the true cost of the addressing mode. However, on RISC
- machines, all instructions normally have the same length and
- execution time. Hence all addresses will have equal costs.
-
- In cases where more than one form of an address is known, the
- form with the lowest cost will be used. If multiple forms have
- the same, lowest, cost, the one that is the most complex will be
- used.
-
- For example, suppose an address that is equal to the sum of a
- register and a constant is used twice in the same basic block.
- When this macro is not defined, the address will be computed in
- a register and memory references will be indirect through that
- register. On machines where the cost of the addressing mode
- containing the sum is no higher than that of a simple indirect
- reference, this will produce an additional instruction and
- possibly require an additional register. Proper specification
- of this macro eliminates this overhead for such machines.
-
- Similar use of this macro is made in strength reduction of loops.
-
- ADDRESS need not be valid as an address. In such a case, the
- cost is not relevant and can be any value; invalid addresses
- need not be assigned a different cost.
-
- On machines where an address involving more than one register is
- as cheap as an address computation involving only one register,
- defining `ADDRESS_COST' to reflect this can cause two registers
- to be live over a region of code where only one would have been
- if `ADDRESS_COST' were not defined in that manner. This effect
- should be considered in the definition of this macro.
- Equivalent costs should probably only be given to addresses with
- different numbers of registers on machines with lots of registers.
-
- This macro will normally either not be defined or be defined as
- a constant. */
-
-#define ADDRESS_COST(ADDR) (REG_P (ADDR) ? 1 : mips_address_cost (ADDR))
-
/* A C expression for the cost of moving data from a register in
class FROM to one in class TO. The classes are expressed using
the enumeration values such as `GENERAL_REGS'. A value of 2 is
@@ -3710,7 +3504,9 @@ typedef struct mips_args {
#define PREDICATE_CODES \
{"uns_arith_operand", { REG, CONST_INT, SUBREG }}, \
- {"arith_operand", { REG, CONST_INT, SUBREG }}, \
+ {"symbolic_operand", { CONST, SYMBOL_REF, LABEL_REF }}, \
+ {"const_arith_operand", { CONST, CONST_INT }}, \
+ {"arith_operand", { REG, CONST_INT, CONST, SUBREG }}, \
{"arith32_operand", { REG, CONST_INT, SUBREG }}, \
{"reg_or_0_operand", { REG, CONST_INT, CONST_DOUBLE, SUBREG }}, \
{"true_reg_or_0_operand", { REG, CONST_INT, CONST_DOUBLE, SUBREG }}, \
@@ -3724,7 +3520,7 @@ typedef struct mips_args {
LTU, LEU }}, \
{"trap_cmp_op", { EQ, NE, GE, GEU, LT, LTU }}, \
{"pc_or_label_operand", { PC, LABEL_REF }}, \
- {"call_insn_operand", { CONST_INT, CONST, SYMBOL_REF, REG}}, \
+ {"call_insn_operand", { CONST, SYMBOL_REF, LABEL_REF, REG }}, \
{"move_operand", { CONST_INT, CONST_DOUBLE, CONST, \
SYMBOL_REF, LABEL_REF, SUBREG, \
REG, MEM}}, \
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 2edbd28d013..4175ab529b4 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -47,7 +47,9 @@
(UNSPEC_CONSTTABLE_DF 17)
(UNSPEC_ALIGN_2 18)
(UNSPEC_ALIGN_4 19)
- (UNSPEC_ALIGN_8 20)])
+ (UNSPEC_ALIGN_8 20)
+ (UNSPEC_CPADD 21)
+ (UNSPEC_RELOC_GPREL16 100)])
;; ....................
@@ -62,11 +64,13 @@
;; call unconditional call
;; load load instruction(s)
;; store store instruction(s)
+;; prefetch memory prefetch
;; move data movement within same register set
;; xfer transfer to/from coprocessor
;; hilo transfer of hi/lo registers
;; arith integer arithmetic instruction
;; darith double precision integer arithmetic instructions
+;; const load constant
;; imul integer multiply
;; imadd integer multiply-add
;; idiv integer divide
@@ -85,7 +89,7 @@
;; nop no operation
(define_attr "type"
- "unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,imadd,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,multi,nop"
+ "unknown,branch,jump,call,load,store,prefetch,move,xfer,hilo,const,arith,darith,imul,imadd,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,multi,nop"
(const_string "unknown"))
;; Main data type used by the insn
@@ -110,6 +114,12 @@
(const_int 0))
(const_int 24)
] (const_int 12))
+ (eq_attr "type" "const")
+ (symbol_ref "mips_const_insns (operands[1]) * 4")
+ (eq_attr "type" "load")
+ (symbol_ref "mips_fetch_insns (operands[1]) * 4")
+ (eq_attr "type" "store")
+ (symbol_ref "mips_fetch_insns (operands[0]) * 4")
] (const_int 4)))
;; Attribute describing the processor. This attribute must match exactly
@@ -140,15 +150,14 @@
(const_string "yes")
(const_string "no")))
+;; Is it a single instruction?
+(define_attr "single_insn" "no,yes"
+ (symbol_ref "get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)"))
+
;; Can the instruction be put into a delay slot?
(define_attr "can_delay" "no,yes"
(if_then_else (and (eq_attr "dslot" "no")
- ; ADJUST_INSN_LENGTH divides length by 2 on mips16,
- ; so cope with it here.
- (ior (and (eq (symbol_ref "mips16") (const_int 0))
- (eq_attr "length" "4"))
- (and (ne (symbol_ref "mips16") (const_int 0))
- (eq_attr "length" "2"))))
+ (eq_attr "single_insn" "yes"))
(const_string "yes")
(const_string "no")))
@@ -165,10 +174,6 @@
(define_asm_attributes
[(set_attr "type" "multi")])
-;; whether or not generating calls to position independent functions
-(define_attr "abicalls" "no,yes"
- (const (symbol_ref "mips_abicalls_attr")))
-
;; .........................
@@ -182,15 +187,14 @@
[(eq_attr "can_delay" "yes")
(nil)
(and (eq_attr "branch_likely" "yes")
- (and (eq_attr "dslot" "no")
- (eq_attr "length" "4")))])
+ (eq_attr "can_delay" "yes"))])
(define_delay (eq_attr "type" "jump")
[(eq_attr "can_delay" "yes")
(nil)
(nil)])
-(define_delay (and (eq_attr "type" "call") (eq_attr "abicalls" "no"))
+(define_delay (eq_attr "type" "call")
[(eq_attr "can_delay" "yes")
(nil)
(nil)])
@@ -1157,7 +1161,7 @@
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
(sign_extend:DI (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
- (match_operand:SI 2 "arith_operand" "I,O,d"))))]
+ (match_operand:SI 2 "arith_operand" "IQ,O,d"))))]
"TARGET_MIPS16 && TARGET_64BIT"
"*
{
@@ -4101,13 +4105,12 @@ move\\t%0,%z4\\n\\
}")
(define_insn "zero_extendsidi2_internal"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (zero_extend:DI (match_operand:SI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (zero_extend:DI (match_operand:SI 1 "memory_operand" "m")))]
"TARGET_64BIT && !TARGET_MIPS16"
"* return mips_move_1word (operands, insn, TRUE);"
[(set_attr "type" "load")
- (set_attr "mode" "DI")
- (set_attr "length" "4,8")])
+ (set_attr "mode" "DI")])
(define_expand "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
@@ -4126,8 +4129,8 @@ move\\t%0,%z4\\n\\
}")
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))]
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
"!TARGET_MIPS16"
"*
{
@@ -4136,18 +4139,17 @@ move\\t%0,%z4\\n\\
else
return mips_move_1word (operands, insn, TRUE);
}"
- [(set_attr "type" "arith,load,load")
+ [(set_attr "type" "arith,load")
(set_attr "mode" "SI")
- (set_attr "length" "4,4,8")])
+ (set_attr "length" "4,*")])
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (zero_extend:SI (match_operand:HI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
"TARGET_MIPS16"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "load,load")
- (set_attr "mode" "SI")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "load")
+ (set_attr "mode" "SI")])
(define_expand "zero_extendhidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4166,8 +4168,8 @@ move\\t%0,%z4\\n\\
}")
(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=d,d,d")
- (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))]
+ [(set (match_operand:DI 0 "register_operand" "=d,d")
+ (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
"TARGET_64BIT && !TARGET_MIPS16"
"*
{
@@ -4176,18 +4178,17 @@ move\\t%0,%z4\\n\\
else
return mips_move_1word (operands, insn, TRUE);
}"
- [(set_attr "type" "arith,load,load")
+ [(set_attr "type" "arith,load")
(set_attr "mode" "DI")
- (set_attr "length" "4,4,8")])
+ (set_attr "length" "4,*")])
(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (zero_extend:DI (match_operand:HI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (zero_extend:DI (match_operand:HI 1 "memory_operand" "m")))]
"TARGET_64BIT && TARGET_MIPS16"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "load,load")
- (set_attr "mode" "DI")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "load")
+ (set_attr "mode" "DI")])
(define_expand "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
@@ -4207,8 +4208,8 @@ move\\t%0,%z4\\n\\
}")
(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=d,d,d")
- (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
+ [(set (match_operand:HI 0 "register_operand" "=d,d")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
"!TARGET_MIPS16"
"*
{
@@ -4217,18 +4218,17 @@ move\\t%0,%z4\\n\\
else
return mips_move_1word (operands, insn, TRUE);
}"
- [(set_attr "type" "arith,load,load")
+ [(set_attr "type" "arith,load")
(set_attr "mode" "HI")
- (set_attr "length" "4,4,8")])
+ (set_attr "length" "4,*")])
(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=d,d")
- (zero_extend:HI (match_operand:QI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:HI 0 "register_operand" "=d")
+ (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
"TARGET_MIPS16"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "load,load")
- (set_attr "mode" "HI")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "load")
+ (set_attr "mode" "HI")])
(define_expand "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
@@ -4247,8 +4247,8 @@ move\\t%0,%z4\\n\\
}")
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
"!TARGET_MIPS16"
"*
{
@@ -4257,18 +4257,17 @@ move\\t%0,%z4\\n\\
else
return mips_move_1word (operands, insn, TRUE);
}"
- [(set_attr "type" "arith,load,load")
+ [(set_attr "type" "arith,load")
(set_attr "mode" "SI")
- (set_attr "length" "4,4,8")])
+ (set_attr "length" "4,*")])
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (zero_extend:SI (match_operand:QI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
"TARGET_MIPS16"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "load,load")
- (set_attr "mode" "SI")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "load")
+ (set_attr "mode" "SI")])
(define_expand "zero_extendqidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4287,8 +4286,8 @@ move\\t%0,%z4\\n\\
}")
(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=d,d,d")
- (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
+ [(set (match_operand:DI 0 "register_operand" "=d,d")
+ (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
"TARGET_64BIT && !TARGET_MIPS16"
"*
{
@@ -4297,9 +4296,9 @@ move\\t%0,%z4\\n\\
else
return mips_move_1word (operands, insn, TRUE);
}"
- [(set_attr "type" "arith,load,load")
+ [(set_attr "type" "arith,load")
(set_attr "mode" "DI")
- (set_attr "length" "4,4,8")])
+ (set_attr "length" "4,*")])
;; These can be created when a paradoxical subreg operand with an implicit
;; sign_extend operator is reloaded. Because of the subreg, this is really
@@ -4307,26 +4306,24 @@ move\\t%0,%z4\\n\\
;; ??? It might be possible to eliminate the need for these patterns by adding
;; more support to reload for implicit sign_extend operators.
(define_insn "*paradoxical_extendhidi2"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
+ [(set (match_operand:DI 0 "register_operand" "=d")
(sign_extend:DI
- (subreg:SI (match_operand:HI 1 "memory_operand" "R,m") 0)))]
+ (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)))]
"TARGET_64BIT"
"*
{
return mips_move_1word (operands, insn, TRUE);
}"
- [(set_attr "type" "load,load")
- (set_attr "mode" "DI")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "load")
+ (set_attr "mode" "DI")])
(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (zero_extend:DI (match_operand:QI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (zero_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
"TARGET_64BIT && TARGET_MIPS16"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "load,load")
- (set_attr "mode" "DI")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "load")
+ (set_attr "mode" "DI")])
;;
;; ....................
@@ -4376,13 +4373,12 @@ move\\t%0,%z4\\n\\
}")
(define_insn "extendhidi2_internal"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (sign_extend:DI (match_operand:HI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (sign_extend:DI (match_operand:HI 1 "memory_operand" "m")))]
"TARGET_64BIT"
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
- (set_attr "mode" "DI")
- (set_attr "length" "4,8")])
+ (set_attr "mode" "DI")])
(define_expand "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
@@ -4406,13 +4402,12 @@ move\\t%0,%z4\\n\\
}")
(define_insn "extendhisi2_internal"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
""
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
- (set_attr "mode" "SI")
- (set_attr "length" "4,8")])
+ (set_attr "mode" "SI")])
(define_expand "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
@@ -4437,13 +4432,12 @@ move\\t%0,%z4\\n\\
}")
(define_insn "extendqihi2_internal"
- [(set (match_operand:HI 0 "register_operand" "=d,d")
- (sign_extend:HI (match_operand:QI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:HI 0 "register_operand" "=d")
+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
""
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
- (set_attr "mode" "SI")
- (set_attr "length" "4,8")])
+ (set_attr "mode" "SI")])
(define_expand "extendqisi2"
@@ -4468,13 +4462,12 @@ move\\t%0,%z4\\n\\
}")
(define_insn "extendqisi2_insn"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (sign_extend:SI (match_operand:QI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
""
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
- (set_attr "mode" "SI")
- (set_attr "length" "4,8")])
+ (set_attr "mode" "SI")])
(define_expand "extendqidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4498,13 +4491,12 @@ move\\t%0,%z4\\n\\
}")
(define_insn "extendqidi2_insn"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (sign_extend:DI (match_operand:QI 1 "memory_operand" "R,m")))]
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (sign_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
"TARGET_64BIT"
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
- (set_attr "mode" "DI")
- (set_attr "length" "4,8")])
+ (set_attr "mode" "DI")])
(define_insn "extendsfdf2"
@@ -5004,8 +4996,8 @@ move\\t%0,%z4\\n\\
;; unaligned word moves generated by the bit field patterns
(define_insn "movsi_ulw"
- [(set (match_operand:SI 0 "register_operand" "=&d,&d")
- (unspec:SI [(match_operand:BLK 1 "general_operand" "R,o")]
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (unspec:SI [(match_operand:BLK 1 "general_operand" "m")]
UNSPEC_ULW))]
"!TARGET_MIPS16"
"*
@@ -5029,13 +5021,13 @@ move\\t%0,%z4\\n\\
return mips_fill_delay_slot (ret, DELAY_LOAD, operands, insn);
}"
- [(set_attr "type" "load,load")
+ [(set_attr "type" "load")
(set_attr "mode" "SI")
- (set_attr "length" "8,16")])
+ (set_attr "length" "8")])
(define_insn "movsi_usw"
- [(set (match_operand:BLK 0 "memory_operand" "=R,o")
- (unspec:BLK [(match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")]
+ [(set (match_operand:BLK 0 "memory_operand" "=m")
+ (unspec:BLK [(match_operand:SI 1 "reg_or_0_operand" "dJ")]
UNSPEC_USW))]
"!TARGET_MIPS16"
"*
@@ -5058,15 +5050,15 @@ move\\t%0,%z4\\n\\
}"
[(set_attr "type" "store")
(set_attr "mode" "SI")
- (set_attr "length" "8,16")])
+ (set_attr "length" "8")])
;; Bit field extract patterns which use ldl/ldr.
;; unaligned double word moves generated by the bit field patterns
(define_insn "movdi_uld"
- [(set (match_operand:DI 0 "register_operand" "=&d,&d")
- (unspec:DI [(match_operand:BLK 1 "general_operand" "R,o")]
+ [(set (match_operand:DI 0 "register_operand" "=&d")
+ (unspec:DI [(match_operand:BLK 1 "general_operand" "m")]
UNSPEC_ULD))]
""
"*
@@ -5090,13 +5082,13 @@ move\\t%0,%z4\\n\\
return mips_fill_delay_slot (ret, DELAY_LOAD, operands, insn);
}"
- [(set_attr "type" "load,load")
+ [(set_attr "type" "load")
(set_attr "mode" "SI")
- (set_attr "length" "8,16")])
+ (set_attr "length" "8")])
(define_insn "movdi_usd"
- [(set (match_operand:BLK 0 "memory_operand" "=R,o")
- (unspec:BLK [(match_operand:DI 1 "reg_or_0_operand" "dJ,dJ")]
+ [(set (match_operand:BLK 0 "memory_operand" "=m")
+ (unspec:BLK [(match_operand:DI 1 "reg_or_0_operand" "dJ")]
UNSPEC_USD))]
""
"*
@@ -5119,30 +5111,36 @@ move\\t%0,%z4\\n\\
}"
[(set_attr "type" "store")
(set_attr "mode" "SI")
- (set_attr "length" "8,16")])
-
-;; These two patterns support loading addresses with two instructions instead
-;; of using the macro instruction la.
-
-;; ??? mips_move_1word has support for HIGH, so this pattern may be
-;; unnecessary.
-
-(define_insn "high"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (high:SI (match_operand:SI 1 "immediate_operand" "")))]
- "mips_split_addresses && !TARGET_MIPS16"
- "lui\\t%0,%%hi(%1) # high"
- [(set_attr "type" "move")])
+ (set_attr "length" "8")])
-(define_insn "low"
+(define_insn "lowsi"
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "")))]
"mips_split_addresses && !TARGET_MIPS16"
- "addiu\\t%0,%1,%%lo(%2) # low"
+ "addiu\\t%0,%1,%%lo(%2)"
[(set_attr "type" "arith")
(set_attr "mode" "SI")])
+(define_insn "lowdi"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "immediate_operand" "")))]
+ "mips_split_addresses && !TARGET_MIPS16 && TARGET_64BIT"
+ "daddiu\\t%0,%1,%%lo(%2)"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")])
+
+(define_insn "lowdi_extend"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "immediate_operand" ""))))]
+ "mips_split_addresses && !TARGET_MIPS16 && TARGET_64BIT"
+ "daddiu\\t%0,%1,%%lo(%2)"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")])
+
;; 64-bit integer moves
;; Unlike most other insns, the move insns can't be split with
@@ -5151,21 +5149,12 @@ move\\t%0,%z4\\n\\
(define_expand "movdi"
[(set (match_operand:DI 0 "nonimmediate_operand" "")
- (match_operand:DI 1 "general_operand" ""))]
+ (match_operand:DI 1 "" ""))]
""
"
{
- if (mips_split_addresses && mips_check_split (operands[1], DImode))
- {
- enum machine_mode mode = GET_MODE (operands[0]);
- rtx tem = ((reload_in_progress | reload_completed)
- ? operands[0] : gen_reg_rtx (mode));
-
- emit_insn (gen_rtx_SET (VOIDmode, tem,
- gen_rtx_HIGH (mode, operands[1])));
-
- operands[1] = gen_rtx_LO_SUM (mode, tem, operands[1]);
- }
+ if (mips_legitimize_move (DImode, operands[0], operands[1]))
+ DONE;
/* If we are generating embedded PIC code, and we are referring to a
symbol in the .text section, we must use an offset from the start
@@ -5183,73 +5172,6 @@ move\\t%0,%z4\\n\\
emit_move_insn (operands[0], force_reg (DImode, temp));
DONE;
}
-
- /* If operands[1] is a constant address illegal for pic, then we need to
- handle it just like LEGITIMIZE_ADDRESS does. */
- if (flag_pic && pic_address_needs_scratch (operands[1]))
- {
- rtx temp = force_reg (DImode, XEXP (XEXP (operands[1], 0), 0));
- rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
-
- if (! SMALL_INT (temp2))
- temp2 = force_reg (DImode, temp2);
-
- emit_move_insn (operands[0], gen_rtx_PLUS (DImode, temp, temp2));
- DONE;
- }
-
- /* On the mips16, we can handle a GP relative reference by adding in
- $gp. We need to check the name to see whether this is a string
- constant. */
- if (TARGET_MIPS16
- && register_operand (operands[0], DImode)
- && GET_CODE (operands[1]) == SYMBOL_REF
- && SYMBOL_REF_FLAG (operands[1]))
- {
- const char *name = XSTR (operands[1], 0);
-
- if (name[0] != '*'
- || strncmp (name + 1, LOCAL_LABEL_PREFIX,
- sizeof LOCAL_LABEL_PREFIX - 1) != 0)
- {
- rtx base_reg;
-
- if (reload_in_progress || reload_completed)
- {
- /* In movsi we use the constant table here. However, in
- this case, we're better off copying $28 into a
- register and adding, because the constant table entry
- would be 8 bytes. */
- base_reg = operands[0];
- emit_move_insn (base_reg,
- gen_rtx (CONST, DImode,
- gen_rtx (REG, DImode,
- GP_REG_FIRST + 28)));
- }
- else
- {
- base_reg = gen_reg_rtx (Pmode);
- emit_move_insn (base_reg, mips16_gp_pseudo_reg ());
- }
-
- emit_move_insn (operands[0],
- gen_rtx (PLUS, Pmode, base_reg,
- mips16_gp_offset (operands[1])));
- DONE;
- }
- }
-
- if ((reload_in_progress | reload_completed) == 0
- && !register_operand (operands[0], DImode)
- && !register_operand (operands[1], DImode)
- && (TARGET_MIPS16
- || ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
- && operands[1] != CONST0_RTX (DImode))))
- {
- rtx temp = force_reg (DImode, operands[1]);
- emit_move_insn (operands[0], temp);
- DONE;
- }
}")
;; For mips16, we need a special case to handle storing $31 into
@@ -5257,7 +5179,7 @@ move\\t%0,%z4\\n\\
;; instruction can be generated by save_restore_insns.
(define_insn ""
- [(set (match_operand:DI 0 "memory_operand" "=R,m")
+ [(set (match_operand:DI 0 "memory_operand" "=m")
(reg:DI 31))]
"TARGET_MIPS16 && TARGET_64BIT"
"*
@@ -5266,32 +5188,31 @@ move\\t%0,%z4\\n\\
return mips_move_2words (operands, insn);
}"
[(set_attr "type" "store")
- (set_attr "mode" "DI")
- (set_attr "length" "4,8")])
+ (set_attr "mode" "DI")])
(define_insn "movdi_internal"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x,*d,*x,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
- (match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*x,*d,*x,*B*C*D,*B*C*D,*d,*m")
+ (match_operand:DI 1 "general_operand" "d,iF,m,d,J,*x,*d,*d,*m,*B*C*D,*B*C*D"))]
"!TARGET_64BIT && !TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|| operands[1] == CONST0_RTX (DImode))"
"* return mips_move_2words (operands, insn); "
- [(set_attr "type" "move,arith,load,load,store,store,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
+ [(set_attr "type" "move,arith,load,store,hilo,hilo,hilo,xfer,load,xfer,store")
(set_attr "mode" "DI")
- (set_attr "length" "8,16,8,16,8,16,8,8,8,8,8,8,8,8,8")])
+ (set_attr "length" "8,16,*,*,8,8,8,8,*,8,*")])
(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,To,*d")
- (match_operand:DI 1 "general_operand" "d,d,y,K,N,R,To,d,d,*x"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
+ (match_operand:DI 1 "general_operand" "d,d,y,K,N,m,d,*x"))]
"!TARGET_64BIT && TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
"* return mips_move_2words (operands, insn);"
- [(set_attr "type" "move,move,move,arith,arith,load,load,store,store,hilo")
+ [(set_attr "type" "move,move,move,arith,arith,load,store,hilo")
(set_attr "mode" "DI")
- (set_attr "length" "8,8,8,8,12,8,16,8,16,8")])
+ (set_attr "length" "8,8,8,8,12,*,*,8")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -5306,17 +5227,17 @@ move\\t%0,%z4\\n\\
"")
(define_insn "movdi_internal2"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,*f,*d,*R,*m,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
- (match_operand:DI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*R,*m,*f,*f,*f,*J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*f,*f,*f,*d,*m,*x,*d,*x,*a,*B*C*D,*B*C*D,*d,*m")
+ (match_operand:DI 1 "move_operand" "d,R,m,dJ,*f,*d*J,*m,*f,*f,*J,*x,*d,*J,*d,*m,*B*C*D,*B*C*D"))]
"TARGET_64BIT && !TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|| operands[1] == CONST0_RTX (DImode))"
"* return mips_move_2words (operands, insn); "
- [(set_attr "type" "move,arith,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
+ [(set_attr "type" "move,const,load,store,move,xfer,load,xfer,store,hilo,hilo,hilo,hilo,xfer,load,xfer,store")
(set_attr "mode" "DI")
- (set_attr "length" "4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,8,8,8,8,8,8,8")])
+ (set_attr "length" "4,*,*,*,4,4,*,4,*,4,4,4,8,8,*,8,*")])
;; Sign-extended operands are reloaded using this instruction, so the
;; constraints must handle every SImode source operand X and destination
@@ -5331,26 +5252,26 @@ move\\t%0,%z4\\n\\
;; The main difference is that dJ -> f and f -> d are the only constraints
;; involving float registers. See mips_secondary_reload_class for details.
(define_insn "*movdi_internal2_extend"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*f,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
- (sign_extend:DI (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D")))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*x,*d,*x,*a,*B*C*D,*B*C*D,*d,*m")
+ (sign_extend:DI (match_operand:SI 1 "move_operand" "d,R,m,dJ,*f,*d*J,*J,*x,*d,*J,*d,*m,*B*C*D,*B*C*D")))]
"TARGET_64BIT
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|| operands[1] == CONST0_RTX (DImode))"
"* return mips_sign_extend (insn, operands[0], operands[1]);"
- [(set_attr "type" "move,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
+ [(set_attr "type" "move,const,load,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,xfer,store")
(set_attr "mode" "DI")
- (set_attr "length" "4,4,8,4,8,4,8,4,4,4,4,4,8,8,8,8,8,8,8")])
+ (set_attr "length" "4,*,*,*,4,4,4,4,4,8,8,*,8,*")])
(define_insn "*movdi_internal2_mips16"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d")
- (match_operand:DI 1 "move_operand" "d,d,y,K,N,s,R,m,d,d,*x"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,m,*d")
+ (match_operand:DI 1 "move_operand" "d,d,y,K,N,R,m,d,*x"))]
"TARGET_64BIT && TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
"* return mips_move_2words (operands, insn);"
- [(set_attr "type" "move,move,move,arith,arith,arith,load,load,store,store,hilo")
+ [(set_attr "type" "move,move,move,arith,arith,const,load,store,hilo")
(set_attr "mode" "DI")
(set_attr_alternative "length"
[(const_int 4)
@@ -5362,13 +5283,9 @@ move\\t%0,%z4\\n\\
(if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "")
(const_int 8)
(const_int 12))
- (if_then_else (match_operand:VOID 1 "m16_usym5_4" "")
- (const_int 4)
- (const_int 8))
- (const_int 4)
- (const_int 8)
- (const_int 4)
- (const_int 8)
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
(const_int 4)])])
@@ -5580,44 +5497,18 @@ move\\t%0,%z4\\n\\
;; 32-bit Integer moves
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "large_int" ""))]
- "!TARGET_DEBUG_D_MODE && !TARGET_MIPS16"
- [(set (match_dup 0)
- (match_dup 2))
- (set (match_dup 0)
- (ior:SI (match_dup 0)
- (match_dup 3)))]
- "
-{
- operands[2] = GEN_INT (trunc_int_for_mode (INTVAL (operands[1])
- & BITMASK_UPPER16,
- SImode));
- operands[3] = GEN_INT (INTVAL (operands[1]) & BITMASK_LOWER16);
-}")
-
;; Unlike most other insns, the move insns can't be split with
;; different predicates, because register spilling and other parts of
;; the compiler, have memoized the insn number already.
(define_expand "movsi"
[(set (match_operand:SI 0 "nonimmediate_operand" "")
- (match_operand:SI 1 "general_operand" ""))]
+ (match_operand:SI 1 "" ""))]
""
"
{
- if (mips_split_addresses && mips_check_split (operands[1], SImode))
- {
- enum machine_mode mode = GET_MODE (operands[0]);
- rtx tem = ((reload_in_progress | reload_completed)
- ? operands[0] : gen_reg_rtx (mode));
-
- emit_insn (gen_rtx_SET (VOIDmode, tem,
- gen_rtx_HIGH (mode, operands[1])));
-
- operands[1] = gen_rtx_LO_SUM (mode, tem, operands[1]);
- }
+ if (mips_legitimize_move (SImode, operands[0], operands[1]))
+ DONE;
/* If we are generating embedded PIC code, and we are referring to a
symbol in the .text section, we must use an offset from the start
@@ -5635,73 +5526,6 @@ move\\t%0,%z4\\n\\
emit_move_insn (operands[0], force_reg (SImode, temp));
DONE;
}
-
- /* If operands[1] is a constant address invalid for pic, then we need to
- handle it just like LEGITIMIZE_ADDRESS does. */
- if (flag_pic && pic_address_needs_scratch (operands[1]))
- {
- rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
- rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
-
- if (! SMALL_INT (temp2))
- temp2 = force_reg (SImode, temp2);
-
- emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
- DONE;
- }
-
- /* On the mips16, we can handle a GP relative reference by adding in
- $gp. We need to check the name to see whether this is a string
- constant. */
- if (TARGET_MIPS16
- && register_operand (operands[0], SImode)
- && GET_CODE (operands[1]) == SYMBOL_REF
- && SYMBOL_REF_FLAG (operands[1]))
- {
- const char *name = XSTR (operands[1], 0);
-
- if (name[0] != '*'
- || strncmp (name + 1, LOCAL_LABEL_PREFIX,
- sizeof LOCAL_LABEL_PREFIX - 1) != 0)
- {
- rtx base_reg;
-
- if (reload_in_progress || reload_completed)
- {
- /* We need to reload this address. In this case we
- aren't going to have a chance to combine loading the
- address with the load or store. That means that we
- can either generate a 2 byte move followed by a 4
- byte addition, or a 2 byte load with a 4 byte entry
- in the constant table. Since the entry in the
- constant table might be shared, we're better off, on
- average, loading the address from the constant table. */
- emit_move_insn (operands[0],
- force_const_mem (SImode, operands[1]));
- DONE;
- }
-
- base_reg = gen_reg_rtx (Pmode);
- emit_move_insn (base_reg, mips16_gp_pseudo_reg ());
-
- emit_move_insn (operands[0],
- gen_rtx (PLUS, Pmode, base_reg,
- mips16_gp_offset (operands[1])));
- DONE;
- }
- }
-
- if ((reload_in_progress | reload_completed) == 0
- && !register_operand (operands[0], SImode)
- && !register_operand (operands[1], SImode)
- && (TARGET_MIPS16
- || GET_CODE (operands[1]) != CONST_INT
- || INTVAL (operands[1]) != 0))
- {
- rtx temp = force_reg (SImode, operands[1]);
- emit_move_insn (operands[0], temp);
- DONE;
- }
}")
;; We can only store $ra directly into a small sp offset. Should the
@@ -5728,40 +5552,25 @@ move\\t%0,%z4\\n\\
;; in FP registers (off by default, use -mdebugh to enable).
(define_insn "movsi_internal"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,?*f,*d,*R,*m,*d,*z,*x,*d,*x,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
- (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*R,*m,*f,*f,*f,*z,*d,J,*x,*d,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,m,*f,*f,*f,*d,*m,*d,*z,*x,*d,*x,*d,*B*C*D,*B*C*D,*d,*m")
+ (match_operand:SI 1 "move_operand" "d,R,m,dJ,*f,*d*J,*m,*f,*f,*z,*d,J,*x,*d,*a,*d,*m,*B*C*D,*B*C*D"))]
"!TARGET_MIPS16
&& (register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
"* return mips_move_1word (operands, insn, FALSE);"
- [(set_attr "type" "move,arith,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
+ [(set_attr "type" "move,const,load,store,move,xfer,load,xfer,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,xfer,store")
(set_attr "mode" "SI")
- (set_attr "length" "4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,4,4,4,4,4,8,4,4,8")])
-
-;; This is the mips16 movsi instruction. We accept a small integer as
-;; the source if the destination is a GP memory reference. This is
-;; because we want the combine pass to turn adding a GP reference to a
-;; register into a direct GP reference, but the combine pass will pass
-;; in the source as a constant if it finds an equivalent one. If the
-;; instruction is recognized, reload will force the constant back out
-;; into a register.
+ (set_attr "length" "4,*,*,*,4,4,*,4,*,4,4,4,4,4,4,4,*,4,*")])
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d,*d")
- (match_operand:SI 1 "move_operand" "d,d,y,K,N,s,R,m,d,d,*x,*a"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,m,*d,*d")
+ (match_operand:SI 1 "move_operand" "d,d,y,K,N,R,m,d,*x,*a"))]
"TARGET_MIPS16
&& (register_operand (operands[0], SImode)
- || register_operand (operands[1], SImode)
- || (GET_CODE (operands[0]) == MEM
- && GET_CODE (XEXP (operands[0], 0)) == PLUS
- && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST
- && mips16_gp_offset_p (XEXP (XEXP (operands[0], 0), 1))
- && GET_CODE (operands[1]) == CONST_INT
- && (SMALL_INT (operands[1])
- || SMALL_INT_UNSIGNED (operands[1]))))"
+ || register_operand (operands[1], SImode))"
"* return mips_move_1word (operands, insn, FALSE);"
- [(set_attr "type" "move,move,move,arith,arith,arith,load,load,store,store,hilo,hilo")
+ [(set_attr "type" "move,move,move,arith,arith,const,load,store,hilo,hilo")
(set_attr "mode" "SI")
(set_attr_alternative "length"
[(const_int 4)
@@ -5773,13 +5582,9 @@ move\\t%0,%z4\\n\\
(if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "")
(const_int 8)
(const_int 12))
- (if_then_else (match_operand:VOID 1 "m16_usym8_4" "")
- (const_int 4)
- (const_int 8))
- (const_int 4)
- (const_int 8)
- (const_int 4)
- (const_int 8)
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
(const_int 4)
(const_int 4)])])
@@ -6025,13 +5830,13 @@ move\\t%0,%z4\\n\\
;; between the general registers and the floating point registers.
(define_insn "movcc"
- [(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*d,*R,*m,*d,*f,*f,*f,*f,*R,*m")
- (match_operand:CC 1 "general_operand" "z,*d,*R,*m,*d,*d,*f,*d,*f,*R,*m,*f,*f"))]
+ [(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*m,*d,*f,*f,*f,*m")
+ (match_operand:CC 1 "general_operand" "z,*d,*m,*d,*f,*d,*f,*m,*f"))]
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
"* return mips_move_1word (operands, insn, FALSE);"
- [(set_attr "type" "move,move,load,load,store,store,xfer,xfer,move,load,load,store,store")
+ [(set_attr "type" "move,move,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "SI")
- (set_attr "length" "8,4,4,8,4,8,4,4,4,4,8,4,8")])
+ (set_attr "length" "8,4,*,*,4,4,4,*,*")])
;; Reload condition code registers. reload_incc and reload_outcc
;; both handle moves from arbitrary operands into condition code
@@ -6089,7 +5894,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT"
"lwxc1\\t%0,%1(%2)"
[(set_attr "type" "load")
- (set_attr "mode" "SF")])
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f")
@@ -6098,7 +5904,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT"
"lwxc1\\t%0,%1(%2)"
[(set_attr "type" "load")
- (set_attr "mode" "SF")])
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -6107,7 +5914,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
"ldxc1\\t%0,%1(%2)"
[(set_attr "type" "load")
- (set_attr "mode" "DF")])
+ (set_attr "mode" "DF")
+ (set_attr "length" "4")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -6116,7 +5924,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
"ldxc1\\t%0,%1(%2)"
[(set_attr "type" "load")
- (set_attr "mode" "DF")])
+ (set_attr "mode" "DF")
+ (set_attr "length" "4")])
(define_insn ""
[(set (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "d")
@@ -6125,7 +5934,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT"
"swxc1\\t%0,%1(%2)"
[(set_attr "type" "store")
- (set_attr "mode" "SF")])
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
(define_insn ""
[(set (mem:SF (plus:DI (match_operand:DI 1 "register_operand" "d")
@@ -6134,7 +5944,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT"
"swxc1\\t%0,%1(%2)"
[(set_attr "type" "store")
- (set_attr "mode" "SF")])
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
(define_insn ""
[(set (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d")
@@ -6143,7 +5954,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
"sdxc1\\t%0,%1(%2)"
[(set_attr "type" "store")
- (set_attr "mode" "DF")])
+ (set_attr "mode" "DF")
+ (set_attr "length" "4")])
(define_insn ""
[(set (mem:DF (plus:DI (match_operand:DI 1 "register_operand" "d")
@@ -6152,7 +5964,8 @@ move\\t%0,%z4\\n\\
"ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
"sdxc1\\t%0,%1(%2)"
[(set_attr "type" "store")
- (set_attr "mode" "DF")])
+ (set_attr "mode" "DF")
+ (set_attr "length" "4")])
;; 16-bit Integer moves
@@ -6184,25 +5997,25 @@ move\\t%0,%z4\\n\\
;; in FP registers (off by default, use -mdebugh to enable).
(define_insn "movhi_internal"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
- (match_operand:HI 1 "general_operand" "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f*z,*f,*x,*d")
+ (match_operand:HI 1 "general_operand" "d,IK,m,dJ,*f*z,*d,*f,*d,*x"))]
"!TARGET_MIPS16
&& (register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,hilo,hilo")
+ [(set_attr "type" "move,arith,load,store,xfer,xfer,move,hilo,hilo")
(set_attr "mode" "HI")
- (set_attr "length" "4,4,4,8,4,8,4,4,4,4,4")])
+ (set_attr "length" "4,4,*,*,4,4,4,4,4")])
(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d")
- (match_operand:HI 1 "general_operand" "d,d,y,K,N,R,m,d,d,*x"))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
+ (match_operand:HI 1 "general_operand" "d,d,y,K,N,m,d,*x"))]
"TARGET_MIPS16
&& (register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode))"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "move,move,move,arith,arith,load,load,store,store,hilo")
+ [(set_attr "type" "move,move,move,arith,arith,load,store,hilo")
(set_attr "mode" "HI")
(set_attr_alternative "length"
[(const_int 4)
@@ -6214,10 +6027,8 @@ move\\t%0,%z4\\n\\
(if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "")
(const_int 8)
(const_int 12))
- (const_int 4)
- (const_int 8)
- (const_int 4)
- (const_int 8)
+ (const_string "*")
+ (const_string "*")
(const_int 4)])])
@@ -6294,25 +6105,25 @@ move\\t%0,%z4\\n\\
;; in FP registers (off by default, use -mdebugh to enable).
(define_insn "movqi_internal"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
- (match_operand:QI 1 "general_operand" "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f*z,*f,*x,*d")
+ (match_operand:QI 1 "general_operand" "d,IK,m,dJ,*f*z,*d,*f,*d,*x"))]
"!TARGET_MIPS16
&& (register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,hilo,hilo")
+ [(set_attr "type" "move,arith,load,store,xfer,xfer,move,hilo,hilo")
(set_attr "mode" "QI")
- (set_attr "length" "4,4,4,8,4,8,4,4,4,4,4")])
+ (set_attr "length" "4,4,*,*,4,4,4,4,4")])
(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d")
- (match_operand:QI 1 "general_operand" "d,d,y,K,N,R,m,d,d,*x"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
+ (match_operand:QI 1 "general_operand" "d,d,y,K,N,m,d,*x"))]
"TARGET_MIPS16
&& (register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode))"
"* return mips_move_1word (operands, insn, TRUE);"
- [(set_attr "type" "move,move,move,arith,arith,load,load,store,store,hilo")
+ [(set_attr "type" "move,move,move,arith,arith,load,store,hilo")
(set_attr "mode" "QI")
(set_attr_alternative "length"
[(const_int 4)
@@ -6324,10 +6135,8 @@ move\\t%0,%z4\\n\\
(if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "")
(const_int 8)
(const_int 12))
- (const_int 4)
- (const_int 8)
- (const_int 4)
- (const_int 8)
+ (const_string "*")
+ (const_string "*")
(const_int 4)])])
@@ -6377,37 +6186,37 @@ move\\t%0,%z4\\n\\
}")
(define_insn "movsf_internal1"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,f,R,m,*f,*d,*d,*d,*d,*R,*m")
- (match_operand:SF 1 "general_operand" "f,G,R,m,fG,fG,*d,*f,*G*d,*R,*m,*d,*d"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,*f,*d,*d,*d,*m")
+ (match_operand:SF 1 "general_operand" "f,G,m,fG,*d,*f,*G*d,*m,*d"))]
"TARGET_HARD_FLOAT
&& (register_operand (operands[0], SFmode)
|| nonmemory_operand (operands[1], SFmode))"
"* return mips_move_1word (operands, insn, FALSE);"
- [(set_attr "type" "move,xfer,load,load,store,store,xfer,xfer,move,load,load,store,store")
+ [(set_attr "type" "move,xfer,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "SF")
- (set_attr "length" "4,4,4,8,4,8,4,4,4,4,8,4,8")])
+ (set_attr "length" "4,4,*,*,4,4,4,*,*")])
(define_insn "movsf_internal2"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,R,m")
- (match_operand:SF 1 "general_operand" " Gd,R,m,d,d"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,m")
+ (match_operand:SF 1 "general_operand" " Gd,m,d"))]
"TARGET_SOFT_FLOAT && !TARGET_MIPS16
&& (register_operand (operands[0], SFmode)
|| nonmemory_operand (operands[1], SFmode))"
"* return mips_move_1word (operands, insn, FALSE);"
- [(set_attr "type" "move,load,load,store,store")
+ [(set_attr "type" "move,load,store")
(set_attr "mode" "SF")
- (set_attr "length" "4,4,8,4,8")])
+ (set_attr "length" "4,*,*")])
(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=d,y,d,d,d,R,m")
- (match_operand:SF 1 "nonimmediate_operand" "d,d,y,R,m,d,d"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=d,y,d,d,m")
+ (match_operand:SF 1 "nonimmediate_operand" "d,d,y,m,d"))]
"TARGET_MIPS16
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
"* return mips_move_1word (operands, insn, FALSE);"
- [(set_attr "type" "move,move,move,load,load,store,store")
+ [(set_attr "type" "move,move,move,load,store")
(set_attr "mode" "SF")
- (set_attr "length" "4,4,4,4,8,4,8")])
+ (set_attr "length" "4,4,4,*,*")])
;; 64-bit floating point moves
@@ -6424,51 +6233,49 @@ move\\t%0,%z4\\n\\
operands[1] = force_reg (DFmode, operands[1]);
}")
-(define_insn "movdf_internal1"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,f,R,To,*f,*d,*d,*d,*d,*R,*T")
- (match_operand:DF 1 "general_operand" "f,G,R,To,fG,fG,*d,*f,*d*G,*R,*T,*d,*d"))]
- "TARGET_HARD_FLOAT && !(TARGET_FLOAT64 && !TARGET_64BIT)
- && TARGET_DOUBLE_FLOAT
+(define_insn "movdf_internal1a"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,*f,*d,*d,*d,*m")
+ (match_operand:DF 1 "general_operand" "f,G,m,fG,*d,*f,*d*G,*m,*d"))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_64BIT
&& (register_operand (operands[0], DFmode)
|| nonmemory_operand (operands[1], DFmode))"
"* return mips_move_2words (operands, insn); "
- [(set_attr "type" "move,move,load,load,store,store,xfer,xfer,move,load,load,store,store")
+ [(set_attr "type" "move,move,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "DF")
- (set_attr "length" "4,8,8,16,8,16,8,8,8,8,16,8,16")])
+ (set_attr "length" "4,8,*,*,4,4,4,*,*")])
-(define_insn "movdf_internal1a"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,R,R,To,To,*d,*d,*To,*R,*d")
- (match_operand:DF 1 "general_operand" " f,To,f,G,f,G,*To,*R,*d,*d,*d"))]
- "TARGET_HARD_FLOAT && (TARGET_FLOAT64 && !TARGET_64BIT)
- && TARGET_DOUBLE_FLOAT
+(define_insn "movdf_internal1b"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,*f,*d,*d,*d,*m")
+ (match_operand:DF 1 "general_operand" "f,G,m,fG,*d,*f,*d*G,*m,*d"))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT
&& (register_operand (operands[0], DFmode)
|| nonmemory_operand (operands[1], DFmode))"
"* return mips_move_2words (operands, insn); "
- [(set_attr "type" "move,load,store,store,store,store,load,load,store,store,move")
+ [(set_attr "type" "move,move,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "DF")
- (set_attr "length" "4,8,4,4,8,8,8,4,8,4,4")])
+ (set_attr "length" "4,8,*,*,8,8,8,*,*")])
(define_insn "movdf_internal2"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,R,To,d,f,f")
- (match_operand:DF 1 "general_operand" "dG,R,To,d,d,f,d,f"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m,d,f,f")
+ (match_operand:DF 1 "general_operand" "dG,m,d,f,d,f"))]
"(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16
&& (register_operand (operands[0], DFmode)
|| nonmemory_operand (operands[1], DFmode))"
"* return mips_move_2words (operands, insn); "
- [(set_attr "type" "move,load,load,store,store,xfer,load,move")
+ [(set_attr "type" "move,load,store,xfer,xfer,move")
(set_attr "mode" "DF")
- (set_attr "length" "8,8,16,8,16,8,8,4")])
+ (set_attr "length" "8,*,*,8,8,4")])
(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,d,R,To")
- (match_operand:DF 1 "nonimmediate_operand" "d,d,y,R,To,d,d"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,m")
+ (match_operand:DF 1 "nonimmediate_operand" "d,d,y,m,d"))]
"TARGET_MIPS16
&& (register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode))"
"* return mips_move_2words (operands, insn);"
- [(set_attr "type" "move,move,move,load,load,store,store")
+ [(set_attr "type" "move,move,move,load,store")
(set_attr "mode" "DF")
- (set_attr "length" "8,8,8,8,16,8,16")])
+ (set_attr "length" "8,8,8,*,*")])
(define_split
[(set (match_operand:DF 0 "register_operand" "")
@@ -6487,7 +6294,7 @@ move\\t%0,%z4\\n\\
(define_insn "loadgp"
[(set (reg:DI 28)
- (unspec_volatile:DI [(match_operand:DI 0 "address_operand" "")
+ (unspec_volatile:DI [(match_operand:DI 0 "immediate_operand" "")
(match_operand:DI 1 "register_operand" "")]
UNSPEC_LOADGP))
(clobber (reg:DI 1))]
@@ -6632,8 +6439,8 @@ move\\t%0,%z4\\n\\
(set_attr "length" "80")])
(define_insn "movstrsi_internal3"
- [(set (match_operand:BLK 0 "memory_operand" "=Ro") ;; destination
- (match_operand:BLK 1 "memory_operand" "Ro")) ;; source
+ [(set (match_operand:BLK 0 "memory_operand" "=m") ;; destination
+ (match_operand:BLK 1 "memory_operand" "m")) ;; source
(clobber (match_scratch:SI 4 "=&d")) ;; temp 1
(clobber (match_scratch:SI 5 "=&d")) ;; temp 2
(clobber (match_scratch:SI 6 "=&d")) ;; temp 3
@@ -7460,19 +7267,17 @@ move\\t%0,%z4\\n\\
;; not have and immediate). We recognize a shift of a load in order
;; to make it simple enough for combine to understand.
+;; ??? FIXME: turn into a define_insn_and_split
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (lshiftrt:SI (match_operand:SI 1 "memory_operand" "R,m")
- (match_operand:SI 2 "immediate_operand" "I,I")))]
- "TARGET_MIPS16"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ "0 && TARGET_MIPS16"
"lw\\t%0,%1\;srl\\t%0,%2"
[(set_attr "type" "load")
(set_attr "mode" "SI")
(set_attr_alternative "length"
[(if_then_else (match_operand:VOID 2 "m16_uimm3_b" "")
- (const_int 8)
- (const_int 12))
- (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "")
(const_int 12)
(const_int 16))])])
@@ -9704,21 +9509,22 @@ move\\t%0,%z4\\n\\
if (GET_MODE (operands[0]) != Pmode)
abort ();
- if (! flag_pic)
+ if (TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64))
{
- if (!(Pmode == DImode))
- emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
- else
- emit_jump_insn (gen_tablejump_internal2 (operands[0], operands[1]));
- }
- else
- {
- if (!(Pmode == DImode))
- emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
+ rtx temp;
+
+ temp = gen_reg_rtx (Pmode);
+ if (Pmode == SImode)
+ emit_insn (gen_cpaddsi (temp, operands[0]));
else
- emit_jump_insn (gen_tablejump_internal4 (operands[0], operands[1]));
+ emit_insn (gen_cpadddi (temp, operands[0]));
+ operands[0] = temp;
}
+ if (Pmode == SImode)
+ emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
+ else
+ emit_jump_insn (gen_tablejump_internal2 (operands[0], operands[1]));
DONE;
}
}")
@@ -9727,7 +9533,7 @@ move\\t%0,%z4\\n\\
[(set (pc)
(match_operand:SI 0 "register_operand" "d"))
(use (label_ref (match_operand 1 "" "")))]
- "!(Pmode == DImode)"
+ "Pmode == SImode"
"%*j\\t%0"
[(set_attr "type" "jump")
(set_attr "mode" "none")])
@@ -9741,13 +9547,23 @@ move\\t%0,%z4\\n\\
[(set_attr "type" "jump")
(set_attr "mode" "none")])
-(define_expand "tablejump_internal3"
- [(parallel [(set (pc)
- (plus:SI (match_operand:SI 0 "register_operand" "d")
- (label_ref:SI (match_operand 1 "" ""))))
- (use (label_ref:SI (match_dup 1)))])]
- ""
- "")
+(define_insn "cpaddsi"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (plus:SI (match_operand:SI 1 "register_operand" "d")
+ (unspec [(const_int 0)] UNSPEC_CPADD)))]
+ "TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)"
+ "addu\t%0,%1,%+"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "cpadddi"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (plus:DI (match_operand:DI 1 "register_operand" "d")
+ (unspec [(const_int 0)] UNSPEC_CPADD)))]
+ "TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)"
+ "daddu\t%0,%1,%+"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")])
(define_expand "tablejump_mips161"
[(set (pc) (plus:SI (sign_extend:SI
@@ -9793,64 +9609,6 @@ move\\t%0,%z4\\n\\
}
}")
-;;; Make sure that this only matches the insn before ADDR_DIFF_VEC. Otherwise
-;;; it is not valid. ??? With the USE, the condition tests may not be required
-;;; any longer.
-
-;;; ??? The length depends on the ABI. It is two for o32, and one for n32.
-;;; We just use the conservative number here.
-
-(define_insn ""
- [(set (pc)
- (plus:SI (match_operand:SI 0 "register_operand" "d")
- (label_ref:SI (match_operand 1 "" ""))))
- (use (label_ref:SI (match_dup 1)))]
- "!(Pmode == DImode) && next_active_insn (insn) != 0
- && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
- && PREV_INSN (next_active_insn (insn)) == operands[1]"
- "*
-{
- /* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */
- if (mips_abi == ABI_32 || mips_abi == ABI_O64
- || (mips_abi == ABI_N32 && TARGET_GAS))
- output_asm_insn (\".cpadd\\t%0\", operands);
- return \"%*j\\t%0\";
-}"
- [(set_attr "type" "jump")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_expand "tablejump_internal4"
- [(parallel [(set (pc)
- (plus:DI (match_operand:DI 0 "register_operand" "d")
- (label_ref:DI (match_operand 1 "" ""))))
- (use (label_ref:DI (match_dup 1)))])]
- ""
- "")
-
-;;; Make sure that this only matches the insn before ADDR_DIFF_VEC. Otherwise
-;;; it is not valid. ??? With the USE, the condition tests may not be required
-;;; any longer.
-
-(define_insn ""
- [(set (pc)
- (plus:DI (match_operand:DI 0 "register_operand" "d")
- (label_ref:DI (match_operand 1 "" ""))))
- (use (label_ref:DI (match_dup 1)))]
- "Pmode == DImode && next_active_insn (insn) != 0
- && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
- && PREV_INSN (next_active_insn (insn)) == operands[1]"
- "*
-{
- /* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */
- if (TARGET_GAS && mips_abi == ABI_64)
- output_asm_insn (\".cpadd\\t%0\", operands);
- return \"%*j\\t%0\";
-}"
- [(set_attr "type" "jump")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
;; Implement a switch statement when generating embedded PIC code.
;; Switches are implemented by `tablejump' when not using -membedded-pic.
@@ -10141,471 +9899,67 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
;;
;; ....................
-;; calls.c now passes a third argument, make saber happy
-
(define_expand "call"
- [(parallel [(call (match_operand 0 "memory_operand" "m")
- (match_operand 1 "" "i"))
- (clobber (reg:SI 31))
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
(use (match_operand 2 "" "")) ;; next_arg_reg
(use (match_operand 3 "" ""))])] ;; struct_value_size_rtx
""
- "
{
- rtx addr;
-
- if (operands[0]) /* eliminate unused code warnings */
- {
- addr = XEXP (operands[0], 0);
- if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
- || ! call_insn_operand (addr, VOIDmode))
- XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
-
- /* In order to pass small structures by value in registers
- compatibly with the MIPS compiler, we need to shift the value
- into the high part of the register. Function_arg has encoded
- a PARALLEL rtx, holding a vector of adjustments to be made
- as the next_arg_reg variable, so we split up the insns,
- and emit them separately. */
-
- if (operands[2] != (rtx)0 && GET_CODE (operands[2]) == PARALLEL)
- {
- rtvec adjust = XVEC (operands[2], 0);
- int num = GET_NUM_ELEM (adjust);
- int i;
-
- for (i = 0; i < num; i++)
- emit_insn (RTVEC_ELT (adjust, i));
- }
-
- if (TARGET_MIPS16
- && mips16_hard_float
- && operands[2] != 0
- && (int) GET_MODE (operands[2]) != 0)
- {
- if (build_mips16_call_stub (NULL_RTX, operands[0], operands[1],
- (int) GET_MODE (operands[2])))
- DONE;
- }
-
- emit_call_insn (gen_call_internal0 (operands[0], operands[1],
- gen_rtx_REG (SImode,
- GP_REG_FIRST + 31)));
- DONE;
- }
-}")
+ mips_expand_call (0, XEXP (operands[0], 0), operands[1], operands[2]);
+ DONE;
+})
-(define_expand "call_internal0"
- [(parallel [(call (match_operand 0 "" "")
- (match_operand 1 "" ""))
- (clobber (match_operand:SI 2 "" ""))])]
+(define_insn "call_internal"
+ [(call (mem:SI (match_operand 0 "call_insn_operand" "c,S"))
+ (match_operand 1 "" "i,i"))
+ (clobber (reg:SI 31))]
""
- "")
-
-;; We need to recognize reg:SI 31 specially for the mips16, because we
-;; don't have a constraint letter for it.
-
-(define_insn ""
- [(call (mem (match_operand 0 "call_insn_operand" "ei"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=y"))]
- "TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS
- && GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 31"
- "%*jal\\t%0"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_insn "call_internal1"
- [(call (mem (match_operand 0 "call_insn_operand" "ri"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=d"))]
- "!TARGET_ABICALLS && !TARGET_LONG_CALLS"
- "*
-{
- register rtx target = operands[0];
-
- if (GET_CODE (target) == CONST_INT)
- return \"%[li\\t%@,%0\\n\\t%*jal\\t%2,%@%]\";
- else if (CONSTANT_ADDRESS_P (target))
- return \"%*jal\\t%0\";
- else
- return \"%*jal\\t%2,%0\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")])
-
-(define_insn "call_internal2"
- [(call (mem (match_operand 0 "call_insn_operand" "ri"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=d"))]
- "TARGET_ABICALLS && !TARGET_LONG_CALLS"
- "*
-{
- register rtx target = operands[0];
-
- if (GET_CODE (target) == CONST_INT)
- return \"li\\t%^,%0\\n\\tjal\\t%2,%^\";
- else if (CONSTANT_ADDRESS_P (target))
- {
- if (GET_MODE (target) == SImode)
- return \"la\\t%^,%0\\n\\tjal\\t%2,%^\";
- else
- return \"dla\\t%^,%0\\n\\tjal\\t%2,%^\";
- }
- else if (REGNO (target) != PIC_FUNCTION_ADDR_REGNUM)
- return \"move\\t%^,%0\\n\\tjal\\t%2,%^\";
- else
- return \"jal\\t%2,%0\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_insn "call_internal3a"
- [(call (mem:SI (match_operand:SI 0 "register_operand" "r"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=d"))]
- "!TARGET_MIPS16
- && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS"
- "%*jal\\t%2,%0"
- [(set_attr "type" "call")
- (set_attr "mode" "none")])
-
-(define_insn "call_internal3b"
- [(call (mem:DI (match_operand:DI 0 "register_operand" "r"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=d"))]
- "!TARGET_MIPS16
- && Pmode == DImode && !TARGET_ABICALLS && TARGET_LONG_CALLS"
- "%*jal\\t%2,%0"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "1")])
-
-(define_insn "call_internal3c"
- [(call (mem:SI (match_operand:SI 0 "register_operand" "e"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=y"))]
- "TARGET_MIPS16 && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS
- && GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 31"
- "%*jal\\t%2,%0"
+ "@
+ %*jalr\\t%0
+ %*jal\\t%0"
[(set_attr "type" "call")
(set_attr "mode" "none")])
-(define_insn "call_internal4a"
- [(call (mem:SI (match_operand:SI 0 "register_operand" "r"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=d"))]
- "!(Pmode == DImode) && TARGET_ABICALLS && TARGET_LONG_CALLS"
- "*
-{
- if (REGNO (operands[0]) != PIC_FUNCTION_ADDR_REGNUM)
- return \"move\\t%^,%0\\n\\tjal\\t%2,%^\";
- else
- return \"jal\\t%2,%0\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_insn "call_internal4b"
- [(call (mem:DI (match_operand:DI 0 "register_operand" "r"))
- (match_operand 1 "" "i"))
- (clobber (match_operand:SI 2 "register_operand" "=d"))]
- "Pmode == DImode && TARGET_ABICALLS && TARGET_LONG_CALLS"
- "*
-{
- if (REGNO (operands[0]) != PIC_FUNCTION_ADDR_REGNUM)
- return \"move\\t%^,%0\\n\\tjal\\t%2,%^\";
- else
- return \"jal\\t%2,%0\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-;; calls.c now passes a fourth argument, make saber happy
-
(define_expand "call_value"
- [(parallel [(set (match_operand 0 "register_operand" "=df")
- (call (match_operand 1 "memory_operand" "m")
- (match_operand 2 "" "i")))
- (clobber (reg:SI 31))
- (use (match_operand 3 "" ""))])] ;; next_arg_reg
- ""
- "
-{
- rtx addr;
-
- if (operands[0]) /* eliminate unused code warning */
- {
- addr = XEXP (operands[1], 0);
- if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
- || ! call_insn_operand (addr, VOIDmode))
- XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
-
- /* In order to pass small structures by value in registers
- compatibly with the MIPS compiler, we need to shift the value
- into the high part of the register. Function_arg has encoded
- a PARALLEL rtx, holding a vector of adjustments to be made
- as the next_arg_reg variable, so we split up the insns,
- and emit them separately. */
-
- if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL)
- {
- rtvec adjust = XVEC (operands[3], 0);
- int num = GET_NUM_ELEM (adjust);
- int i;
-
- for (i = 0; i < num; i++)
- emit_insn (RTVEC_ELT (adjust, i));
- }
-
- if (TARGET_MIPS16
- && mips16_hard_float
- && ((operands[3] != 0
- && (int) GET_MODE (operands[3]) != 0)
- || GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT))
- {
- if (build_mips16_call_stub (operands[0], operands[1], operands[2],
- (operands[3] == 0 ? 0
- : (int) GET_MODE (operands[3]))))
- DONE;
- }
-
- /* Handle Irix6 function calls that have multiple non-contiguous
- results. */
- if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1)
- {
- emit_call_insn (gen_call_value_multiple_internal0
- (XEXP (XVECEXP (operands[0], 0, 0), 0),
- operands[1], operands[2],
- XEXP (XVECEXP (operands[0], 0, 1), 0),
- gen_rtx_REG (SImode, GP_REG_FIRST + 31)));
- DONE;
- }
-
- /* We have a call returning a DImode structure in an FP reg.
- Strip off the now unnecessary PARALLEL. */
- if (GET_CODE (operands[0]) == PARALLEL)
- operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
-
- emit_call_insn (gen_call_value_internal0 (operands[0], operands[1], operands[2],
- gen_rtx_REG (SImode,
- GP_REG_FIRST + 31)));
-
- DONE;
- }
-}")
-
-(define_expand "call_value_internal0"
[(parallel [(set (match_operand 0 "" "")
(call (match_operand 1 "" "")
(match_operand 2 "" "")))
- (clobber (match_operand:SI 3 "" ""))])]
+ (use (match_operand 3 "" ""))])] ;; next_arg_reg
""
- "")
-
-;; Recognize $31 specially on the mips16, because we don't have a
-;; constraint letter for it.
-
-(define_insn ""
- [(set (match_operand 0 "register_operand" "=d")
- (call (mem (match_operand 1 "call_insn_operand" "ei"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=y"))]
- "TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS
- && GET_CODE (operands[3]) == REG && REGNO (operands[3]) == 31"
- "%*jal\\t%1"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_insn "call_value_internal1"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem (match_operand 1 "call_insn_operand" "ri"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=d"))]
- "!TARGET_ABICALLS && !TARGET_LONG_CALLS"
- "*
-{
- register rtx target = operands[1];
-
- if (GET_CODE (target) == CONST_INT)
- return \"%[li\\t%@,%1\\n\\t%*jal\\t%3,%@%]\";
- else if (CONSTANT_ADDRESS_P (target))
- return \"%*jal\\t%1\";
- else
- return \"%*jal\\t%3,%1\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")])
-
-(define_insn "call_value_internal2"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem (match_operand 1 "call_insn_operand" "ri"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=d"))]
- "TARGET_ABICALLS && !TARGET_LONG_CALLS"
- "*
{
- register rtx target = operands[1];
-
- if (GET_CODE (target) == CONST_INT)
- return \"li\\t%^,%1\\n\\tjal\\t%3,%^\";
- else if (CONSTANT_ADDRESS_P (target))
- {
- if (GET_MODE (target) == SImode)
- return \"la\\t%^,%1\\n\\tjal\\t%3,%^\";
- else
- return \"dla\\t%^,%1\\n\\tjal\\t%3,%^\";
- }
- else if (REGNO (target) != PIC_FUNCTION_ADDR_REGNUM)
- return \"move\\t%^,%1\\n\\tjal\\t%3,%^\";
- else
- return \"jal\\t%3,%1\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_insn "call_value_internal3a"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem:SI (match_operand:SI 1 "register_operand" "r"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=d"))]
- "!TARGET_MIPS16
- && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS"
- "%*jal\\t%3,%1"
- [(set_attr "type" "call")
- (set_attr "mode" "none")])
-
-(define_insn "call_value_internal3b"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem:DI (match_operand:DI 1 "register_operand" "r"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=d"))]
- "!TARGET_MIPS16
- && Pmode == DImode && !TARGET_ABICALLS && TARGET_LONG_CALLS"
- "%*jal\\t%3,%1"
- [(set_attr "type" "call")
- (set_attr "mode" "none")])
+ mips_expand_call (operands[0], XEXP (operands[1], 0),
+ operands[2], operands[3]);
+ DONE;
+})
-(define_insn "call_value_internal3c"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem:SI (match_operand:SI 1 "register_operand" "e"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=y"))]
- "TARGET_MIPS16 && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS
- && GET_CODE (operands[3]) == REG && REGNO (operands[3]) == 31"
- "%*jal\\t%3,%1"
+(define_insn "call_value_internal"
+ [(set (match_operand 0 "register_operand" "=df,df")
+ (call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
+ (match_operand 2 "" "i,i")))
+ (clobber (reg:SI 31))]
+ ""
+ "@
+ %*jalr\\t%1
+ %*jal\\t%1"
[(set_attr "type" "call")
(set_attr "mode" "none")])
-(define_insn "call_value_internal4a"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem:SI (match_operand:SI 1 "register_operand" "r"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=d"))]
- "!(Pmode == DImode) && TARGET_ABICALLS && TARGET_LONG_CALLS"
- "*
-{
- if (REGNO (operands[1]) != PIC_FUNCTION_ADDR_REGNUM)
- return \"move\\t%^,%1\\n\\tjal\\t%3,%^\";
- else
- return \"jal\\t%3,%1\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_insn "call_value_internal4b"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem:DI (match_operand:DI 1 "register_operand" "r"))
- (match_operand 2 "" "i")))
- (clobber (match_operand:SI 3 "register_operand" "=d"))]
- "Pmode == DImode && TARGET_ABICALLS && TARGET_LONG_CALLS"
- "*
-{
- if (REGNO (operands[1]) != PIC_FUNCTION_ADDR_REGNUM)
- return \"move\\t%^,%1\\n\\tjal\\t%3,%^\";
- else
- return \"jal\\t%3,%1\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-(define_expand "call_value_multiple_internal0"
- [(parallel [(set (match_operand 0 "" "")
- (call (match_operand 1 "" "")
- (match_operand 2 "" "")))
- (set (match_operand 3 "" "")
- (call (match_dup 1)
- (match_dup 2)))
- (clobber (match_operand:SI 4 "" ""))])]
+(define_insn "call_value_multiple_internal"
+ [(set (match_operand 0 "register_operand" "=df,df")
+ (call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
+ (match_operand 2 "" "i,i")))
+ (set (match_operand 3 "register_operand" "=df,df")
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:SI 31))]
""
- "")
-
-;; ??? May eventually need all 6 versions of the call patterns with multiple
-;; return values.
-
-(define_insn "call_value_multiple_internal1"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem (match_operand 1 "call_insn_operand" "ri"))
- (match_operand 2 "" "i")))
- (set (match_operand 3 "register_operand" "=df")
- (call (mem (match_dup 1))
- (match_dup 2)))
- (clobber (match_operand:SI 4 "register_operand" "=d"))]
- "!TARGET_ABICALLS && !TARGET_LONG_CALLS"
- "*
-{
- register rtx target = operands[1];
-
- if (GET_CODE (target) == CONST_INT)
- return \"%[li\\t%@,%1\\n\\t%*jal\\t%4,%@%]\";
- else if (CONSTANT_ADDRESS_P (target))
- return \"%*jal\\t%1\";
- else
- return \"%*jal\\t%4,%1\";
-}"
+ "@
+ %*jalr\\t%1
+ %*jal\\t%1"
[(set_attr "type" "call")
(set_attr "mode" "none")])
-(define_insn "call_value_multiple_internal2"
- [(set (match_operand 0 "register_operand" "=df")
- (call (mem (match_operand 1 "call_insn_operand" "ri"))
- (match_operand 2 "" "i")))
- (set (match_operand 3 "register_operand" "=df")
- (call (mem (match_dup 1))
- (match_dup 2)))
- (clobber (match_operand:SI 4 "register_operand" "=d"))]
- "TARGET_ABICALLS && !TARGET_LONG_CALLS"
- "*
-{
- register rtx target = operands[1];
-
- if (GET_CODE (target) == CONST_INT)
- return \"li\\t%^,%1\\n\\tjal\\t%4,%^\";
- else if (CONSTANT_ADDRESS_P (target))
- {
- if (GET_MODE (target) == SImode)
- return \"la\\t%^,%1\\n\\tjal\\t%4,%^\";
- else
- return \"dla\\t%^,%1\\n\\tjal\\t%4,%^\";
- }
- else if (REGNO (target) != PIC_FUNCTION_ADDR_REGNUM)
- return \"move\\t%^,%1\\n\\tjal\\t%4,%^\";
- else
- return \"jal\\t%4,%1\";
-}"
- [(set_attr "type" "call")
- (set_attr "mode" "none")
- (set_attr "length" "8")])
-
-
;; Call subroutine returning any type.
(define_expand "untyped_call"
@@ -10616,21 +9970,18 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
""
"
{
- if (operands[0]) /* silence statement not reached warnings */
- {
- int i;
+ int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
- for (i = 0; i < XVECLEN (operands[2], 0); i++)
- {
- rtx set = XVECEXP (operands[2], 0, i);
- emit_move_insn (SET_DEST (set), SET_SRC (set));
- }
-
- emit_insn (gen_blockage ());
- DONE;
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
}
+
+ emit_insn (gen_blockage ());
+ DONE;
}")
;;
@@ -10647,10 +9998,10 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
(match_operand 1 "const_int_operand" "")
(match_operand 2 "const_int_operand" ""))]
"ISA_HAS_PREFETCH"
-"{
- if (symbolic_operand (operands[0], GET_MODE (operands[0])))
- operands[0] = force_reg (GET_MODE (operands[0]), operands[0]);
-}")
+{
+ if (symbolic_operand (operands[0], GET_MODE (operands[0])))
+ operands[0] = force_reg (GET_MODE (operands[0]), operands[0]);
+})
(define_insn "prefetch_si_address"
[(prefetch (plus:SI (match_operand:SI 0 "register_operand" "r")
@@ -10659,7 +10010,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
(match_operand:SI 2 "const_int_operand" "n"))]
"ISA_HAS_PREFETCH && Pmode == SImode"
"* return mips_emit_prefetch (operands);"
- [(set_attr "type" "load")])
+ [(set_attr "type" "prefetch")])
(define_insn "prefetch_si"
[(prefetch (match_operand:SI 0 "register_operand" "r")
@@ -10667,7 +10018,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
(match_operand:SI 2 "const_int_operand" "n"))]
"ISA_HAS_PREFETCH && Pmode == SImode"
"* return mips_emit_prefetch (operands);"
- [(set_attr "type" "load")])
+ [(set_attr "type" "prefetch")])
(define_insn "prefetch_di_address"
[(prefetch (plus:DI (match_operand:DI 0 "register_operand" "r")
@@ -10676,7 +10027,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
(match_operand:DI 2 "const_int_operand" "n"))]
"ISA_HAS_PREFETCH && Pmode == DImode"
"* return mips_emit_prefetch (operands);"
- [(set_attr "type" "load")])
+ [(set_attr "type" "prefetch")])
(define_insn "prefetch_di"
[(prefetch (match_operand:DI 0 "register_operand" "r")
@@ -10684,7 +10035,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
(match_operand:DI 2 "const_int_operand" "n"))]
"ISA_HAS_PREFETCH && Pmode == DImode"
"* return mips_emit_prefetch (operands);"
- [(set_attr "type" "load")])
+ [(set_attr "type" "prefetch")])
(define_insn "nop"
[(const_int 0)]
@@ -11189,26 +10540,6 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
(set_attr "mode" "none")
(set_attr "length" "8")])
-;; For the rare case where we need to load an address into a register
-;; that can not be recognized by the normal movsi/addsi instructions.
-;; I have no idea how many insns this can actually generate. It should
-;; be rare, so over-estimating as 10 instructions should not have any
-;; real performance impact.
-(define_insn "leasi"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (match_operand:SI 1 "address_operand" "p"))]
- "Pmode == SImode"
- "la %0,%a1"
- [(set_attr "type" "arith")
- (set_attr "mode" "SI")
- (set_attr "length" "40")])
-
-;; Similarly for targets where we have 64bit pointers.
-(define_insn "leadi"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (match_operand:DI 1 "address_operand" "p"))]
- "Pmode == DImode"
- "la %0,%a1"
- [(set_attr "type" "arith")
- (set_attr "mode" "DI")
- (set_attr "length" "40")])
+(define_expand "reloc_gprel16"
+ [(const (unspec [(match_operand:SI 0 "" "")] UNSPEC_RELOC_GPREL16))]
+ "" "")
diff --git a/gcc/config/mips/sr71k.md b/gcc/config/mips/sr71k.md
index 82162e3ca39..76417b620f8 100644
--- a/gcc/config/mips/sr71k.md
+++ b/gcc/config/mips/sr71k.md
@@ -206,7 +206,7 @@
(define_insn_reservation "ir_sr70_arith"
1
(and (eq_attr "cpu" "sr71000")
- (eq_attr "type" "arith,darith"))
+ (eq_attr "type" "arith,darith,const"))
"ri_insns")
;; emulate repeat (dispatch stall) by spending extra cycle(s) in