diff options
author | Richard Sandiford <rsandifo@redhat.com> | 2003-01-09 17:45:55 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@redhat.com> | 2003-01-09 17:45:55 +0000 |
commit | 26f7aa5bc1e2d1f18cf4e60a66a94ee82c4c3e45 (patch) | |
tree | c95f9e21012fc06a3fc1524d82ac04f02982eb0f | |
parent | aa97f4c1014244e5a5bbbd3c08ce67537a286e02 (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.rewrite | 124 | ||||
-rw-r--r-- | gcc/config/mips/5400.md | 2 | ||||
-rw-r--r-- | gcc/config/mips/5500.md | 2 | ||||
-rw-r--r-- | gcc/config/mips/mips-protos.h | 22 | ||||
-rw-r--r-- | gcc/config/mips/mips.c | 2027 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 394 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 1315 | ||||
-rw-r--r-- | gcc/config/mips/sr71k.md | 2 |
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 |